16 KiB
Database Schema
This app creates and maintains its schema at startup through src/db/index.js.
The sections below summarize the current tables and their purpose.
Tables generally use a numeric auto-increment id primary key. The relationship table d_announcement_screens intentionally uses the composite (announcement_id, screen_id) primary key instead. Natural and relationship keys remain as unique constraints where needed. Timestamps are stored as created_at and modified_at when a table supports auditing.
Admin
a_users- admin user accounts and password hashes.a_roles- named role definitions.a_permissions- permission catalog seeded from the application constants.a_role_permissions- many-to-many mapping between roles and permissions.a_user_roles- many-to-many mapping between users and roles.a_sessions- persisted admin session tokens.a_account_tokens- short-lived account verification and password-reset tokens.a_user_invitations- pending user invitations and assigned role ids.a_login_attempts- login rate-limit and lockout state.
a_users
id,name,username,email,email_verified_at,pending_email,pending_email_token_hash,pending_email_expires_at,password_hash,password_salt,password_iterations,must_change_password,account_locked,last_login_at,last_login_ip,created_at,created_by,modified_at,modified_byusernameis unique.
a_account_tokens
id,user_id,token_type,token_hash,expires_at,used_at,created_attoken_hashis unique.- Foreign key:
-
user_id->a_users.idwithON DELETE CASCADE - Indexed by
(token_type, token_hash, expires_at)and(user_id, token_type).
a_user_invitations
id,email,name,role_ids_json,token_hash,expires_at,used_at,created_at,created_bytoken_hashis unique.- Indexed by
(email, used_at, expires_at)and(created_by, created_at).
a_login_attempts
id,rate_key,failed_count,last_failed_at,locked_until,created_at,modified_atrate_keyis unique.
a_roles
id,role_key,name,description,created_at,created_by,modified_at,modified_byrole_keyis unique.nameis unique.
a_permissions
id,permission_key,name,section_name,description,created_at,modified_atpermission_keyis unique.
a_role_permissions
id,role_id,permission_id,created_at,modified_at- Foreign keys:
-
role_id->a_roles.id-permission_id->a_permissions.id - Unique key:
(role_id, permission_id)
a_user_roles
id,user_id,role_id,created_at,modified_at- Foreign keys:
-
user_id->a_users.id-role_id->a_roles.id - Unique key:
(user_id, role_id)
a_sessions
id,session_hash,user_id,ip_address,user_agent,expires_at,created_at,created_by,last_used_at,modified_bysession_hashis unique.- Foreign key:
-
user_id->a_users.id
Content
c_canvas_sizes- reusable canvas presets for templates.c_playlists- playlist definitions, playback options, and canvas assignment.c_templates- slide templates with canvas and background settings.c_template_regions- template region layout and metadata.c_slides- slide records with template binding, JSON content, and thumbnail path.c_media_assets- reusable uploaded media files referenced by slides and templates.c_playlist_slides- ordered playlist items and timing.c_playlist_slide_schedule_rules- rule rows attached to playlist slides.
c_canvas_sizes
id,name,width,height,created_at,created_by,modified_at,modified_by(width, height)is unique.
c_playlists
id,name,fade_between_slides,skip_unavailable_rtmp,canvas_id,created_at,created_by,modified_at,modified_by- Foreign key:
-
canvas_id->c_canvas_sizes.idwithON DELETE SET NULL
c_templates
id,name,canvas_size_id,background_image_path,background_color,background_gradient,created_at,created_by,modified_at,modified_bybackground_gradientstores normalized linear gradient settings as JSON text, including angle and colour stops.- Foreign key:
-
canvas_size_id->c_canvas_sizes.idwithON DELETE SET NULL
c_template_regions
id,template_id,region_key,region_type,label,font_family,lock_ratio,animation_json,x,y,width,height,z_index,created_at,created_by,modified_at,modified_by- Foreign key:
-
template_id->c_templates.idwithON DELETE CASCADE
c_slides
id,title,template_id,content_json,thumbnail_path,created_at,created_by,modified_at,modified_by- Foreign key:
-
template_id->c_templates.idwithON DELETE SET NULL
c_media_assets
id,media_path,original_name,media_type,mime_type,file_size,is_published,created_at,created_by,modified_at,modified_bymedia_pathis unique.- Indexed by
media_typeandcreated_at.
c_playlist_slides
id,playlist_id,slide_id,position,duration_seconds,use_video_duration,disable_audio,created_at,created_by,modified_at,modified_by- Foreign keys:
-
playlist_id->c_playlists.idwithON DELETE CASCADE-slide_id->c_slides.idwithON DELETE CASCADE
c_playlist_slide_schedule_rules
-
id,playlist_slide_id,position,start_datetime,end_datetime,start_time,end_time,schedule_days_json,created_at,created_by,modified_at,modified_by -
Foreign key: -
playlist_slide_id->c_playlist_slides.idwithON DELETE CASCADE -
Index: -
(playlist_slide_id, position) -
Each playlist slide can have zero or more schedule rules.
-
Rules are evaluated with OR across rows and with AND across the fields inside a single rule.
Devices
d_players- player registry and connection metadata.d_screens- screen records and playlist assignment.d_onboarding_devices- device-to-screen bindings and onboarded client names.
d_players
id,identifier,public_base_url,internal_base_url,last_seen_at,created_at,modified_atidis the primary key.identifieris unique and is the stable player identity used by the app.
d_screens
-
id,name,slug,playlist_id,created_at,created_by,modified_at,modified_by -
slugis unique. -
Foreign keys: -
playlist_id->c_playlists.idwithON DELETE SET NULL -
Screens are no longer tied to a player foreign key directly; player registration and live connection metadata are tracked separately in
d_players.
d_onboarding_devices
id,device_id,client_name,screen_id,created_at,created_by,modified_at,modified_by,last_seen_atdevice_idis unique.- Foreign key:
-
screen_id->d_screens.idwithON DELETE SET NULL
Onboarding
- The onboarding flow uses
d_onboarding_devicesto bind a device to a screen and persist the client name.
Announcements
d_announcements- announcement content and display metadata.d_announcement_screens- announcement-to-screen assignments.
d_announcements
id,message,short_label,announcement_type,color_key,icon_key,duration_seconds,expires_at,created_at,created_by,modified_at,modified_byannouncement_typedefaults tolower-third.
d_announcement_screens
announcement_id,screen_id,created_at,created_by,modified_at,modified_by- Foreign keys:
-
announcement_id->d_announcements.idwithON DELETE CASCADE-screen_id->d_screens.idwithON DELETE CASCADE - Unique key:
(announcement_id, screen_id)
Integrations
i_rss_feeds- RSS feed definitions and refresh cadence.i_rss_feed_items- cached RSS feed items.i_api_source_groups- API source names and shared authentication settings.i_api_sources- named requests, independent refresh settings, and last response snapshots.i_weather_locations- configured weather locations and last response snapshot.i_timetable_groups- grouped timetable definitions used by the timetable region.i_timetable_entries- dated entries that belong to a timetable group.
i_rss_feeds
id,name,feed_url,update_interval_value,update_interval_unit,item_limit,enabled,last_pulled_at,created_at,created_by,modified_at,modified_by
i_rss_feed_items
id,rss_feed_id,position,item_json,created_at,created_by,modified_at,modified_by- Foreign key:
-
rss_feed_id->i_rss_feeds.idwithON DELETE CASCADE - Unique key:
-
(rss_feed_id, position)
i_api_source_groups
id,name,auth_method,auth_username,auth_password,auth_bearer_token,auth_header_name,auth_header_value,token_url,token_request_body_json,token_response_path,token_refresh_url,token_refresh_request_body_json,token_refresh_response_path,token_header_name,token_header_prefix,created_at,created_by,modified_at,modified_by- Unique group name; authentication applies to every child request.
auth_method = 'none'supports public endpoints. Token caches are keyed by group and authentication configuration.
i_api_sources
id,auth_source_id,name,api_url,request_method,request_body_json,items_path,update_interval_value,update_interval_unit,enabled,last_pulled_at,last_pull_error,last_response_status,last_response_content_type,last_response_json,created_at,created_by,modified_at,modified_byauth_source_idreferencesi_api_source_groups.idwith restricted parent deletion. The web application requires at least one request per group and unique request names within each group.- Request IDs remain the
source_idstored in slide regions and the keys used by scheduled refreshes. Removing a request used by a slide is blocked. - The 2.16.1 migration copies each existing source's authentication into a same-ID parent group and links the original request without changing its ID or response snapshot. Legacy authentication columns remain on request rows for schema compatibility but runtime authentication is loaded from the parent.
- Editor/player request lists exclude authentication credentials. Refreshes resolve current parent authentication at execution time.
i_weather_locations
id,name,location_label,latitude,longitude,timezone,provider,temperature_unit,wind_unit,precipitation_unit,update_interval_value,update_interval_unit,enabled,last_pulled_at,last_pull_error,last_response_json,created_at,created_by,modified_at,modified_by- Stores configured weather locations and the most recent provider response used for forecast previews and weather regions.
i_timetable_groups
id,name,short_description,timezone,created_at,created_by,modified_at,modified_bytimezonedefaults toEurope/London.
i_timetable_entries
id,schedule_group_id,title,short_description,start_datetime,end_datetime,created_at,created_by,modified_at,modified_by- Foreign key:
-
schedule_group_id->i_timetable_groups.idwithON DELETE CASCADE - Index:
-
(schedule_group_id, start_datetime)
Operations
o_background_tasks- queue and history for background jobs.o_app_state- generic app state and version markers stored as key/value pairs.o_app_settings- administrator-configurable application settings stored by key.o_audit_events- retained audit events for administrator activity and system changes.
o_background_tasks
id,task_key,task_type,title,category,status,payload_json,metadata_json,attempts,created_at,created_by,started_at,finished_at,error_message- Indexed by
status,task_key, andtask_type.
o_app_state
id,state_key,state_value,created_at,modified_atstate_keyis unique.schema_versionis stored here so startup can detect the previously recorded schema version before deciding whether migrations need to run.
o_app_settings
id,setting_key,setting_value,created_at,created_by,modified_at,modified_bysetting_keyis unique.- Values are stored as JSON and validated against the application setting definitions in
src/data/app-settings.js.
o_audit_events
id,occurred_at,category,event_type,actor_user_id,target_type,target_id,target_label,ip_address,user_agent,details_json- Indexed by occurrence time, category and event type, actor, and target.
Notes
- The schema is initialized with
CREATE TABLE IF NOT EXISTS, so new installs can start from an empty database. src/db/bootstrap.jsseeds the canvas size defaults, default permissions, and the default administrator role.src/db/migrations.jsrecords the current schema version ino_app_stateduring startup so later launches can tell whether an update is happening.- The ER diagram shows declared foreign keys and the logical audit actor association; player registry and JSON-based references are intentionally not shown as foreign-key relationships.
erDiagram
A_USERS {
}
A_ROLES {
}
A_PERMISSIONS {
}
A_ROLE_PERMISSIONS {
}
A_USER_ROLES {
}
A_SESSIONS {
}
A_ACCOUNT_TOKENS {
}
A_USER_INVITATIONS {
}
A_LOGIN_ATTEMPTS {
}
C_CANVAS_SIZES {
}
C_PLAYLISTS {
}
C_TEMPLATES {
}
C_TEMPLATE_REGIONS {
}
C_SLIDES {
}
C_MEDIA_ASSETS {
}
C_PLAYLIST_SLIDES {
}
C_PLAYLIST_SLIDE_SCHEDULE_RULES {
}
D_PLAYERS {
}
D_SCREENS {
}
D_ONBOARDING_DEVICES {
}
D_ANNOUNCEMENTS {
}
D_ANNOUNCEMENT_SCREENS {
}
I_RSS_FEEDS {
}
I_RSS_FEED_ITEMS {
}
I_API_SOURCES {
}
I_API_SOURCE_GROUPS {
}
I_WEATHER_LOCATIONS {
}
I_TIMETABLE_GROUPS {
}
I_TIMETABLE_ENTRIES {
}
O_APP_STATE {
}
O_APP_SETTINGS {
}
O_BACKGROUND_TASKS {
}
O_AUDIT_EVENTS {
}
A_USERS ||--o{ A_USER_ROLES : has
A_ROLES ||--o{ A_USER_ROLES : assigned_to
A_ROLES ||--o{ A_ROLE_PERMISSIONS : has
A_PERMISSIONS ||--o{ A_ROLE_PERMISSIONS : granted_to
A_USERS ||--o{ A_SESSIONS : owns
A_USERS ||--o{ A_ACCOUNT_TOKENS : has
A_USERS o|--o{ O_AUDIT_EVENTS : acts
I_API_SOURCE_GROUPS ||--o{ I_API_SOURCES : contains
C_CANVAS_SIZES o|--o{ C_TEMPLATES : used_by
C_CANVAS_SIZES o|--o{ C_PLAYLISTS : used_by
C_TEMPLATES ||--o{ C_TEMPLATE_REGIONS : contains
C_TEMPLATES o|--o{ C_SLIDES : used_by
C_MEDIA_ASSETS }o..o{ C_SLIDES : referenced_by
C_MEDIA_ASSETS o{..o| C_TEMPLATES : background_for
C_PLAYLISTS ||--o{ C_PLAYLIST_SLIDES : contains
C_SLIDES ||--o{ C_PLAYLIST_SLIDES : included_in
C_PLAYLIST_SLIDES ||--o{ C_PLAYLIST_SLIDE_SCHEDULE_RULES : has_rules
C_PLAYLISTS o|--o{ D_SCREENS : uses
D_SCREENS o|--o{ D_ONBOARDING_DEVICES : binds
D_ANNOUNCEMENTS ||--o{ D_ANNOUNCEMENT_SCREENS : targets
D_SCREENS ||--o{ D_ANNOUNCEMENT_SCREENS : receives
I_RSS_FEEDS ||--o{ I_RSS_FEED_ITEMS : caches
I_TIMETABLE_GROUPS ||--o{ I_TIMETABLE_ENTRIES : contains