forked from Qortal/q-blog
216 lines
7.8 KiB
Markdown
216 lines
7.8 KiB
Markdown
# Q-Blog — Project Instructions (1.0 Track)
|
|
|
|
_Generated 2025-08-16 23:37Z_
|
|
|
|
> Default instructions for all Q-Blog chats. Optimize for **correctness, accessibility, collaboration, and a focused writing UX**. Keep answers decisive and artifact-oriented.
|
|
|
|
---
|
|
|
|
## 1) Intent
|
|
|
|
Q-Blog is a modern blogging workspace for **individuals and small teams**. Writers can own **multiple blogs under one Name**, and enable **Shared Blogs** with roles (Owner/Editor/Author). North star: **inclusive, predictable publishing** with a resilient, testable UI.
|
|
|
|
---
|
|
|
|
## 2) Core flows & stable components (props)
|
|
|
|
**Flows:** Read → Draft → Edit → Publish → Manage Blogs → Collaborate.
|
|
|
|
**BlogSwitcher** — select active blog; scopes all lists/forms.
|
|
|
|
```ts
|
|
activeBlog: BlogRef | null
|
|
blogs: BlogSummary[]
|
|
onCreateBlog: () => void
|
|
onSelectBlog: (blog: BlogRef) => void
|
|
disabled?: boolean
|
|
```
|
|
|
|
**PostEditor** — Slate-based editor with autosave and preview.
|
|
|
|
```ts
|
|
mode: 'create' | 'edit'
|
|
blog: BlogRef
|
|
value: EditorState
|
|
onChange: (s: EditorState) => void
|
|
onSaveDraft: (s: EditorState) => Promise<void>
|
|
onPublish: (input: PublishInput) => Promise<void>
|
|
canPublish: boolean
|
|
status: 'idle'|'saving'|'publishing'|'error'|'success'
|
|
```
|
|
|
|
**PostList** — virtualized list scoped to active blog.
|
|
|
|
```ts
|
|
blog: BlogRef
|
|
filters: PostFilters
|
|
onOpenPost: (id: Id) => void
|
|
```
|
|
|
|
**MembersPanel** (shared blogs).
|
|
|
|
```ts
|
|
blog: BlogRef
|
|
members: Membership[]
|
|
onInvite: (name: NameRef, role: Role) => Promise<void>
|
|
onRemove: (name: NameRef) => Promise<void>
|
|
currentUserRole: Role
|
|
```
|
|
|
|
**Header/Nav** — global actions.
|
|
|
|
```ts
|
|
onOpenMembers?: () => void
|
|
onCreatePost: () => void
|
|
onSwitchBlog: () => void
|
|
unreadCount?: number
|
|
```
|
|
|
|
**Stable props** change only via coordinated refactor with tests & docs.
|
|
|
|
---
|
|
|
|
## 3) Tech & repo posture
|
|
|
|
React 18 + TypeScript (strict) + Vite; **MUI v5**; Slate editor; **Redux Toolkit + RTK Query**; i18next (strings).
|
|
Testing: **Vitest + RTL + user-event + MSW + jest-axe**.
|
|
Config parity across dev/test/build (aliases, JSX, TS). Alias: **@ → src**. Layout: `src/`, `tests/`, `docs/`, `.gitea/`.
|
|
|
|
---
|
|
|
|
## 4) Behavior contracts
|
|
|
|
**Blog scoping & routing**
|
|
|
|
- Every view is scoped to **active blog**. Route params encode scope (conceptually `/{name}/{blog}/...`). Changing blog updates lists/forms without leaks.
|
|
|
|
**Editor & autosave**
|
|
|
|
- Debounced autosave writes drafts with **polite live region** announcements. Clear “Last saved” time; explicit **Publish** pathway. Toolbar enable/disable is deterministic from selection.
|
|
|
|
**Post lifecycle**
|
|
|
|
- States: `draft | scheduled | published | archived`. Idempotent publish; show attribution (`createdBy`, `updatedBy`, `updatedAt`).
|
|
|
|
**Media**
|
|
|
|
- Client validates type/size; shows upload progress; failed uploads are retryable; all `<img>` have alt (or `alt=""` if decorative).
|
|
|
|
---
|
|
|
|
## 5) Accessibility (A11y)
|
|
|
|
- Landmarks: header/nav/main/footer; **Skip link** focuses main. One H1 per route.
|
|
- Keyboard: all controls reachable; **Esc closes** dialogs/popovers and **restores focus**.
|
|
- Names/roles/states: explicit labels; toggles expose `aria-pressed`.
|
|
- Live regions: succinct progress for save/publish/upload; no spam.
|
|
- Preferences: honor `prefers-reduced-motion`; enforce contrast tokens.
|
|
- Tests: axe checks for key pages; keyboard journey tests for protected flows.
|
|
|
|
---
|
|
|
|
## 6) Data, permissions & contracts
|
|
|
|
- **Entities**: Name 1..N Blog; Post 1..1 Blog (immutable link). (`nameId`,`blogHandle`) unique.
|
|
- **Roles**: Owner (all), Editor (edit any, manage drafts), Author (own posts). Deny by default.
|
|
- **RTK Query** is the only remote path; queries/mutations define cache keys by blog.
|
|
- **Validation**: Prefer **Zod** for forms & responses (or JSON Schema + AJV if aligning w/ Q-Chess); failed validation → friendly error with retry path.
|
|
- **Concurrency**: optimistic where safe; use revision/ETag to detect conflicts; show resolve UI on 409.
|
|
|
|
---
|
|
|
|
## 7) Testing standards
|
|
|
|
- Register matchers once in `tests/setup.ts`. Use **accessible queries** (`getByRole`, `getByLabelText`).
|
|
- Unit: selectors, reducers, guards (`can()`), formatters, sanitizers.
|
|
- Component: editor toolbar & autosave, blog switch scoping, lists (virtualized), dialogs focus.
|
|
- A11y: axe smoke on read/draft/manage; keyboard-only journeys.
|
|
- MSW: success + error + invalid payload paths. Deterministic tests; fake timers for debounce.
|
|
- Coverage gate per package; exclude fixtures/build artifacts.
|
|
|
|
---
|
|
|
|
## 8) Performance & resilience
|
|
|
|
- Virtualize long lists; memoize high-churn components.
|
|
- Abortable fetch with timeouts; retry/backoff for GETs; idempotency keys for create/update.
|
|
- Perceived speed: skeletons & optimistic UI (draft saves); defer non-critical work to idle.
|
|
- Offline-friendly drafts: queued writes with clear status and conflict handling.
|
|
|
|
---
|
|
|
|
## 9) TypeScript posture
|
|
|
|
Strict mode, zero `any` in public props; no `@ts-nocheck`. Prefer discriminated unions for async/status shapes. Treat red squiggles as **must fix** before PR.
|
|
|
|
---
|
|
|
|
## 10) Security & content safety
|
|
|
|
- Sanitize editor output **on save and render** (DOMPurify allowlist). Never render untrusted HTML directly.
|
|
- Validate inputs at boundaries; never trust client-visible state for authorization (server checks required).
|
|
- Error boundaries: route-level and editor-level with friendly fallback + “copy details” action.
|
|
- Minimal telemetry for quality (crashes, vitals); no PII.
|
|
|
|
---
|
|
|
|
## 11) Internationalization & theming
|
|
|
|
Centralize strings; use Intl for dates/numbers; prep RTL-safe layouts. Theme tokens (color/spacing/typography) audited for WCAG AA; respect `prefers-color-scheme`.
|
|
|
|
---
|
|
|
|
## 12) Docs & decision hygiene
|
|
|
|
Docs live in `docs/`. Keep: **ARCHITECTURE**, **TESTING**, **ACCESSIBILITY**, **SECURITY**, **USER_JOURNEYS**, **GLOSSARY**, **RISKS**, **ROADMAP_DEPENDENCIES**, **DECISIONS/** (short ADRs). Update docs when behavior or contracts change.
|
|
|
|
---
|
|
|
|
## 13) Delivery & workflow (assistants)
|
|
|
|
- Prepare files locally; share **download links** (send full files once edits exceed a few lines). Keep a resendable copy.
|
|
- Prefer thin **vertical slices** (schema→API→state→UI→tests→docs). Include acceptance notes + quick verify.
|
|
- If assumptions are needed, state them briefly and proceed with a concrete artifact.
|
|
|
|
---
|
|
|
|
## 14) Single source of truth (constants)
|
|
|
|
Centralize shared constants and import everywhere: roles, statuses, limits (upload sizes), blog handle rules, debounce durations, routes, a11y labels. **UI, data, and tests** must reference the same values.
|
|
|
|
---
|
|
|
|
## 15) Versioning & releases
|
|
|
|
SemVer with human changelogs; each release includes notes, migration steps, and quick verify. CI gates: typecheck, lint (jsx-a11y), unit/component tests, axe smoke, coverage, build.
|
|
|
|
---
|
|
|
|
## 16) Common error → action
|
|
|
|
- **MUI v4 import fails** → switch to `@mui/material` / `@mui/icons-material`.
|
|
- **Unexpected HTML execution** → sanitize on save+render; add unit tests with known XSS vectors.
|
|
- **Data shape mismatch** → validation failed: show friendly error; log redacted details; fix schema or endpoint.
|
|
- **Keyboard trap** → ensure focus trap + restore; add test.
|
|
- **Leaked posts across blogs** → check scoping (selector/query keys) and route params; add failing test then fix.
|
|
|
|
---
|
|
|
|
## 17) Checklists
|
|
|
|
**Before sending anything**
|
|
|
|
- [ ] No red underlines; strict TS passes.
|
|
- [ ] Vite build + **Vitest green** (unit & component); axe smoke passes (no criticals).
|
|
- [ ] Dev/test/build configs match (aliases, JSX, TS options).
|
|
- [ ] Public props typed; callers match; no `any` in props.
|
|
- [ ] Landmarks + labels; toggles use `aria-pressed`; live regions only when meaningful.
|
|
- [ ] Lists scoped to active blog; routes stable and shareable.
|
|
- [ ] Editor: autosave status visible; publish path explicit; sanitized output.
|
|
|
|
**Thin vertical delivery**
|
|
|
|
- [ ] Code + tests + docs move together.
|
|
- [ ] Include acceptance criteria and quick verification steps.
|
|
- [ ] If any contract changes, add/adjust a short Decision Record.
|