Convention: Aykhan drives every task. The "Commit author" column records which team member's identity the resulting commits are attributed to, not who does the work. Effort tags (S/M/L/XL) reflect approximate session time, not external workload distribution.
- Phase 4 status: complete. Seed script and initial Prisma migration merged to
dev. - Phase 5 status: complete (M1-M8 all on
dev). - Phase 6 status: M1 ✓ (PR #28), M2 ✓ (PR #29), M3 ✓ (PR #30), M4 ✓ (
98ad518), M5 ✓ (PR #32,6ce01b3), M6 ✓ (PR #33,b9f3858), M7 ✓ (PR #34,871dd49), M8 ✓ (PR #35,ae9309f), M9 ✓ (state vocabulary, PR #37), M10 ✓ (PR #38,f16bb46), M11 ✓ (PR #39,ec35ed2), M12 ✓ (PR #40,ea76c55), M13 ✓ (PR #41,a8a49a3). Phase 6 frontend redesign is complete. (Note: redesign is Phase 6; the existing "Deployment and submission" section stays unnumbered.) - Current milestone: none; Phase 6 is complete.
- Last shipped: P6-M13 Accessibility pass. Adds root JSX accessibility lint coverage; fixes heading hierarchy, table semantics, search region wiring, media control labels, heatmap narration, focus rings, and contrast-safe section aliases; records
docs/design/a11y-audit.mdplus the DESIGN.md contrast table. Verification:pnpm format:check,pnpm lint,pnpm typecheck,pnpm test,pnpm build, CI, and local accessibility smoke for signup, login, global search, track preview, playlist create, admin users, landmarks, and keyboard focus all passed. - Last maintenance fix: API CORS now permits the shared CSRF request header, unblocking local browser mutation smoke for playlist/admin flows.
- Last local change: Expired hard-coded Apple artwork sample URLs on the redesigned landing surfaces were replaced with local tokenized decorative cover tiles;
/styleguidecover demos use local data images;apps/web/next.config.mjsnow allowsi.scdn.cofor Spotify artwork. Verification passed:pnpm lint,pnpm --filter @statify/web typecheck,pnpm --filter @statify/web test,pnpm --filter @statify/web build, and local HTTP smoke for/plus/styleguideon port 3001 with no remainingmzstaticsample references. - Previous local UI change: Public
/and authed/melandings are redesigned, and manual light/dark mode is wired through rootdata-theme,statify_themepersistence, and shared theme toggles in public, auth, desktop app, and mobile app chrome. Verification passed:pnpm format:check,pnpm lint,pnpm --filter @statify/web typecheck,pnpm --filter @statify/web test,pnpm --filter @statify/web build, and local HTTP smoke for/,/login, dark-mode/login, and authenticated/meon port 3001. - Previous local change: ADR-003 records Spotify as the album/artist artwork source and iTunes as the preview source;
packages/db/src/scripts/backfill-media.tsnow bulk-fills album and artistimage_urlvalues from Spotify with idempotent skipping, chunked Web API requests, and 429 backoff. A live probe reached Spotify successfully but Spotify returned403 Active premium subscription required for the owner of the app; run again after the Spotify app owner has Premium or swap in credentials from a Premium-owned app. Verification passed:pnpm format:check,pnpm lint,pnpm --filter @statify/db test,pnpm --filter @statify/db typecheck,pnpm --filter @statify/api test, andpnpm --filter @statify/api typecheck. - Last merge (non-milestone): PR #36
chore: add pnpm setup one-shot bootstraprebase-merged intodev2026-05-25 (HEAD3ad5c16). Addspnpm setup+scripts/setup.sh; not a milestone task, so no Phase 6 milestone status changed this session. - Open file/component: none.
- Locked decisions feeding Phase 6:
- Design direction: Vivid Workshop (picked 2026-05-24).
- Entity media field shape: single nullable
image_urlontracks,albums,artists. ADR-003 supersedes the original ADR-002 iTunes artwork-source assumption: Spotify populates album and artist artwork, iTunes only populates track preview metadata, and trackimage_urlremains nullable with UI fallback to album artwork. - Playlist media shape: list/detail DTOs expose
coverImages: string[]derived from the first four member tracks'track.imageUrl ?? album.imageUrl; UI repeats fewer than four to fill the 2x2 collage and falls back to the playlist letter when none exist. Landed in P6-M7. - Form primitives: built on RHF + native control elements (no @radix-ui/react-switch / -select), styled through CSS-variable + state-color tokens; spec lives in DESIGN.md §9. Landed in P6-M8.
- Motion library:
tailwindcss-animate;framer-motionwas not introduced during P6-M12. - Webfonts: self-hosted via
next/font; families locked in P6-M2 DESIGN.md. - Existing UI during Phase 6: destructively replaced as each P6 milestone lands.
- Blocker: none.
- Next concrete action: resume the unnumbered Deployment and submission section; start with production env vars for the web/API hosts, then production smoke.
- Stack chosen (NestJS, Next.js 15, Postgres on Neon, Argon2 + JWT) - S - aykhan
- Constraints, rubric, dataset stance captured - S - aykhan
- ADR-001 drafted - L - aykhan
- ADR-001 approved - S - aykhan
- Open items resolved (dataset subset, repo visibility, no-AI-references, lazy iTunes-derived genres) - S - aykhan
- Create directory tree at
/Users/aykhan/Documents/projects/statify/- S - aykhan - Write
HANDOFF.md- S - aykhan - Write
CHECKLIST.md- S - aykhan - Write
docs/adr/0001-tech-stack-and-foundation.md- L - aykhan - Write
README.md- S - aykhan - Write
CONTRIBUTING.md- S - aykhan - Write
LICENSE(MIT) - S - aykhan - Write
.gitignore,.editorconfig,.nvmrc,.env.example- S - aykhan - Write
scripts/commit-as.shandscripts/.authors, make executable - S - aykhan -
git init, first commit (foundation docs) - S - aykhan - Initialize pnpm workspace:
pnpm-workspace.yaml, rootpackage.json, roottsconfig.base.json- M - elshad - Add Prettier config (
.prettierrc,.prettierignore) - S - elshad - Add ESLint config (root
eslint.config.mjs, shared rules) - M - elshad - Add commitlint config (
commitlint.config.cjs) - S - elshad - Add Husky + lint-staged (
.husky/pre-commit,.husky/commit-msg) - S - elshad - Scaffold
packages/shared: error codes enum, AppError base, Pagination DTO - M - aykhan - Scaffold
packages/db: Prisma init, seed stub, ingest CLI stub directory - L - eljan - Prisma schema commits (the 12 tables from ADR-001 Section 3.2) - L - aykhan
- Scaffold
apps/api(NestJS): ConfigModule, PrismaModule, LoggerModule (Pino), AllExceptionsFilter, ZodValidationPipe, /healthz endpoint - L - eljan - Scaffold
apps/web(Next.js 15 App Router): Tailwind 4, base layout, theme tokens, /healthz route - L - rahila - Add
docker-compose.ymlfor local Postgres + adminer - S - elshad - Add
.github/workflows/ci.yml(typecheck, lint, build) - M - elshad - Add
.github/pull_request_template.mdandCODEOWNERS- S - elshad - Run
pnpm install,pnpm lint,pnpm typecheck,pnpm build; fix any errors - M - aykhan - Push to
https://github.com/aykhan019/statify.git, createdevbranch, set branch protection onmainanddev- S - aykhan - Verify commit attribution on GitHub for all four identities - S - aykhan
- F1: Config and Logging foundation (env Zod schema, Pino, request IDs, Sentry wiring) - M - eljan
- F2: Database layer foundation (PrismaService, base repository pattern, transaction helper) - M - eljan
- F3: Error handling and API envelope foundation (AllExceptionsFilter, error codes, validation pipe wired end-to-end) - M - elshad
- F4: Auth foundation (registration, login, refresh rotation, password hashing, CSRF, JwtAuthGuard, RolesGuard, refresh_tokens table use) - XL - aykhan
- F5: User session on the frontend (server-side session lookup, middleware route guard,
useCurrentUserhook) - L - rahila - F6: Catalog read foundation (TracksRepository, ArtistsRepository, AlbumsRepository, list+detail endpoints with pagination/filter/sort, DTOs in
shared) - L - eljan - F7: iTunes adapter foundation (client, adapter, persistent cache via tracks table, rate limiter, fallback behaviour, integration test against a mock server) - L - elshad
- F8: Listening history foundation (write endpoint with idempotency, repository, schema, indexes) - M - aykhan
- F9: Analytics foundation (the six advanced SQL queries, raw $queryRaw, typed return types, unit tests with seed data) - XL - aykhan
- F10: Frontend design system foundation (theme tokens, base components, layout primitives, navigation shell, audio player component) - L - rahila
- F11: MPD ingestion CLI (parser, normalizer, batched upserts, checkpoint table, resume capability, 10k-playlist dry run) - XL - eljan
- F12: Admin extensibility foundation (audit log writer, admin module skeleton, RolesGuard usage, no UI yet) - M - aykhan
Each milestone is one PR into dev. Per-task commits are attributed via the "Commit author" column. A milestone is ticked [x] only when every row underneath it is ticked.
-
M1: Authentication UI - 5/5
- Signup form + validation + success state - M - aykhan (depends on F4)
- Login form + error states - M - aykhan
- Logout - S - aykhan
- Password change - M - aykhan
- Account deletion (soft delete, audit logged) - M - aykhan
-
M2: Catalog browsing - 4/5
- Tracks list page with infinite scroll - M - rahila (depends on F6, F10)
- Track detail page with preview player, artist + album links - M - rahila
- Artists list and detail with discography - M - rahila
- Albums list and detail with track list - M - rahila
- Genres list and detail (post-genre derivation; waits for later iTunes-derived genre data) - M - rahila
-
M3: Audio player + listening history - 6/6
- Audio player UI (play, pause, scrub, volume) - L - rahila (depends on F7, F10)
- Auto-fetch preview on play if not cached - S - rahila (depends on F7)
- Graceful "preview unavailable" state - S - rahila
- "Play" event fires from audio player to backend - S - aykhan (depends on F8)
- Recent listens page with infinite scroll - M - aykhan
- Per-track play count on detail pages - S - aykhan
-
M4: Indexes + search/filter - 3/3
- Global search bar with debounce, multi-entity results - L - eljan (depends on pg_trgm indexes)
- Filter UI: duration range and preview availability - M - rahila (genre/year waits for later iTunes-derived data)
- Sort controls on every list - S - rahila
-
M5: Personal stats and analytics views - 8/8
- Top artists page (advanced query #1 wired into UI with Recharts) - L - aykhan
- Top tracks page (variant of #1) - M - aykhan
- Discover page (#2) - L - aykhan
- Listening heatmap (#3) - M - aykhan
- Trending artists (#4) - M - eljan
- MPD playlist browsing (list + detail endpoints and /catalog/playlists pages, prereq for #5) - M - eljan
- Similar playlists (#5) - M - eljan
- Hidden gems (#6) - M - eljan
-
M6: Playlist creation and management - 4/4
- Create user playlist - M - elshad
- Add/remove tracks, reorder (drag-drop) - L - elshad
- Public vs private toggle - S - elshad
- Browse other users' public playlists - M - elshad
-
M7: Admin / data management - 4/4
- Admin login route + role gate - S - aykhan (depends on F12)
- Users list with search, ban/unban, role change (audit logged) - M - aykhan
- Ingestion run trigger from admin UI - M - eljan
- Audit log viewer - M - aykhan
-
M8: Rubric / quality demands - 6/6
- ERD diagram (dbdiagram.io DBML export + PNG in
docs/) - S - aykhan - Relational model write-up in
report/erd-explanation.md- M - aykhan - Advanced SQL queries documented in
report/sql-queries.md- M - aykhan - Seed script that produces meaningful number of tuples reliably - M - eljan
- Final report - L - aykhan
- Demo script - M - aykhan
- ERD diagram (dbdiagram.io DBML export + PNG in
The Phase 5 frontend works against the API but was built against the prior visual posture: single-hue accent on grayscale, no semantic token layer, no real entity imagery, no shared icon vocabulary. Phase 6 replaces that posture wholesale against a fully tokenized, multi-hue, identity-bearing system. Component-level work does not begin until M3 has shipped the token layer.
Milestones must ship in order. Each milestone is a single PR into dev on a feat/p6-m<n>-<slug> branch, per-task commits attributed via the "Commit author" column, merged with gh pr merge <n> --rebase --delete-branch.
Existing (app)/** components are destructively replaced as each Phase 6 milestone lands; the dev branch will show visual inconsistency between merged and unmerged surfaces during Phase 6. This is accepted.
-
P6-M1: Design Direction Exploration - S - aykhan
- Goal: produce reference notes for five apps and three Statify direction proposals; surface a single pick.
- Entry criteria: HANDOFF + CHECKLIST + ADR-001 read; design intent confirmed; roadmap approved.
- Exit criteria:
docs/design/explorations.mdcommitted containing Step A (Linear, Vercel dashboard, Stripe dashboard, PostHog, Resend reference notes, 2-3 lines each covering typography character, color treatment, spacing density, separation strategy, vibe phrase) and Step B (three distinct named directions, each with feel paragraph, closest reference, sharpest tradeoff, imagery treatment, iconography treatment); Aykhan has picked one direction and the pick is recorded in HANDOFF.md Section 2. - Files and folders touched:
docs/design/explorations.md(new),HANDOFF.md(decision recorded),CHECKLIST.md(this row ticked). - Depends on: none.
-
P6-M2: Author DESIGN.md from locked direction - M - aykhan
- Goal: turn the locked direction into a complete token specification document at repo root.
- Entry criteria: P6-M1 merged; direction picked.
- Exit criteria:
DESIGN.mdcommitted at repo root specifying full color token set in oklch (semantic naming layer over raw palette, including data-viz palette of at least eight hues), type scale (font families with weight axis, size scale, line-height pairs, letter-spacing per role), spacing scale, radius scale, shadow scale, motion tokens (durations, easings, named transitions, all driven throughtailwindcss-animateutilities), image aspect ratio scale with frame and overlay treatments and explicit fallback strategy when media fields are NULL, icon size scale with locked stroke weight and role mapping (inline / navigation / feature), and a one-screen "do / do not" section calling out the hard constraints from the design intent. ADR-002 drafted to record the deviation from ADR-001 §3.8 / §3.20 and the lockedimage_urlschema decision. - Files and folders touched:
DESIGN.md(new),docs/adr/0002-design-system-and-token-layer.md(new),HANDOFF.md(Structural Changes Log row, Documents Map updated). - Depends on: P6-M1.
-
P6-M3: Token layer implementation + dependency install +
/styleguideroute - L - rahila- Goal: encode every DESIGN.md token in CSS variables and the Tailwind 4
@themeblock, install Lucide + shadcn/ui + Radix primitives +tailwindcss-animate, and ship a/styleguideroute that renders every token visually for QA. - Entry criteria: P6-M2 merged; DESIGN.md tokens locked.
- Exit criteria:
apps/web/src/app/globals.cssrewritten so every color, font, radius, spacing step, shadow, motion duration, easing, aspect ratio, and icon size exists as a CSS variable inside@theme;lucide-react,@radix-ui/*, shadcn/ui generator config,tailwindcss-animate, and the chosen self-hosted webfonts vianext/fontadded toapps/web/package.jsonwith the locked stroke weight enforced via a thin<Icon>wrapper;/styleguideroute atapps/web/src/app/styleguide/page.tsxrenders the color palette (raw + semantic), type scale (every role at every weight), spacing scale, radius scale, shadow scale, motion samples, image frame treatments at every aspect ratio (with a NULL-media fallback example wired to the real fallback), and the entire in-use icon set at all locked sizes;pnpm lint,pnpm typecheck,pnpm buildpass; manual QA on/styleguideconfirms every token is visible. - Files and folders touched:
apps/web/src/app/globals.css,apps/web/src/app/styleguide/page.tsx(new),apps/web/src/components/ui/(Icon wrapper, base shadcn primitives copied in),apps/web/src/lib/fonts.ts(new),apps/web/package.json,apps/web/components.json(shadcn config, new),HANDOFF.md(Structural Changes Log rows for each dep). - Depends on: P6-M2.
- Goal: encode every DESIGN.md token in CSS variables and the Tailwind 4
-
P6-M4: Media foundation (schema, adapter persistence, backfill) - L - aykhan
- Goal: make real entity imagery available from the Prisma layer so later surfaces can render
<Image>against live URLs per the design intent. - Entry criteria: P6-M3 merged; DESIGN.md aspect ratio scale locked; ADR-002 records the
image_url-column decision. - Exit criteria: Prisma migration adds
image_url(text, nullable) totracks,albums,artists; iTunes adapter atapps/api/src/integrations/itunes/persists the artwork URL on resolve alongside the existingpreview_urlwrite (using the100x100bb.jpg→600x600bb.jpgsubstitution at write time); backfill script atpackages/db/src/scripts/backfill-media.tspopulates existing rows by replaying iTunes lookups for tracks lackingimage_url; albums inherit from the first ingested track's image; artistimage_urlstays null and the UI uses the DESIGN.md null-fallback; DTOs inpackages/sharedexposingimageUrlon the relevant entities;apps/web/next.config.mjsimage domain allowlist updated foris*-ssl.mzstatic.com; unit tests for adapter persistence and backfill idempotency;pnpm --filter @statify/db prisma migrate dev,pnpm --filter @statify/api test,pnpm typecheck,pnpm buildpass; HANDOFF Structural Changes Log row added. - Files and folders touched:
packages/db/prisma/schema.prisma,packages/db/prisma/migrations/<timestamp>_entity_media/,packages/db/src/scripts/backfill-media.ts(new),apps/api/src/integrations/itunes/itunes.adapter.ts,apps/api/src/integrations/itunes/itunes.cache.ts,apps/api/src/modules/catalog/**(DTO surface),packages/shared/src/dto/**,apps/web/next.config.mjs,docs/adr/0002-design-system-and-token-layer.md(schema decision section). - Depends on: P6-M3.
- Goal: make real entity imagery available from the Prisma layer so later surfaces can render
-
P6-M5: Layout primitives + app shell rewrite - M - rahila
- Goal: replace ad-hoc layout JSX with token-bound primitives (Container, Stack, Grid, Section, Surface, Divider, Spacer) and rebuild the authed shell on top.
- Entry criteria: P6-M3 merged.
- Exit criteria: primitives under
apps/web/src/components/layout/consume only token classes (no hard-coded px, hex, or font-family); existing(app)/layout.tsxre-implemented in terms of the primitives; container widths, gutters, and grid steps documented in DESIGN.md update;/styleguideroute gains a "Primitives" section showing every primitive at every documented variant; lint / typecheck / build pass; manual smoke confirms every existing authed route still renders without layout regressions. - Files and folders touched:
apps/web/src/components/layout/**(new),apps/web/src/app/(app)/layout.tsx,apps/web/src/app/styleguide/page.tsx,DESIGN.md(primitives addendum). - Depends on: P6-M3.
-
P6-M6: Navigation system - L - rahila
- Goal: rebuild top bar, side navigation, mobile navigation, breadcrumbs, and the user menu against the new token layer and the layout primitives.
- Entry criteria: P6-M5 merged.
- Exit criteria: nav components under
apps/web/src/components/navigation/use only Lucide icons at the locked nav size and the semantic color tokens; active / hover / focus / disabled states defined in DESIGN.md and visible at/styleguide; mobile breakpoint behaviour documented; keyboard navigation through every nav surface verified manually; lint / typecheck / build pass. - Files and folders touched:
apps/web/src/components/navigation/**(new),apps/web/src/app/(app)/layout.tsx(consumes nav),DESIGN.md(nav states addendum),apps/web/src/app/styleguide/page.tsx. - Depends on: P6-M5.
-
P6-M7: Data display with real media (cards, lists, detail pages) - L - rahila
- Goal: rebuild Track, Artist, Album, and Playlist cards / list rows / detail headers to render
<Image>from the Prismaimage_urlfields with the DESIGN.md aspect ratio and frame treatments. - Entry criteria: P6-M4 merged (media in DB) and P6-M6 merged (shell exists).
- Exit criteria: components under
apps/web/src/components/{catalog,playlists}/usenext/imageagainst liveimageUrlfields from the API; aspect ratio, frame, and overlay match the DESIGN.md scale; explicit fallback variant renders when the field is NULL (the DESIGN.md null-fallback, no generic gradients, no placeholders); detail page hero treatments updated for Track / Artist / Album / Playlist; lint / typecheck / build pass; manual smoke on each list and detail route against seeded data confirms real artwork loads. - Files and folders touched:
apps/web/src/components/catalog/**,apps/web/src/components/playlists/**,apps/web/src/app/(app)/catalog/**,apps/web/src/app/(app)/playlists/**, DESIGN.md (any media decisions discovered during build). - Depends on: P6-M4, P6-M6.
- Goal: rebuild Track, Artist, Album, and Playlist cards / list rows / detail headers to render
-
P6-M8: Forms system - M - aykhan
- Goal: rebuild every form (signup, login, password change, account deletion confirmation, playlist create / edit, admin user edit) on a token-bound RHF + Zod primitive set.
- Entry criteria: P6-M3 merged.
- Exit criteria: form primitives under
apps/web/src/components/forms/(Field, Label, Input, Textarea, Select, Checkbox, Switch, FormError, FormHint, SubmitButton) wired to existing shared Zod schemas; error, focus, disabled, and loading states defined in DESIGN.md and visible at/styleguide; each existing form route re-implemented against the primitives; lint / typecheck / build pass; manual smoke of every form route confirms submission and validation paths still work. - Files and folders touched:
apps/web/src/components/forms/**(new),apps/web/src/components/auth/**,apps/web/src/components/playlists/**(form-touching ones),apps/web/src/components/admin/**(form-touching ones),DESIGN.md(form states addendum),apps/web/src/app/styleguide/page.tsx. - Depends on: P6-M3.
-
P6-M9: Empty, loading, and error states pass - M - rahila
- Goal: design and ship a shared vocabulary for empty states, skeleton loaders, error surfaces, and not-found pages on top of every list, detail, and form route built so far.
- Entry criteria: P6-M7 and P6-M8 merged.
- Exit criteria: state primitives under
apps/web/src/components/states/(Skeleton, EmptyState, ErrorState, NotFoundState) consume tokens only; every list and detail route in(app)/**wired to a skeleton during suspense, an empty state when the response is zero-length, an error state when the fetch fails, and a not-found state when the entity is missing; copy and icon choices documented in DESIGN.md; lint / typecheck / build pass; manual smoke triggers each state (throttle network for skeletons, force 404, force 500). - Files and folders touched:
apps/web/src/components/states/**(new), every route file underapps/web/src/app/(app)/**that fetches,DESIGN.md(states addendum). - Depends on: P6-M7, P6-M8.
-
P6-M10: Section identity headers + section-hue propagation - L - rahila
- Goal: apply the locked Vivid Workshop "section-as-color" identity (DESIGN.md §1.3) to every top-level route — a full-bleed section-hue block header on each route, with the section hue propagated to the active nav indicator, row hover, cover frames, and the default chart series. This closes the gap where the §1.3 tokens and per-route hue assignments exist but no route renders the block treatment.
- Entry criteria: P6-M5 (shell) and P6-M6 (nav) merged; section identity hue assignments and the
--color-section-*aliases locked in DESIGN.md §1.3. - Exit criteria: a section provider under
apps/web/src/components/section/resolves the active section from the route prefix per DESIGN.md §1.3 and sets--color-section-block,-block-fg,-tint,-accent,-accent-fg,-row-hover, and-frameon the route subtree; every top-level route renders a full-bleed block header inbg-section-block text-section-on-blockattext-5xlweight 800 per §2.2, with/me/accountkept as neutral chrome (no block) per the §1.3 exception; the active section hue propagates to the active nav / tab indicator, list row hover tint (--color-section-row-hover), the cover frame on every card / list / detail cover inside the section (--color-section-frame), and the default chart series (section hue moved to series index 0 per §1.6); no-section routes (global search, sign-in, error / not-found) resolve to the indigo Library default per §1.3; DESIGN.md gains a section-header / block-treatment addendum (block dimensions, full-bleed behaviour, propagation rules);/styleguidegains a section rendering the block header for all eleven section hues; lint / typecheck / build pass; manual smoke confirms each top-level route shows its block header in the correct hue and the nav indicator / row hover / cover frame match. - Files and folders touched:
apps/web/src/components/section/**(new section provider + block header),apps/web/src/app/(app)/**(per-route headers / layouts),apps/web/src/components/navigation/**(active indicator reads section hue),apps/web/src/components/{catalog,playlists}/**(cover frame reads--color-section-frame),DESIGN.md(section-header addendum),apps/web/src/app/styleguide/page.tsx. - Depends on: P6-M5, P6-M6.
-
P6-M11: Analytics surfaces re-skin (Recharts against tokens) - M - aykhan
- Goal: re-skin every Recharts surface (top artists, top tracks, discover, heatmap, trending, hidden gems) against the locked token palette and motion tokens, including a shared chart wrapper that pulls axis / grid / tooltip / palette from CSS variables.
- Entry criteria: P6-M3 merged; data-viz palette (at least eight hues) defined in DESIGN.md; P6-M10 merged (active section hue available for the series index-0 swap).
- Exit criteria: a single chart theme module at
apps/web/src/components/charts/reads axis, grid, tooltip, and series colors from CSS variables; every existingstats/**page wired through it with no inline hex; heatmap uses a documented multi-stop scale from the DESIGN.md data-viz palette; tooltip and legend treatments documented; lint / typecheck / build pass; manual smoke confirms charts render with the new palette and reflow on resize. - Files and folders touched:
apps/web/src/components/charts/**,apps/web/src/components/stats/**,apps/web/src/app/(app)/me/stats/**,DESIGN.md(data-viz palette addendum). - Depends on: P6-M3, P6-M10.
-
P6-M12: Motion pass - M - rahila
- Goal: apply the DESIGN.md motion tokens across navigation, list mounts, modal / dialog open / close, hover and focus transitions, and player state changes; honour
prefers-reduced-motion.framer-motionmay be introduced here only if a specific surface needs layout / exit animation thattailwindcss-animatecannot deliver; recorded in HANDOFF Structural Changes Log if added. - Entry criteria: P6-M7, P6-M8, P6-M9, P6-M10, P6-M11 merged.
- Exit criteria: every transition in the app references a named motion token (no inline durations, no inline easings);
prefers-reduced-motion: reduceswaps to a no-motion variant globally; motion tokens visible on/styleguidewith side-by-side reduce-motion preview; lint / typecheck / build pass; manual smoke of every authed route confirms transitions feel coherent and no surface flashes. - Files and folders touched:
apps/web/src/components/**(transition wiring),apps/web/src/app/globals.css(reduce-motion override),apps/web/src/app/styleguide/page.tsx. - Depends on: P6-M7, P6-M8, P6-M9, P6-M10, P6-M11.
- Goal: apply the DESIGN.md motion tokens across navigation, list mounts, modal / dialog open / close, hover and focus transitions, and player state changes; honour
-
P6-M13: Accessibility pass - M - aykhan
- Goal: end-to-end a11y audit and fix pass against WCAG 2.2 AA on the redesigned surfaces.
- Entry criteria: P6-M12 merged.
- Exit criteria:
eslint-plugin-jsx-a11yclean; semantic landmarks (header,nav,main,aside,footer) verified on every layout; focus order keyboard-walked through every authed route; visible focus ring (from tokens) confirmed on every interactive element; color contrast checked for every semantic foreground / background pair documented in DESIGN.md and recorded in a contrast table at the bottom of DESIGN.md; screen-reader smoke (VoiceOver) on signup, login, search, track detail with preview play, playlist create, admin user edit; results recorded indocs/design/a11y-audit.md; lint / typecheck / build pass. - Files and folders touched:
apps/web/src/components/**(fixes),apps/web/src/app/**(fixes),DESIGN.md(contrast table),docs/design/a11y-audit.md(new). - Depends on: P6-M12.
- PWA install + offline shell - M
- AZ / RU translations - M
- Google OAuth - M
- Spotify OAuth (if dashboard cooperates) - L
- Track recommendations via simple matrix factorization on
listening_history- XL - Social: follow other users, see their public listens - XL
- Native shell via Capacitor - L
- Public and authed landing page redesign with manual light/dark mode and local decorative cover art - M - rahila
- Generate initial Prisma migration (
prisma migrate dev --name initial); commitpackages/db/prisma/migrations/- S - aykhan - Spotify album and artist artwork backfill script + ADR - M - aykhan
- Production env vars set in Vercel and Render - S - aykhan
- Smoke test against production URLs - S - aykhan
- Demo dataset confirmed on prod DB (10k-playlist subset ingested) - M - eljan
- Warm-up ping verified via cron-job.org - S - elshad
- Report final draft circulated - L - aykhan
- Slides for in-class presentation - M - aykhan
- Final demo dry-run - M - all
- Submit - S - aykhan