diff --git a/CHANGELOG.md b/CHANGELOG.md index 78aa5bc..071fe7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. +## 2.6.21 - 2026-08-09 + +### Changed + +- Startup now logs the previously detected schema version, the current app version, and whether migrations are required. +- The schema documentation now reflects the timetable table rename, the new `o_app_state` table, and startup version tracking. +- Timetable timezone placeholders now use `tz` for the short zone name and `tz_long` for the full IANA zone. + ## 2.6.20 - 2026-08-09 ### Changed diff --git a/build/package.player.json b/build/package.player.json index 513fbb0..cb33a65 100644 --- a/build/package.player.json +++ b/build/package.player.json @@ -1,6 +1,6 @@ { "name": "pulse-signage-player", - "version": "2.6.20", + "version": "2.6.21", "private": false, "description": "Pulse Signage player application bundle", "main": "src/common.js", diff --git a/build/package.web.json b/build/package.web.json index 421bf29..61494d3 100644 --- a/build/package.web.json +++ b/build/package.web.json @@ -1,6 +1,6 @@ { "name": "pulse-signage-web", - "version": "2.6.20", + "version": "2.6.21", "private": false, "description": "Pulse Signage web and bridge application bundle", "main": "src/common.js", diff --git a/docs/schema.md b/docs/schema.md index ed53229..4970c2f 100644 --- a/docs/schema.md +++ b/docs/schema.md @@ -165,8 +165,8 @@ Primary keys are `id` unless noted otherwise. Timestamps are stored as `created_ - `i_rss_feeds` - RSS feed definitions and refresh cadence. - `i_rss_feed_items` - cached RSS feed items. - `i_api_sources` - API source definitions and last response snapshot. -- `i_schedule_groups` - grouped schedule definitions used by the schedule region. -- `i_schedule_entries` - dated entries that belong to a schedule group. +- `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` @@ -184,32 +184,40 @@ Primary keys are `id` unless noted otherwise. Timestamps are stored as `created_ - `id`, `name`, `api_url`, `auth_method`, `auth_username`, `auth_password`, `auth_bearer_token`, `auth_header_name`, `auth_header_value`, `items_path`, `update_interval_value`, `update_interval_unit`, `last_pulled_at`, `last_pull_error`, `last_response_status`, `last_response_content_type`, `last_response_json`, `created_at`, `created_by`, `modified_at`, `modified_by` -### `i_schedule_groups` +### `i_timetable_groups` -- `id`, `name`, `short_description`, `created_at`, `created_by`, `modified_at`, `modified_by` +- `id`, `name`, `short_description`, `timezone`, `created_at`, `created_by`, `modified_at`, `modified_by` +- `timezone` defaults to `Europe/London`. -### `i_schedule_entries` +### `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_schedule_groups.id` with `ON DELETE CASCADE` + - `schedule_group_id` -> `i_timetable_groups.id` with `ON 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_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`, and `task_type`. +### `o_app_state` + +- `state_key`, `state_value`, `created_at`, `modified_at` +- `state_key` is the primary key. +- `schema_version` is stored here so startup can detect the previously recorded schema version before deciding whether migrations need to run. + ## Notes - The schema is initialized with `CREATE TABLE IF NOT EXISTS`, so new installs can start from an empty database. - `src/db/bootstrap.js` seeds the canvas size defaults, default permissions, and the default administrator role. -- The migration module stays in place for future releases, but this version treats the current schema as the install baseline. +- `src/db/migrations.js` records the current schema version in `o_app_state` during startup so later launches can tell whether an update is happening. ```mermaid erDiagram @@ -255,9 +263,11 @@ erDiagram } I_API_SOURCES { } - I_SCHEDULE_GROUPS { + I_TIMETABLE_GROUPS { } - I_SCHEDULE_ENTRIES { + I_TIMETABLE_ENTRIES { + } + O_APP_STATE { } O_BACKGROUND_TASKS { } @@ -282,5 +292,5 @@ erDiagram D_SCREENS ||--o{ D_ANNOUNCEMENT_SCREENS : receives I_RSS_FEEDS ||--o{ I_RSS_FEED_ITEMS : caches - I_SCHEDULE_GROUPS ||--o{ I_SCHEDULE_ENTRIES : contains + I_TIMETABLE_GROUPS ||--o{ I_TIMETABLE_ENTRIES : contains ``` \ No newline at end of file diff --git a/package.json b/package.json index 348ab2b..5f7aca8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pulse-signage", - "version": "2.6.20", + "version": "2.6.21", "private": false, "description": "Pulse Signage application with MySQL and media storage", "repository": { diff --git a/src/player/regions/time-date.js b/src/player/regions/time-date.js index 62df679..8cc0a7e 100644 --- a/src/player/regions/time-date.js +++ b/src/player/regions/time-date.js @@ -213,8 +213,8 @@ function getFormattedParts(timeZone, date) { MMM: toTitleCase(getPart(monthShort, 'month')), MMMM: toTitleCase(getPart(monthLong, 'month')), a: toTitleCase(getPart(ampm, 'dayPeriod')), - tz: resolvedTimeZone, - tz_short: getPart(timezoneShort, 'timeZoneName'), + tz: getPart(timezoneShort, 'timeZoneName'), + tz_long: resolvedTimeZone, date: getPart(numericParts, 'year') + '-' + getPart(numericParts, 'month') + '-' + getPart(numericParts, 'day'), time: getPart(numericParts, 'hour') + ':' + getPart(numericParts, 'minute') + ':' + getPart(numericParts, 'second') }; diff --git a/src/web/public/js/regions/type/schedule.js b/src/web/public/js/regions/type/schedule.js index d460ecf..3fb588c 100644 --- a/src/web/public/js/regions/type/schedule.js +++ b/src/web/public/js/regions/type/schedule.js @@ -84,8 +84,8 @@ } return { - tz: timeZone, - tz_short: shortName + tz: shortName, + tz_long: timeZone }; } @@ -298,7 +298,7 @@ '
{{title.upper()}}, {{title.title()}}, {{title.lower()}}, {{start.format("MMM D, YYYY h:mm A")}}, {{start.tz()}} or {{start.tz_short()}}.{{title.upper()}}, {{title.title()}}, {{title.lower()}}, {{start.format("MMM D, YYYY h:mm A")}}, {{start.tz()}} for the short zone name, or {{start.tz_long()}} for the full IANA zone name.{{title}} {{start.tz()}} {{start.tz_short()}}
', + value: '{{title}} {{start.tz()}} {{start.tz_long()}}
', timetable_group_id: 1, display_mode: 'current', max_items: 3 @@ -103,7 +103,7 @@ test('timetable region editor lists timezone transforms in helper text', () => { assert.match(html, /Placeholder values support transforms/); assert.match(html, /\{\{start\.tz\(\)\}\}<\/code>/);
- assert.match(html, /\{\{start\.tz_short\(\)\}\}<\/code>/);
+ assert.match(html, /\{\{start\.tz_long\(\)\}\}<\/code>/);
assert.doesNotMatch(html, /class="chip">\{\{start\.tz\(\)\}\}<\/span>/);
});
@@ -136,7 +136,7 @@ test('timetable region editor shows supported date format tokens', () => {
assert.doesNotMatch(html, /yyyy<\/code><\/td>/);
assert.doesNotMatch(html, /yy<\/code><\/td>/);
assert.doesNotMatch(html, /tz<\/code><\/td>/);
- assert.doesNotMatch(html, /tz_short<\/code><\/td>/);
+ assert.match(html, /start\.tz_long\(\)/);
assert.match(html, /Use these tokens inside \.format\(\.\.\.\)<\/code>/);
});
@@ -145,7 +145,7 @@ test('timetable region preview resolves timezone placeholders from explicit time
const preview = module.renderPreview(
{ id: 47, width: 500, height: 280 },
{
- value: '{{start.tz("UTC")}} {{start.tz_short("UTC")}}
',
+ value: '{{start.tz("UTC")}} {{start.tz_long("UTC")}}
',
timetable_group_id: 1,
display_mode: 'both',
max_items: 3
@@ -210,7 +210,7 @@ test('timetable timezone abbreviation changes across daylight saving boundaries'
const preview = module.renderPreview(
{ id: 47, width: 500, height: 280 },
{
- value: '{{start.tz_short("Europe/London")}}
',
+ value: '{{start.tz("Europe/London")}}
',
timetable_group_id: 1,
display_mode: 'both',
max_items: 10
@@ -265,7 +265,7 @@ test('timetable preview does not force the group timezone into placeholder trans
const preview = module.renderPreview(
{ id: 47, width: 500, height: 280 },
{
- value: '{{start.tz_short()}}
',
+ value: '{{start.tz_long()}}
',
timetable_group_id: 1,
display_mode: 'both',
max_items: 3