Appearance
[UX] tt-time-tracker — Component gallery
Draft from /ux-audit on 2026-07-30 (unattended batch run). Not filed. Repo: Dr-Wade/tt-time-tracker · Branch:
develop@bb3238c· Files reviewed: 4 Patterns: none (internal style guide; covered by baseline)
Summary
/dev (Dev.vue, 506 lines) is an internal PrimeVue component gallery titled « Composants » — buttons, cards, form fields, tags, a stepper, a demo table, all built from hardcoded French demo data. As a design surface it is fine. The real issue is that it ships to production and is reachable by any unauthenticated visitor: the route carries no requiresAuth meta and nothing strips it at build time. It leaks no sensitive data — every value is static placeholder content, there are no API calls, no env vars and no secrets — so this is design-surface exposure, not a data leak. Product-UX rules are assessed leniently here as agreed for a style guide.
Findings
1. Internal component gallery is public and ships to production — Medium · SEC-DEV-SURFACE (proposed)
Where: services/client/src/router/routes.ts:49; component services/client/src/views/Dev.vue; build config services/client/vite.config.tsWhat: The route { path: "/dev", name: "dev", component: Dev } is declared as a top-level sibling of the auth routes with no meta.requiresAuth. The global guard (router/index.ts:23) only enforces auth on routes whose matched chain carries requiresAuth, so /dev resolves for anyone — no login, no role. Dev is imported unconditionally at routes.ts:29 (no import.meta.env.DEV guard), and vite.config.ts has no plugin or conditional that excludes the view or route from the production bundle. Dev.vue also mounts ThemeChooser from primevue-theme-builder (line 458), a design-time theme editor, into the shipped app. I confirmed there is no build-level strip, as the assignment asked. Why it matters: An internal style guide is exposed on the public origin to anyone who guesses /dev. It reveals the component inventory, theming and design direction, and puts a design-tool dependency in the production bundle. No user data, credentials or secrets are exposed — the page is entirely static demo content — so the impact is professional/exposure, not confidentiality; hence Medium, not Blocker (nothing an outsider can act on for data or auth). Fix: Gate the route behind import.meta.env.DEV (register it only in dev), or strip it via a build-time plugin, or at minimum add meta: { requiresAuth: true, requiresAdmin: true }. Preferred: exclude both the import and the route record from the production build so the gallery and primevue-theme-builder never ship.
2. Demo form labels are not programmatically associated — Low · FORM-01
Where: services/client/src/views/Dev.vue:117,125,133,145,153,161,169,178,193,197,201,333,337,341,347,355,363,375,379What: Every field label in the gallery is a bare <label class="…">Texte</label> sibling of its control, with no for/id pairing and no wrapping. Clicking a label does not focus its input, and assistive tech does not associate the two. Why it matters: This is minor on the gallery itself, but a style guide is the reference other views copy; an unassociated-label pattern demonstrated here can propagate. Low because it is an internal reference page, not a product form. Fix: Wrap each control in its <label>, or give inputs ids and labels a matching for. Better: demonstrate the project's Field* wrappers (which should own the association) rather than raw <label> + PrimeVue input pairs.
Unverified
- A11Y-01 (contrast). The gallery hardcodes light utilities (
bg-white,text-gray-700,text-gray-400,text-gray-500) yet ships a liveThemeChooserand dark-surface tokens; contrast in either theme needs a rendered page and a contrast tool. Not asserted. - A11Y-06 (short viewport / mobile keyboard). The multi-column grids (
lg:grid-cols-2,grid-cols-3) need a rendered viewport to judge. Not asserted.
Baseline additions
SEC-DEV-SURFACE(proposed): Internal-only surfaces (component galleries, style guides, debug/dev tools) must not be reachable in a production build — gate byimport.meta.env.DEVor strip at build time; an unauthenticated route is not sufficient. Distinct from the SEC-01..05 auth-flow rules, which do not cover dev-surface exposure. (Orchestrator to renumber.)
Cross-project note
Worth a one-line check in the other three: does any of playout, customer-portal or members ship a /dev, /styleguide, /components or Storybook-style route into production without a build-time strip? Same shape, same fix. CONTENT-01: not-applicable — see project-level i18n finding (tt-time-tracker has no i18n layer by design). No PROJECT-LEVEL.md finding applies to this feature (no money path, no list/error surface, no auth flow here).