ProjectR Docs
Audit 2026-09

Fix Backlog

23 sequenced fix tasks + 5 owner decisions, prepared for the fixing agent. Source: FIX_TASKS.md in the repo.

Canonical source: apps/dashboard/docs/audit-2026-09/FIX_TASKS.md (ground rules, per-task acceptance criteria, file:line links). Summary:

Ground rules for the fixing agent

One task = one branch = one PR, referencing the task ID. Re-verify findings before fixing (line numbers may have drifted; if a finding no longer holds, close the task with a note). Follow apps/dashboard/CLAUDE.md + packages/backend/CLAUDE.md patterns. Backend changes backward-compatible only (mobile shares it); never bump the auth-cluster pins. bun run check-all + bun test; browser-verify user-facing changes via http://localhost:3000 (never 127.0.0.1; smoke a real sign-in).

Decisions needed from the owner (do not invent policy)

#Decision
D1Orders tier: client gate dashboard vs backend requireAdminAccess — which is intended? (F-I4)
D2Ratings sub-pages: nav says admin, gate is dashboard — which is intended? (F-I34)
D3Authorization policy: gate all pages client-side, or officially adopt backend-only enforcement and strip client gates + fictional comments? (F-B2, F-A5)
D4lib/toast.ts: adopt or delete? (F-H4)
D5Rename the live -v2 files (no v1 exists)? (F-H7)

Sprint 0 — correctness & honesty (≈1–2 days, do first)

IDPriTaskFindings
T1P1Hook-layer error contract ({data, error}) + sweep ~35 unchecked result.success sites — the audit's #1 fixF-B8, F-B1, F-F1, + 12 site findings
T2P1error.tsx at /dashboard + route groups; fix eternal-loading not-found; guard deep-link literal castsF-C1, F-I3, F-B5, F-I2-14
T3P1Lock down the two public getCampaignById queries (check mobile callers first)F-I2-1, F-I43
T4P1logAdminAction on the three unlogged destructive familiesF-D1–D4
T5P1Confirmations + in-flight guards on the five unconfirmed destructive opsF-F3/4/5, F-I38, F-I45, F-I2-9
T6P2Safe-delete list + housekeeping (incl. components.json — prereq for T16)F-H1–H9, F-A1, F-G14
T7P2Doc reconciliation (TECH_DEBT, README, CHECKLIST, CLAUDE.md, env docs)F-H10–H12, F-A9
T8P2Install @tailwindcss/typography for tiptap; align sanitizer allowlistF-E3, F-E4

Sprint 1 — authorization & states (≈3–5 days, after D1–D3)

IDPriTaskFindings
T9P1Authorization presentation sweep (37 pages) per D3; align orders/ratings tiers per D1/D2F-B2, F-A5, F-I34, F-I4, F-I42
T10P1isProfileAccessActive on Shopify write paths; kbar role filterF-D5, F-B4
T11P1Ratings: states + working pagination + remove dead controlsF-F2, F-I32, F-I39
T12P2Dead controls & fake surfaces: make real or remove (marketing-campaigns pagination, fake refresh buttons, fabricated KPIs, dead selection UI)F-I44, F-I48/49/50, F-I2-7/13, +
T13P1Perf quick wins: overview remount, orders double-subscribe, memoize transforms, subscribe-on-open (bell/media picker), dynamic rechartsF-G3–G8, F-G12, F-I47
T14P1Backend cost: aggregates migration where the dimension exists; paginate or surface truncation (export warning); bound bulk inputs; kill dead N+1; align export revenueF-D6–D9, D11, D13, D14
T15P2Auth-chain latency: optimistic shell render + stale-while-revalidate role snapshotF-G1, F-G2
T16P2shadcn refresh sequence: button (safe) → card (113-file visual review); never blind-refresh dialog/tableF-E1, F-E2, F-E12

Sprint 2 — structural (as capacity allows)

IDPriTaskFindings
T17P1Token system: add --success/--warning/--info, migrate ~650 raw utilities, ESLint guardrailF-E11
T18P2Component consolidation: one delete-dialog pattern, one table wrapper, two date recipes, split channel-multi-select, move 3 violating ui/ filesF-E5–E9, E13–E15, F-A6, F-A7
T19P2Hook/data-layer restructuring: split use-loyalty.ts, extract vouchers data layer, fix inverted imports, move profile schemasF-A2, F-A3, F-A8, F-A10, F-A11
T20P2UX consistency: unsaved-changes guards (3/12 forms → all + route-level), badge semantics, header pattern, date/currency/toast wording, draft-clearing bugF-F6–F9, F-F15–F19
T21P3Accessibility batch: name ~30 icon buttons, keyboard rows, dialog descriptions, labelsF-F10–F14
T22P3Backend consistency batch: error-key consistency, dual-minting divergences, privilege tiers, v.any() ×55, compose MAX_BULK, onboarding dead-end, pool atomicityF-D10–D18, F-J1–J4, F-I35–I37
T23P3Frontend long tail (work lane-file P3 sections when the queue is empty): CSP/proxy/Sentry hardening (needs an owner decision on strictness), misc polishF-C4/C5/C7/C9, +

Sequencing

T1 → T2 → T3 → T4 → T5 unlock everything (T11/T12 need T1's contract). D1–D5 block T9 and parts of T12/T19. Everything is independently shippable.

On this page