App Architecture
This developer guide explains how the code is organized. For user guidance on roles and production workflow, start with the Overview.
The sections below describe dependencies between pages, app components and library modules. The shared UI library has separate documentation linked below.
Dependency Diagram
Read the diagram from top to bottom: pages load app.mjs and app components,
which use shared UI components and library modules. An indented component is opened or
mounted by the component above it.
How to read the diagram
The diagram shows which pages load each component, which components mount others, and dependencies between groups of library modules. Drawing every import would make the diagram unreadable. For individual imports, use the per-page and per-module lists below.
Shared components appear once in the diagram. bg-jobs
and app-local-audio also appear inside
app-advanced;
app-workflow opens from both members and production
cards; and side-panel underlies three studio panels.
The studio.html section maps module names to exported classes.
index.html initializes localization independently and has no auth
guard, so it has no dependency on app.mjs.
index.html — Landing Page
Introduces SpokenWords and links to the app and documentation. It initializes localization
to translate its static markup without loading app.mjs or applying a
data-auth guard. It loads ui-icon and ui-theme-toggle.
auth.html — Authentication
Signs in existing accounts, which administrators create. The
data-auth="guest" guard redirects signed-in users to Productions or the page
that originally requested sign-in.
Imports
- app.mjs
- ui-icon, ui-statusbar
- Inline auth module using auth.mjs and auth-error.mjs
productions.html — Dashboard
Main dashboard with production list, team members, and the Advanced hub.
Auth guard: data-auth="required".
App Components
- app-productions — Production cards with menu actions → api, auth, assignment-rows, project-health, content-types, webarch-socket, diagnostics, dialog, toast, notifications
- app-team-members — Manage team members → api, auth, teams, dialog, toast
-
app-advanced — Advanced tools at
#advanced/<slug>, opened from the account menu. Tabs show this browser's job queue, local recordings and private file system for any signed-in session → bg-jobs, app-local-audio, app-local-storage
Dialog and view sub-components
- app-project-import — "Import production" dialog: select a product and issue, import through POST /issues/{id}/import, then open assignments → api, x-select, ui-combobox
- app-project-edit — Project metadata editor: title, author, language. The content type is shown but not editable; it comes from the source product
- app-workflow — Assign production roles: lead, producer, editor, narrator and reviewer
- app-production-details — Full production details beyond the card's metadata summary
- app-article-preview — The production's article list inside its card, with take counts and review state → app-held-takes
- app-add-member — Launched from team members → api
UI Components used
- ui-icon, ui-menu, ui-dialog, ui-tab, ui-outlet, ui-combobox, ui-notifications, ui-statusbar, ui-theme-toggle, x-select
studio.html — Recording Studio
The inline script reads ?id= and optional &article= parameters,
creates state and tracking objects, and initializes panel classes against existing markup.
It coordinates recording, editing, playback and synchronization.
The page requires data-auth="required".
State objects (initialized in inline script)
- StudioState — Project articles, assignments, metadata
- EditorState — Markup and guidance annotations with undo/redo
- RecordingState — Recording state machine, takes (wired to recording-session, the advisory "recording right now" presence signal)
- Playback — Audio playback with word-level timing
- LiveTracker — Live reading progress from streaming speech recognition
- VuMeter — Real-time audio level metering
- SentenceIssues — Per-sentence issue tracking
- DeliveryCheck — Delivery readiness of the production
sync-pipeline handles uploads as a shared module used
through RecordingState and StudioFooter. The page follows export
outcomes through commit-flow.
App Components (exported classes, not custom elements)
- StudioHeader — Top bar: stage, hand-over, export, mic device → workflow-stage, article-state, workflow-actions, commit-flow, production-menu, held-takes, mic-devices, dialog, toast, tooltip
- StudioToolbar — Annotation editing toolbar → studio-actions, annotations, annotation-groups, toast, tooltip
- StudioReader — Main reading/editing area: the chapter’s original document, rendered → wdf-html, article-figures, annotations, annotation-paint, sentences, sentence-status, studio-actions, audio-levels, text-search, listbox, dialog, toast, tooltip
- StudioFooter — Bottom controls (record/sync) → studio-actions, sync-pipeline, audio-store, audio-levels, article-state, mic-devices, dialog, toast, tooltip
- StudioPanel — Annotation sidebar → annotations, annotation-groups, side-panel, dialog, toast, tooltip
- BookmarksPanel — Bookmarks side panel → bookmarks
- AudioProcessingPanel — Audio processing side panel → audio-processing
- ContentNavigator — Move between the production's articles → article-state, content-types, tree, side-panel
- ArticleOverview — Whole-article take and waveform overview → waveform-data, previous-audio, speech-estimate, playhead-mark, take-row
- DeliveryChecklist — What still blocks delivery → delivery-check
Components loaded by the studio panels
These custom elements and the shared base class are loaded by the panels above. They appear as indented boxes in the diagram's studio column.
- app-held-takes — Held recordings for an article, with Accept and Discard controls for producers (from StudioHeader and from app-article-preview) → held-takes, diagnostics, dialog
- app-declined-saves — Declined queued markup saves, shown beside the text each edit was based on (from StudioToolbar) → toast
- SentenceWaveform — Inline per-sentence waveform with draggable trim handles, mounted by the reader's "Show waveform" toggle (from StudioReader) → waveform-data
- app-studio-search — Search across the production. This component manages the query; the reader highlights matches (from StudioReader) → text-search
-
SidePanelHost — The studio's end-side panel: one
<aside>that collapses to a rail of icon buttons and shows one member view at a time (BookmarksPanel, AudioProcessingPanel, StudioPanel, the reading settings) through<ui-outlet>. The slide and theinertmarking come from ui/lib/side-panel.mjs
UI Components used
- ui-icon, ui-menu, ui-popover, ui-toolbar, ui-notifications, ui-notification-item, ui-statusbar
jobs.html — Job Queue Monitor
Background job status tracking. Auth guard: data-auth="required".
App Components
- bg-jobs — Job list with retry/delete → job-queue, stable-table, notifications
local-audio.html — Local Audio Manager
Manage locally cached audio files in IndexedDB. Auth guard: data-auth="required".
App Components
- app-local-audio — Audio storage list → audio-store, stable-table, notifications
Lib Modules
Grouped by domain. Arrows (→) show imports from other lib modules.
Config & Utilities
- config — the per-install
api_baseandwebsocket_url(imported by app.mjs, api, playback, webarch-socket) - stt-elevenlabs — ElevenLabs Scribe integration: batch and streaming endpoints, language mappings and team credentials → audio-format
- project-languages — Supported production languages accepted by the projects endpoint
- version — Build version and whether the page assets are served by a service worker
- UiElement —
html,csstemplate tag helpers (used by all components + toast, tooltip) - AppElement — Base class for app custom elements with localization updates (planned infrastructure; no subclass yet)
- l10n — Translation catalog,
t(), plurals, and locale change events - activity — Activity timestamp tracking (
track()/last()) - esc — HTML escaping for template interpolation
- units — Quantities written the way the reader's locale writes them; today byte sizes → l10n
- aria-reflection — ARIA attribute reflection polyfill (side-effect, loaded from preload)
- anchor-fallback — Fallback for browsers without CSS anchor positioning (side-effect, loaded from preload)
- ui —
spin()icon animation andcoalesce_microtask() - select — DOM reconciliation for x-select options (
setOptions) - cross-tab-events — BroadcastChannel bus shared by audio-store and job-queue
- idb-promise — Promise wrapper over IndexedDB requests
Auth & API
- api — HTTP client (get/get_text/post/patch/del/upload) → config, activity, l10n
- auth — Session management with auto-refresh → api, activity
- auth-error — Reports sign-in errors through the shared toast and statusbar
- teams — Team and role labels shared by the members page and the workflow dialog
- crew — Organization assignments and the shared dialog for viewing and staffing production roles → api, dialog, l10n
UI Helpers
- dialog — Dialog lifecycle (open/close/show_component_dialog/response_dialog) → view, animation
- toast — Transient messages with ARIA live region → UiElement
- notifications — App-global notification store behind ui-statusbar and ui-notifications
- tooltip — Tooltip attachment → UiElement
- view — View lifecycle helpers for ui-outlet → animation
- animation — Await a CSS animation, with a fallback timer for headless runs
- announce — Polite live-region announcements for the decorators
- tree, accordion, listbox, side-panel — APG keyboard behavior for existing markup
- stable-table — Diff-and-patch
<tbody>re-render that keeps row identity - scroll-util — Scroll into view only when the target has left the reading zone, on both axes
- theme — System / Light / Dark switch behind ui-theme-toggle
Text Processing
- sentences — Canonical sentence model (server-derived) (hub: imported by 9 modules)
- annotations — SSML annotation CRUD + char/word position mapping → sentences
- annotation-groups — One table of annotation groups, read by both the toolbar and the reader's per-sentence menu
- annotation-paint — Paints annotation marks over the rendered text
- guidance-annotations — API storage for comment, tone and structure guidance
- sentence-status — Per-sentence status glyphs in the reader → sentences
- text-search — Search result positions and mapping to displayed word spans
- wdf-html — Converts a chapter’s source HTML into the allowed subset the studio’s reading area mounts
- alignment — Align STT timestamps to sentences → sentences
- ipa-lookup — Swedish IPA pronunciation lookup
Audio & Recording
- audio-store — IndexedDB offline audio storage → cross-tab-events, idb-promise (hub: imported by 5 modules)
- recording-state — Recording state machine → api, audio-store, sync-pipeline, wav-recorder, audio-processing, take-row, studio-settings
- recording-session — Advisory "recording right now" presence signal → api
- wav-recorder — Captures the microphone and encodes WAV
- playback — Audio playback with karaoke timing → config, api, audio-store, previous-audio
- previous-audio — Loads previous audio from byte ranges in published files
- take-row — Pure mapping from a takes API row to the in-memory take
- held-takes — API access to recordings held after an article was locked
- vu-meter — Real-time audio level metering
- audio-levels — RMS analysis & level warnings → audio-processing
- audio-processing — The post-processing DSP chain (high-pass, de-esser, EQ, gate, trim, normalize, limiter) plus peak/LUFS analysis
- waveform-data — Extracts waveform peaks from decoded recordings
- article-figures — Fetches a rendered chapter’s figures once its words are on screen → api
- playhead-mark — Draws the playhead over a waveform
- audio-format — File extension and container for the recorded audio
- mic-devices — Populates the microphone selector
- speech-estimate — Estimated speaking time for a stretch of text
- live-tracking — Tracks reading progress from streaming recognition of recorded PCM → stt
- stt — Selects an entitled speech-recognition service for batch and live transcription → stt-elevenlabs
- stt-install — Page side of the device-local speech model's install; runs the shared worker and publishes how far it has got → config, api, stt
- stt-install-worker — Shared worker that fetches the model into the private file system, resuming with Range requests and reporting the whole install's byte counts and time estimate
- stt-install-sizes — The install's completeness ledger: the expected length of each stored file
- stt-notice — The one statusbar entry reporting speech-recognition startup, on every signed-in page → notifications, l10n, units, stt-install, stt
Sync & Jobs
- sync-pipeline — Upload → transcribe → align → save → api, audio-store, transcription, audio-format, alignment, sentences, diagnostics
- webarch-socket — Websocket feed of import and export progress → config
- commit-flow — Export articles, then follow them to their terminal state → workflow-actions, api, webarch-socket, notifications
- job-queue — Job queue interface (spawns Web Worker) → cross-tab-events, job-backoff
- job-worker — Background job processor (Web Worker) → job-backoff, idb-promise
- job-backoff — Retry schedule shared by the queue and its worker
State
- studio-state — Project, articles, assignments → api, auth, sentences, content-types, workflow-stage, assignment-rows, session-store, diagnostics
- editor-state — Annotation state with undo/redo → annotations, guidance-annotations, sentences, api + job-queue (lazy)
- article-state — What state an article is in, and what the viewer may do to it
- workflow-stage — The per-article stage (draft → recording → review → done), its label, and whose turn it is
- workflow-actions — API operations for stage changes, import, export and rollback → api
- assignment-rows — Which rows of a production's assignments belong to the reader
- project-health — Project configuration checks that can block work
- delivery-check — Client for server-computed delivery readiness
- content-types — Content-type terminology: what a production's parent and its units are called, and their icons
- studio-settings — The shared
studio-settingslocalStorage blob: reading preferences plus mic gain and device - session-store — IndexedDB store for the studio resume position, so a reload lands where the reader left off
- bookmarks — Per-user, per-project quick-jump markers (API wrapper)
- studio-actions — Action handlers (phoneme, comment, review) → toast, dialog, ipa-lookup
- production-menu — The bulk-action menu shared by the studio header and the productions list
- sentence-issues — Per-sentence issue tracking (EventTarget)
- diagnostics — Error reporting + STT debug logging → toast, notifications, alignment