Sequenced sprint plan to take Architecture, Feature Depth, and UX Polish from current grades to A+ across the board. ~22 sprints, ~38 dev-days. Every sprint shippable on its own.
tokens.css — design system tokens, skeleton CSS, offline-dot CSS, reduced-motion respectA2lib/util.js — shared esc / escAttr / fmtDate / fmtPhone / copyToClipboard / haptic / debounce / throttle / toastA1 partiallib/empty-states.js — 13 brand-voice empty-state copies + render helperU6lib/observability.js — Sentry stub (gated on DSN), offline indicator, perf marksA6 + U15components/copy-link.js — <copy-link> web component with copy-confirm animationU14print.css — paper-backup print stylesheet for scorecardF8 partialtsconfig.json — JSDoc type-check setup, no-emit, includes lib/ + components/A3 setupmigrations/006_drop_is_admin.sql — drafted, NOT applied (gated on client-side cutover)A7migrations/007_round_model.sql — drafted, NOT applied (rounds table + scores.round_id backfill)A7vercel.json — security headers (CSP / HSTS / XFO / Referrer-Policy / Permissions-Policy) addedSec §6lib/util.jsmulti-sessionesc(), format constants, date utils) into lib/util.js. Extract repeated UI fragments (toast, modal, skeleton) into components/*.js. Replace inline scripts/styles with linked external assets so files drop from 150KB to ~30KB HTML + cached shared assets.grep -c "function esc" *.html returns 0.tokens.css. Every page imports it. Tournament theming overrides via inline style block injected by tourney-init.js.tokens.css propagates everywhere on next load.lib/. tsconfig.json with checkJs: true, allowJs: true, noEmit: true. GitHub Action runs npx tsc on PR.npx tsc returns zero errors. No build artifacts shipped.lib/*.js. Playwright for end-to-end: creation wizard, score submit, admin grant. GitHub Action runs both.git push origin staging deploys to staging.tourney.greenskeeper.studio.lib/observability.js — gated on window.SENTRY_DSN. Posthog free-tier for funnel tracking on /create. Activate by setting DSN.supabase db push after security cutover + client-code migration to tournament_admins.supabase db diff returns empty between repo + prod.pg_dump to private S3. Monthly restore drill to scratch Supabase project.series + tournaments.series_id FK. Series landing /s/{slug}/ with year tabs. Champions roll up across years./s/bova/ → see Bova 2025 + 2026 + future events.achievements. Postgres triggers auto-award hole-in-one, eagle, double-eagle, birdie streak, comeback win. Profile badges + feed posts auto-fire./t/{slug}/spectate?p={passcode} read-only scoreboard + feed. No auth required./t/{slug}/recap. Recap email to all players.tier-config.js. Starter: 1 tournament, 24 players. Pro: 5 tournaments, 96 players, series, achievements. Club: unlimited. Admin UI shows disabled states + upgrade CTAs.@page styling for paper backup. Print stylesheet shipped — CSV export queued.courses-db.js to courses table. Admin picker on tournament create. Crowdsource course submissions.idle | loading | success | error pattern across all pages. Skeleton CSS already shipped in tokens.css.lib/util.js. Wire it everywhere, replace every alert(). Modal: backdrop blur, focus trap, ESC to close.alert() calls in repo.lib/empty-states.js. Wire tourneyEmpty.render(el, key) into every empty-render branch.haptic() already in lib/util.js. Wire to score submit, hole-in-one notification, tournament end. Toggleable sound effects (off by default).? opens overlay. g r rounds, g p pairings, g d design, n p add player, cmd+s save.<copy-link href="..."> custom element with confirm animation. Drop into every shareable URL site (tournament home, scoreboard, install, recap).body.is-offline class toggled by lib/observability.js; .nav-offline-dot CSS in tokens.css.