You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Used in TWO contexts: (1) users.role for system-level admin access (OWNER only), (2) project_users.role for project-level access control (READER/TESTER only). Project ownership is tracked by projects.user_id, not by project_users.role = OWNER. The getProjectRole() function returns "OWNER" as a computed value when user matches projects.user_id.
project_visibility
PUBLIC, PRIVATE, TEAM
Project visibility (not to be confused with roles)
Where to look for {pattern}.png or serve generated placeholders
created_at
timestamp
updated_at
timestamp
9. Route Configurations
User-defined routes per project. Replaces hardcoded route enums.
Column
Type
Notes
id
uuid PK
project_id
uuid FK → projects
route_key
text, not null
"hero", "villain" - unique per project
route_name
text, not null
"Hero's Route" - display name
jump_prefix
text, not null
"hero_" - for Ren'Py labels
sort_order
integer, default 0
Display order
is_shared
boolean, default false
Whether this is a shared route
created_at
timestamp
updated_at
timestamp
Unique constraint: (project_id, route_key)
10. Ren'Py Definitions
Character tags, colors, transforms.
Column
Type
Notes
id
uuid PK
project_id
uuid FK → projects
category
enum
CHARACTER, TRANSFORM, IMAGE, INIT
sort_order
integer
Export sequence
tag
text
"eileen", e
display_name
text
"Eileen"
definition_code
text
Full line: define eileen = Character(...)
reference_tag
text, nullable
For transform/image target
created_at
timestamp
updated_at
timestamp
Unique constraint: (project_id, tag)
11. Variables
Boolean story state tracking (simpler alternative to flags).
Column
Type
Notes
id
uuid PK
project_id
uuid FK → projects
key
text, not null
"met_lucas"
description
text
Variable description
category
text
For grouping
created_at
timestamp
Unique constraint: (project_id, key)
12. Characters
Column
Type
Notes
id
uuid PK
project_id
uuid FK → projects
name
text, not null
Database key
display_name
text, not null
UI display
renpy_tag
text, not null
Export: "eileen"
route_affiliation
text
Legacy; prefer label.route
is_love_interest
boolean, default false
pair_group_id
uuid FK → pair_groups, nullable
Sequel duos
dialogue_style
text
Personality for AI dialogue
conditional_prefix
text, nullable
Sprite variants: "eileen_happy"
color
text, not null
Hex for UI
avatar_url
text, nullable
Path to avatar image file
created_at
timestamp
updated_at
timestamp
13. Pair Groups
Sequel duo tracking.
Column
Type
Notes
id
uuid PK
project_id
uuid FK → projects
character_a_id
uuid FK → characters
character_b_id
uuid FK → characters
duo_ending_label
text
Jump target if both >threshold
threshold
integer, default 70
Stat value for duo ending
created_at
timestamp
updated_at
timestamp
14. Stats
Column
Type
Notes
id
uuid PK
project_id
uuid FK → projects
character_id
uuid FK → characters, nullable
Null for global
key
text, not null
"eileen_affection"
name
text, not null
"Eileen's Affection"
min_value
integer, default 0
max_value
integer, default 100
description
text
created_at
timestamp
updated_at
timestamp
15. Labels
Container for logical labels; content in label_lines. Represents Ren'Py label statements (not to be confused with Ren'Py 'scene' commands).
Column
Type
Notes
id
uuid PK
project_id
uuid FK → projects
title
text, not null
group_type
text, nullable
"act", "chapter", "episode", etc. or null
group_value
text, nullable
"I", "1", "1a", etc. or null
label_number
integer, not null
sequence_order
integer, default 0
Sorting
route
text, nullable
Soft reference to route_configs.route_key within same project. Null = shared/common. Application-layer validation ensures the route exists for the project; no database FK constraint due to composite key requirement (project_id, route) → route_configs(project_id, route_key).
Design Note - Soft Route Reference: The route column uses a soft reference (text field without FK constraint) instead of a hard foreign key. This design choice was made because:
Composite Key Requirement: A proper FK would require (project_id, route) → route_configs(project_id, route_key), which Drizzle ORM doesn't natively support
Current Implementation: Labels are created via GitLab sync with route = null (shared/common), and there is no current API to modify the route field
Future Safeguards: When adding route assignment functionality, application-layer validation must ensure the route exists for the project by querying route_configs before allowing a non-null value
16. Label Lines
Atomic lines with images.
Column
Type
Notes
id
uuid PK
label_id
uuid FK → labels
sequence
integer, not null
Line order within label
content
text, not null
The text
content_type
content_type, not null
speaker_id
uuid FK → characters, nullable
Null = narration
visual_type
visual_type, default GENERATED
visual_slug_override
text, nullable
Manual slug instead of auto
custom_visual_name
text, nullable
For CUSTOM type
menu_options
jsonb, nullable
[{label, targetLabelId, conditionFlags?}]
word_count
integer, nullable
Computed on insert/update via trigger
demo_placeholder_color
text, nullable
Black screen fallback hex
demo_notes
text, nullable
"Character enters from left" for placeholder rendering
project_file_id
uuid FK → project_files, nullable
Project file reference
line_position
integer, nullable
Position within the RPY file
content_hash
text, nullable
SHA-256 of content field
last_synced_hash
text, nullable
Hash at last sync
is_dirty
boolean, default false
Modified since last sync
last_synced_at
timestamp, nullable
rpy_line_number
integer, nullable
Actual line number in source
rpy_indent_level
integer, nullable
Indent for proper formatting
deleted_at
timestamp, nullable
Soft delete
created_at
timestamp
updated_at
timestamp
17. Label Characters (Junction)
Column
Type
Notes
label_id
uuid FK → labels
character_id
uuid FK → characters
role
character_role, default PRIMARY
emotion
text
For sprite tracking
notes
text
"Wearing red dress"
PK: (label_id, character_id)
18. World Elements
Column
Type
Notes
id
uuid PK
project_id
uuid FK → projects
name
text, not null
type
element_type, not null
description
text
tags
jsonb, default []
created_at
timestamp
19. AI Suggestions
Column
Type
Notes
id
uuid PK
project_id
uuid FK → projects
label_id
uuid FK → labels, nullable
character_id
uuid FK → characters, nullable
For voice checks
suggestion_type
suggestion_type, not null
prompt_context
jsonb
Anonymized context
project_name_anonymized
text
Audit trail
raw_response
text
parsed_suggestions
jsonb
Array of suggestions
status
suggestion_status, default PENDING
applied_at
timestamp, nullable
When accepted
created_at
timestamp
20. Exports
Column
Type
Notes
id
uuid PK
project_id
uuid FK → projects
format
text
RENPY, MARKDOWN, JSON
file_name
text, not null
content
text
Generated .rpy content
file_size
integer
visual_system_snapshot
jsonb
Version of pattern used
created_at
timestamp
21. Import Logs
One-time migration tracking (e.g., from Google Docs).