feat: initial Signage 0.1.0
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
# Signage
|
||||
|
||||
Ekklesia's visual programming, timeline, synchronization, and display-delivery module.
|
||||
|
||||
Signage decides **what is on a screen, when, and on which screens together**. It natively supports
|
||||
static images; every other kind of content reaches a screen because another Ekklesia module
|
||||
registered a content provider and contributed a live React renderer for it. Signage never learns what
|
||||
an announcement, a Bible passage, or a trivia question is.
|
||||
|
||||
This repository is a standalone, independently versioned Ekklesia module package. It is not a fork of
|
||||
Ekklesia and vendors none of its SDKs.
|
||||
|
||||
- Module id: `signage`
|
||||
- Package: `@ekklesia/signage`
|
||||
- Manifest version: 7
|
||||
|
||||
## Status
|
||||
|
||||
Version 0.1.0 is feature-complete for its declared scope and unreleased. What exists today:
|
||||
|
||||
- The module package, manifest (v7), four capabilities, six permissions, ten operator settings, and
|
||||
one logical storage bucket.
|
||||
- Eleven tables and a single initial migration, declared non-destructive.
|
||||
- Native image ingest: one image per streamed request, 25 MiB, content-addressed, with display and
|
||||
thumbnail renditions and temporary object keys removed after any unsuccessful upload.
|
||||
- The content provider contract and registry, a bounded and sanitized call path, and Signage's own
|
||||
built-in image provider registered through that same capability.
|
||||
- Timelines, provider source slots, pinned slots, channel groups, synchronized audience channels,
|
||||
authoritative playback with absolute instants, activation and scheduling, and viewer
|
||||
registration, assignment, heartbeat, and health.
|
||||
- A management-UI artifact and a full-viewport display artifact, both built through the canonical
|
||||
Ekklesia module UI pipeline and mounted through the platform's browser ABI.
|
||||
- Two permanent scene layers with a crossfade that never fades the outgoing slide, provider
|
||||
renderers mounted as browser contributions, the built-in "Content unavailable" slate, deliberate
|
||||
blackout, and offline continuation from this display's own persisted state.
|
||||
|
||||
Nothing here is deployed, and no cutover from the legacy Announcements container has happened or is
|
||||
planned by this repository. Video, audio, MQTT, Home Assistant, Companion, and a notification outbox
|
||||
are out of scope; so is any content module — Signage ships with no announcements, scripture, or
|
||||
trivia, and cannot render any until one is installed.
|
||||
|
||||
### Offline cold start is not yet possible
|
||||
|
||||
A display that is **already mounted** keeps playing with no network: its schedule, playback state,
|
||||
provider payloads, and media are Signage's own, persisted by this module in IndexedDB and Cache
|
||||
Storage. Core's service worker caches module *code*, not Signage domain data.
|
||||
|
||||
A display that is **restarted while Ekklesia is completely unreachable** cannot mount Signage at all.
|
||||
Mounting requires an authenticated module descriptor, and Core does not yet cache one. True offline
|
||||
cold start depends on a Core-provided authorized offline display descriptor or lease; until that
|
||||
exists, this module does not claim it. See ADR 0006.
|
||||
|
||||
## Developing against Ekklesia
|
||||
|
||||
Signage is developed **inside the authoritative Ekklesia workspace**, checked out at the path it will
|
||||
eventually be installed at:
|
||||
|
||||
```bash
|
||||
git clone <ekklesia> ekklesia
|
||||
git clone <this repository> ekklesia/modules/signage
|
||||
cd ekklesia
|
||||
pnpm install
|
||||
```
|
||||
|
||||
`modules/*` is an Ekklesia workspace glob, so the checkout is picked up with no registry edit,
|
||||
no second copy of Ekklesia, and no vendored SDK. `@ekklesia/module-sdk`, `@ekklesia/module-ui-sdk`,
|
||||
`@ekklesia/design-tokens`, `@ekklesia/ui`, and `@ekklesia/module-ui-build` all resolve through the
|
||||
workspace as `workspace:*` dependencies.
|
||||
|
||||
Two consequences worth knowing:
|
||||
|
||||
- Ekklesia uses a shared workspace lockfile, so installing here writes an importer entry for
|
||||
`modules/signage` into Ekklesia's `pnpm-lock.yaml`. That entry belongs to whoever maintains the
|
||||
Ekklesia checkout; it is not committed from this repository.
|
||||
- Signage requires the Ekklesia platform prerequisites for shared design tokens, module stylesheets,
|
||||
browser contributions, bounded streaming request bodies, and display offline code
|
||||
(ADRs 0039–0043). An Ekklesia checkout without them cannot build or validate this module.
|
||||
|
||||
### Commands
|
||||
|
||||
Run from the **Ekklesia repository root**:
|
||||
|
||||
```bash
|
||||
pnpm --filter @ekklesia/signage build # tsc + the canonical module UI build
|
||||
pnpm --filter @ekklesia/signage test # unit and browser-artifact tests
|
||||
pnpm --filter @ekklesia/signage typecheck # node, browser, and browser-test projects
|
||||
pnpm --filter @ekklesia/signage lint
|
||||
|
||||
pnpm boundaries # four-layer boundary enforcement
|
||||
pnpm modules:validate # static manifest, entrypoint, and schema validation
|
||||
pnpm migrations:validate # migration journal, policy, ordering, and checksums
|
||||
pnpm verify # the full Docker-free gate
|
||||
```
|
||||
|
||||
Signage's tests are its own: `pnpm test` here runs `vitest` against this package's `vitest.config.ts`,
|
||||
which includes `.test.tsx` as well as `.test.ts`. The workspace-root config includes only `.test.ts`,
|
||||
so a browser test added here without that config would be silently skipped.
|
||||
|
||||
Never run `pnpm migrations:apply` against a persistent database while developing this module. Signage
|
||||
reads no environment variable, constructs no database client, configures no object storage, hardcodes
|
||||
no Ekklesia URL, opens no socket of its own, and applies no migration: every one of those reaches it
|
||||
through the host.
|
||||
|
||||
### Changing the schema
|
||||
|
||||
```bash
|
||||
pnpm --filter @ekklesia/signage migration:generate # drizzle-kit, into drizzle/
|
||||
```
|
||||
|
||||
`tests/schema.test.ts` pins the checksum of the generated SQL, so a regenerated migration fails the
|
||||
suite until the pin is updated deliberately. `drizzle/meta/_ekklesia.json` declares the migration
|
||||
non-destructive; `pnpm migrations:validate` enforces that.
|
||||
|
||||
### Verifying what only a browser can show
|
||||
|
||||
Automated DOM assertions cannot prove a crossfade, a letterboxed image, or a slate. Those are
|
||||
verified by driving the **built** artifacts in a real Chromium against a stub host and reading the
|
||||
frames: native fill, both letterboxed fits, a contributed renderer, a frozen mid-crossfade composite,
|
||||
the slate, a blackout, the offline indicator, every management tab, and the narrow-screen gate. The
|
||||
harness is deliberately not committed — it stubs a host and would rot into a second, wrong
|
||||
description of the platform ABI.
|
||||
|
||||
## What Signage owns, and what providers own
|
||||
|
||||
| Signage owns | A content provider owns |
|
||||
| --- | --- |
|
||||
| Native image assets and their renditions | Its own domain content and tables |
|
||||
| Saved timelines, repeating patterns, and slots | Which of its content is available now |
|
||||
| Channel groups and synchronized audience channels | Selecting the next item from one of its sources |
|
||||
| Slot timing and authoritative playback | Repeat and no-repeat policy |
|
||||
| Timeline activation and scheduling | Audience-specific variants and fallback |
|
||||
| Viewer registration, assignment, heartbeat, health | Its own live React presentation |
|
||||
| Transitions, offline continuation, playback controls | Dynamic change within one slide |
|
||||
| The management and display UI | Its own internal multi-stage behaviour |
|
||||
|
||||
## Licence and scope
|
||||
|
||||
Deployment, the module store, a theme editor, a mobile management UI, video and audio, MQTT, Home
|
||||
Assistant, Companion, and any migration of legacy Announcements data are explicitly out of scope for
|
||||
this repository.
|
||||
|
||||
Reference in New Issue
Block a user