**TL;DR:** Below is a phase-by-phase implementation guide: what libraries we’ll use, what kinds of tests we’ll write, what contracts/functions we’ll define, and how we’ll validate each step. Still high-level—no filenames or code dropped—yet detailed enough to steer day-to-day work. --- # Q-Blog → 1.0.0 Implementation Plan (Technical, High-Level) ## Phase 0 — Orientation & Quality Bar **Libraries / tools** - Issue labels & PR templates (tracker-native). - Metrics: Web Vitals (`web-vitals`), synthetic a11y checks (`axe-core` via CI). **Artifacts** - **Quality charter**: SLOs (e.g., “save post success ≥ 99.9%”), accessibility bar (keyboard-only paths pass), perf budgets (LCP/INP). - **Protected journeys** list: _read post, create post, edit post, manage blogs_. **Validation** - Signed-off charter; journeys ratified in a short doc. --- ## Phase 1 — Project Docs & Working Agreements **Libraries / tools** - Diagrams as code (Mermaid in docs renderer). - Conventional commits (tooling optional). **Artifacts** - **Architecture map** (UI ↔ state ↔ API), **Testing pyramid**, **A11y standard**, **Contributing rules**, **Changelog categories**. - **Decision Record template** (context → options → decision → impact). **Validation** - New contributor dry run: “can run + test + understand contracts in <30 min.” --- ## Phase 2 — Test Harness & Linting Baseline **Libraries** - Unit/Component: **Vitest**, **@testing-library/react**, **@testing-library/user-event**, **@testing-library/jest-dom**. - A11y lint/checks: **eslint-plugin-jsx-a11y**, **axe-core** or **jest-axe**. - Mocking: **MSW** (Mock Service Worker) for API. - Types: TypeScript strict mode. - Lint/format: **eslint** (flat config), **@typescript-eslint** plugin, **prettier**. **Key setup** - Global test setup (RTL matchers, MSW server, clock/timers). - Coverage thresholds (e.g., 80/70/70 lines/branches/functions to start). - CI lanes: install/cache → typecheck → lint → unit/component → (later) e2e smoke. **Tests to seed** - Smoke renders: home, post list, editor screen. - Tiny interaction: typing in editor, enabling/disabling toolbar control, save button disabled until valid. **Validation** - Green **typecheck + lint + tests** on clean checkout; coverage reports generated. --- ## Phase 3 — Correctness Sweep **Libraries** - RTK ecosystem: **@reduxjs/toolkit** (already present), **RTK Query** for data-fetching (adds caching, retries, invalidation). - Schema/runtime validation: **Zod** (form/io validation) **and** `zod-to-json-schema` for docs **or** **AJV** if we align with JSON Schema like Q-Chess. (Pick one; see “Contracts” below.) **Contracts / functions** - **Fetch layer** with cancellation & retries: - `fetchJson(req: Request, opts): Promise>` - `withTimeout(controller, ms): AbortSignal` - **Async state convention**: `{ status: 'idle'|'loading'|'success'|'error', data?, error? }`. - **Error object**: `{ code: string; message: string; recoverable: boolean }`. - **Validation**: - For Zod: `const PostDto = z.object({ id: z.string(), ... })` → `parse(response)`. - For AJV: compile JSON Schemas once; validate per response. **Work items** - Remove legacy UI imports (v4 → v5), delete `ts-nocheck` sections by adding minimal types. - Replace `any` in reducers/selectors and editor props with discriminated unions & precise payloads. - Normalize empty/loading/error states for all remote views. **Tests** - Contract tests: MSW returns both **valid** and **invalid** payloads → validation errors surface as user-friendly messages. - Reducer tests: transitions for each thunk/query state. **Validation** - No suppressed type regions; “known issues” list empty; core routes never hard-crash on bad data. --- ## Phase 4 — Accessibility Baseline **Libraries** - A11y testing: **jest-axe** or **axe-core** integration; **testing-library** queries by role/name. - Focus management: rely on MUI’s **Dialog/Popover** focus traps; add **focus-trap** only where needed. **Contracts / behaviors** - **Landmarks**: header/nav/main/footer; **Skip link** available and visible on focus. - **Focus policy**: focus moves to first interactive element on open; returns to invoker on close. - **Names/roles/states**: toggles expose `aria-pressed`; inputs have programmatic labels; errors are linked with `aria-describedby`. - **Live regions**: polite updates for “saving…/uploaded/failed”. - **Motion/contrast**: respect `prefers-reduced-motion`; enforce contrast tokens. **Tests** - Keyboard paths for protected journeys (Tab/Shift+Tab order, Escape close). - axe checks for key pages (no critical violations). - Live region announces long-running operations (assertions via `toHaveAccessibleDescription` or role queries). **Validation** - Keyboard-only success across protected journeys; automated checks pass with zero criticals. --- ## Phase 5 — UX & IA Touch-up **Libraries** - Router (current choice): ensure route guards & prefetch hooks supported. - Toasts/banners: lightweight (e.g., notistack or MUI Snackbar pattern). **Contracts / functions** - **Design tokens**: spacing, radius, typography, color roles (text, surface, brand) centralized. - **Common UI patterns**: - Empty state contract: `{ icon?, title, body, primaryAction?, secondaryAction? }` - Error surface: banner + inline guidance; all errors have recovery action. - **Editor ergonomics**: - Toolbar state machine: `computeToolbarState({ selection, schema }) → { boldEnabled, … }` - Draft lifecycle: `autosaveDraft(postId, content) → { savedAt }` with debounce and “last saved” indicator. **Tests** - Token snapshots for theme roles; editor toolbar enable/disable based on selection. - Error/empty states render consistently across pages (table-driven tests). **Validation** - Navigation clarity (first-click discoverability); zero dead ends; consistent affordances. --- ## Phase 6 — Multiple Blogs per Name **Libraries** - State & data: continue **RTK Query** (cache per blog key). - Validation: same as Phase 3 (Zod/AJV). **Domain model** - **Name** (account) 1..N **Blog**; **Post** 1..1 **Blog** (immutable relationship post-creation). - **Identifiers**: - Blog handle: lowercase, slug rules; unique per **Name**; stored canonical form. - URL composition: `/{name}/{blogHandle}/…` (conceptual, router-agnostic). **Functions / contracts** - `listBlogs(name): Promise` - `createBlog(input: { handle; title; visibility }): Promise` - `switchBlog(handle): void` (updates app-scoped “current blog”) - `listPosts(blogId, filters)`, `createPost(blogId, input)` - **Migration**: `backfillDefaultBlogs(): MigrationResult` (idempotent: skip if blog exists) **Tests** - Migration test with legacy dataset → posts appear under default blog. - Router/selector scoping: when switching blogs, lists & counts update without leaking data. - Handle validation: rejects collisions & invalid slugs; normalizes input. **Validation** - Users can create/switch blogs; all lists/summaries are scoped; legacy users retained seamlessly. --- ## Phase 7 — Shared Blogs (Collaboration) **Libraries** - Role/permission helpers: in-house constants; optional **casl** if we want DSL-like permissions (not required). **Role model** - **Owner**, **Editor**, **Author**, **Viewer** (implicit). - Operation matrix: - Owner: all - Editor: edit any post, manage drafts - Author: CRUD own posts **Functions / contracts** - Membership: - `inviteMember(blogId, name, role): InviteToken` - `acceptInvite(token): Membership` - `removeMember(blogId, name): void` - `listMembers(blogId): Membership[]` - Authorization guard: - `can(op: 'create'|'edit'|'publish'|'manageMembers', ctx: { user, blog, post? }): boolean` - Attribution: - Post metadata: `{ createdBy, updatedBy, updatedAt, revision }` - Concurrency: - `savePost(postId, input, { ifMatchRevision }): { revision }` → 409 on stale; client shows resolve UI. **Tests** - Permission matrix table tests (unit): each role × operation result. - API guard tests via MSW: simulate forbidden responses, assert UI disables and surfaces denial. - Concurrency tests: stale write attempt returns conflict → user offered resolve path. **Validation** - Owner can manage access; editors/authors can work within role; no unauthorized writes pass. --- ## Milestone Updates - v0.1.x — Multiblog foundations and quality baselines delivered. - v0.2.0 — Wiki Mode canonical selection shipped (owner/whitelist/blacklist; canonical dedupe across Names in feed, favorites, subscriptions, and post view). Settings cache added for efficient owner/settings resolution. ## Phase 8 — Performance & Resilience **Libraries** - **react-virtuoso** or equivalent (already used) for long lists. - Data layer retries/backoff: **RTK Query**’s retry plugin or custom wrapper. - RUM metrics: **web-vitals** + lightweight sender. **Functions / policies** - **Optimistic updates** where safe (draft save, title edits) with rollback on failure. - **Retry policy**: GETs exponential backoff; POST/PUT guarded by idempotency keys where applicable. - **Abortable fetch**: timeouts and user-initiated cancel for uploads. - **Prefetching**: on-hover/visible prefetch of likely next routes and data keys. **Tests** - Latency injection with MSW to verify spinners/skeletons and cancel/abort behaviors. - Optimistic update rollback test: forced server failure restores previous UI state. **Validation** - Subjective feel: interactions seem instant; objective: Web Vitals within budget; error paths recover without data loss. --- ## Phase 9 — Internationalization & Theming Consistency **Libraries** - **react-i18next** (already used in sister projects). - Intl APIs for date/number/plural; fallback polyfills if needed. **Functions / contracts** - `t('namespace:key', { vars })` usage with explicit, descriptive keys. - Currency/number/date formatters as wrapper utilities to standardize formatting. - Theme tokens as a single source of truth; contrast checks (scripted) against WCAG AA. **Tests** - Snapshot tests for key screens in both light/dark with token diffs. - Formatting tests for pluralization and number/date locales. **Validation** - Strings externalized; theme passes automated contrast check; RTL-safety spot check on core screens. --- ## Phase 10 — Observability, Security & Release Readiness **Libraries** - Error tracking: **Sentry** (or equivalent) with source maps. - Sanitization: **DOMPurify** for any HTML serialization/render of editor output. - CSP guidance (server-side; document the policy). **Functions / policies** - **Error boundaries**: route-level and editor-level with friendly fallback and “copy details”. - **Client logging**: `logClientError({ code, message, context })` throttle; opt-in breadcrumbs (sanitized, no PII). - **Security checks**: - Validate all inputs client-side with Zod/AJV before sending. - Sanitize rich text on ingest and display; allowlist for marks/nodes. - Permission checks every write path; never trust client-side hide/disable alone. - **Migrations**: - Versioned, idempotent; dry-run flag; record migration status. - **Release discipline**: - Version bump + changelog; migration notes; upgrade guide; go/no-go checklist (green gates + budgets met). **Tests** - Error boundary renders fallback on thrown child component; telemetry is called with redacted payload. - XSS tests: paste malicious payload → sanitized output (no script execution) both save and render paths. - Migration dry-run/effects tests with sample datasets. **Validation** - Crashes captured with actionable context; no stored XSS vectors; release checklist green. --- ## Cross-Cutting Standards **Contracts-first** - Pick **Zod** _(form/input + client response validation, type inference)_ or **JSON Schema + AJV** _(cross-project parity with Q-Chess)_. - If Zod: generate JSON Schema for docs via `zod-to-json-schema`. - If AJV: generate TypeScript types via `json-schema-to-ts`. - Maintain a single **roles/status/constants** module imported across UI, data, and tests. **Data access layer** - Prefer **RTK Query** for cache, memoized selectors, retries, and invalidation; treat queries/mutations as the one path to remote state. **State shaping** - Store UI state distinct from server cache; selectors derive view models (small pure functions, unit-tested). **Security posture** - Default-deny in permission checks; treat editor input as untrusted; output sanitize on every render path. **Testing pyramid (target distributions)** - Unit (\~60%): pure utils, selectors, reducers, permission guards. - Component (\~30%): screens/components with RTL (+ axe). - Integration/E2E (\~10%): happy-path create/edit/publish; blog switch; invite/accept. **CI** - Node LTS matrix (current + previous). - Caching for package manager. - Artifacts: coverage report, axe report, Web Vitals synthetic (if applicable), build output for preview. --- ## Example Function Signatures (illustrative, no filenames) ```ts // Networking & validation type Result = | { ok: true; data: T } | { ok: false; error: { code: string; message: string; recoverable: boolean } }; function fetchJson( input: RequestInfo, init?: RequestInit & { timeoutMs?: number }, ): Promise>; // Permissions type Role = 'owner' | 'editor' | 'author'; function can( op: 'create' | 'edit' | 'publish' | 'manageMembers', ctx: { role: Role; userId: string; postOwnerId?: string }, ): boolean; // Blog management function createBlog(input: { handle: string; title: string; visibility: 'public' | 'private'; }): Promise>; function inviteMember(blogId: string, name: string, role: Role): Promise>; function savePost( postId: string, input: PostInput, opts: { ifMatchRevision: number }, ): Promise>; ``` --- ## Completion Bars (what “done” looks like per category) - **Correctness:** zero suppressed type regions; known issues = empty; core flows never hard-crash. - **Testability:** green typecheck/lint/tests on clean checkout; coverage trend up and stable; fast local watch. - **Accessibility:** keyboard-only paths pass; axe shows no criticals; live region & focus rules verified. - **Usability:** consistent patterns for empty/error; editor ergonomics predictable; no dead ends. - **Security:** sanitized rich text; permission matrix enforced server- and client-side; no privilege escalation paths. - **Performance:** web vitals within budget; optimistic updates/abortable fetches; graceful failure/retry. --- **Assumptions & Risks:** We can evolve API contracts to support multi-blog and roles; legacy data maps cleanly to default blogs; Slate output can be sanitized without losing required formatting; e2e scope remains minimal to avoid CI flake—expand only if signals require it.