Appearance
Playout — feature audits
Vue 3 + FormKit + @playout/ui · en/fr/no. 21 features audited. Totals across this project:
Blocker 10 · High 69 · Medium 145 · Low 50.See the feature queue for the inventory and the project-level findings for architectural root-causes. Severity counts are parsed from each draft's finding headers.
Every feature below links to its full audit.
Admin management
Blocker 0 · High 3 · Medium 6 · Low 0
settings-admins is the screen that grants and revokes tenant admin rights, and it is the least defended write surface in the app. Nothing stops an admin from removing or demoting themselves, and nothing counts the remaining admins — a single-admin ten…
Admin registration
Blocker 2 · High 2 · Medium 8 · Low 4
RegisterAdmin.vue is the only route in the app that turns a URL into tenant admin rights, and it is the least finished auth surface in the repo: it decides whether to show a sign-in form by reading auth.currentUser synchronously at mount, which is alway…
Audit log
Blocker 0 · High 2 · Medium 5 · Low 3
The Audit view is 56 lines and renders correctly, and its action vocabulary is genuinely well built — a closed AuditActionSchema enum, a documented legacy-prose fallback in useAuditActionLabel, and **all 20 action labels fully translated in en/fr/`n…
Bible overlay
Blocker 1 · High 4 · Medium 7 · Low 2
The Bible overlay is the operator's live control surface for what an audience sees on the broadcast screen: every write to the bible module document is rendered verbatim by BibleFullscreen on the live-screen route (`src/components/output/ScreenCompone…
Custom overlay components
Blocker 1 · High 4 · Medium 8 · Low 3
The custom-overlay editor is one of the most carefully built views in the repo — auto-save is debounced and diffed, the off-stage warning, the checkerboard preview and the "live preview mirrors air" wiring are all thoughtful, and the comments show the failu…
Custom songs
Blocker 0 · High 3 · Medium 8 · Low 2
#415 is genuinely fixed — I traced create and edit end to end (handleSave → songs.add/songs.update → validateDoc → stripUndefined → addDoc/setDoc, with the dialog now closing only on success) and both paths are sound; there is no Blocker. …
Error and empty states
Blocker 0 · High 2 · Medium 4 · Low 2
playout is one of only two projects in the programme with a catch-all 404, so this feature is the intended reference implementation — but measured against MSG-03/MSG-04 it is a template without an action. ErrorHero.vue renders a code, a title and a se…
Event dashboard
Blocker 0 · High 3 · Medium 6 · Low 4
The event dashboard is a well-composed operational overview — event identity, live status, "Now on air" drill-downs, recent activity and the playlist all read clearly, and the destructive paths (off air, delete) are gated by a confirm dialog. The problems a…
Event list
Blocker 0 · High 4 · Medium 5 · Low 1
The event list is the landing surface after sign-in, and it is the least localised screen in a repo whose CI enforces locale parity: the primary action button, all six tab labels, three of four status badges, the month names and the weekday header are hardc…
Keyboard shortcuts
Blocker 0 · High 2 · Medium 7 · Low 1
The screen is well-built for a first cut: capture is scoped to an explicit "listening" state, the window listener is registered through useEventListener so it is torn down on unmount (unlike the Mousetrap binds elsewhere in the app), duplicate keys are …
Lower third overlay
Blocker 0 · High 5 · Medium 5 · Low 2
The lower-third page is the most consequential surface in the app — every button here changes what viewers are seeing right now — and it is built as if nothing could fail. No write is error-handled, the success haptic and the audit-log entry both fire *befo…
Platform admin
Blocker 1 · High 4 · Medium 6 · Low 1
Eight routes (admin, admin-tenant, overview, languages, tickets, mails, syncs, persons) share one shell, one Table, one Confirm and one toast pair, so almost every defect here is common to all eight rather than route-specific. The consol…
Profile
Blocker 0 · High 3 · Medium 10 · Low 2
Profile is the only account-settings surface in playout, and it is where a user links and unlinks sign-in methods. Those are the highest-value writes in the application and they are the least protected ones: linking a new email/password credential needs n…
Queue overlay
Blocker 0 · High 3 · Medium 7 · Low 1
The queue overlay is the operator's live playlist: it selects what goes on air, reorders it by drag, and pushes elements to the program output. Functionally it is in good shape and the recently added "Clear playlist" action (#429) is a model of MSG-05 — it …
Screens
Blocker 1 · High 5 · Medium 7 · Low 4
The admin editor (screens) is well-structured — a real EmptyState, a live preview, a copyable URL — but its destructive paths are unguarded: deleting a screen writes straight to Firestore with no confirmation, and creating or renaming a screen silently …
Sharing links
Blocker 2 · High 4 · Medium 8 · Low 2
The sharing-links feature is the highest-stakes surface audited in playout so far — a link in a URL grants another organisation read access to the source tenant's person data — and it is currently non-functional for its intended recipient. Firestore rul…
Sign in
Blocker 1 · High 2 · Medium 7 · Low 3
Correction to the assignment brief first: none of the password-reset audit's fixes to Login.vue are on develop. They live only on the unmerged branch atlas/issue-436 (PR #437). git log -- src/views/Authentication/Login.vue ends at 82e576ae (#4…
Songs overlay
Blocker 1 · High 3 · Medium 7 · Low 3
The Songs overlay is the operator's live lyric desk: every control in it writes straight to the shared song module document, so it is on air the moment it is clicked. The single most important defect is that **a bare Escape keypress, from anywhere on th…
Streaming
Blocker 0 · High 4 · Medium 11 · Low 3
The on-air machinery is honest: stage is derived in streaming.store.ts from the Firestore live-stage document that Mux webhooks and the poller write, so "Live" is never asserted before the provider says so, and widgetEnabled is read back from the same…
Tenant chooser
Blocker 0 · High 3 · Medium 5 · Low 2
The chooser itself is small and mostly well built: real <button> options with a visible focus ring, generous hit targets, an i18n'd empty state, and a sensible auto-resolve for single-tenant users. Two things are genuinely broken around it. A user with **…
Tenant settings
Blocker 0 · High 4 · Medium 8 · Low 5
The three tenant-settings pages (settings-general, settings-locations, settings-overlay) all sit on one shared composable, useSettingsDirty, and that composable is where the serious defects are: it fires the green "saved" toast unconditionally after…