# Release QA Checklist Keep every item unchecked until it has been verified in the named environment. Automated checks are necessary but do not replace browser, assistive-technology, media-lifecycle, or production verification. ## Automated release gate - [ ] Run `npm ci` from a clean dependency state. - [ ] Run `npm audit --audit-level=high`. - [ ] Run `npm run lint`. - [ ] Run `npm run typecheck`. - [ ] Run `npm test`, including registry, scoring, quiz-media, Storage v3, cloud revision, community, journal, governance, password reset, runtime Turnstile configuration, and share suites. - [ ] Run `npm run audit:flagship` and confirm all 16 public assessments meet the ready threshold. - [ ] Run `npm run audit:a11y`. - [ ] Run `npm run build` and `npm run package:standalone`. - [ ] Confirm the standalone artifact contains the application runtime, public assets, `.next/static`, media-worker runtime, and required Linux x64 native addons for both `better-sqlite3` and `sharp`. ## Desktop product flows - [ ] Windows Chrome: home -> assessments -> detail -> quiz -> result completes without layout, focus, network, or console errors. - [ ] Windows Chrome: home -> journal library -> new journal -> upload -> private preview -> publish -> community -> detail completes without layout, focus, network, or console errors. - [ ] Windows Edge: both assessment and image-journal flows complete successfully. - [ ] Windows Firefox: both assessment and image-journal flows complete successfully. - [ ] Light, dark, and system themes remain readable across home, assessments, quiz, result, journal library/editor/detail, community, account, moderation, complaints, settings, and privacy. ## Account recovery - [ ] The sign-in form links to password recovery, and the recovery and reset pages match the account area's layout, language, and theme behavior in both Simplified Chinese and English. - [ ] A recovery request completes Cloudflare Turnstile before submission; without a token the request is blocked client-side and server-side. - [ ] The recovery response is identical for registered and unknown addresses, sends at most one email, and never states whether the address exists. - [ ] The reset email opens the reset page with a valid token; the link expires in 30 minutes and works only once. - [ ] Setting a new password enforces 10 to 128 characters, rejects a mismatched confirmation, and reports success with a sign-in link. - [ ] After a reset, the old password is rejected, the new password signs in, and previously signed-in sessions are revoked. - [ ] Reusing a consumed token or an expired token shows an invalid-link message and changes no password. - [ ] Missing SMTP or Turnstile configuration fails closed with a clear unavailable message instead of exposing the reset form. ## Homepage, routes, and navigation - [ ] `/` renders the unified community feed as the first viewport: shared assessment results, text posts, and image posts with type filters and latest/most-resonant sort. - [ ] The full reviewed catalog is available at `/assessments/`; the homepage feed surfaces shared content, not a catalog listing. - [ ] Header and mobile navigation link to Home, Assessments, History, and Account with correct current-page state; `/` and the `/community/` compatibility route both mark Home as current. - [ ] Guests see a sign-in invitation in the create actions; signed-in verified users see the text composer and a link to their image-post library. - [ ] Empty feed states guide to assessments, history, or the image-post editor according to the active filter. - [ ] `/community/` has one mixed feed with assessment, text, and image filters; switching filters never leaks another item type or changes the selected sort. - [ ] Private routes and `/admin/moderation/` use noindex metadata; public journals are indexable only while published and visible. ## Assessment result imagery - [ ] Animal Personality selects the correct type image, including the mixed result. - [ ] Emotion Regulation selects the unique leading-dimension image and uses the cover fallback for a tie or missing key. - [ ] Attachment Style selects the correct type image, including the mixed result. - [ ] Life Satisfaction selects the correct stable score-band image at every lower/upper boundary. - [ ] Missing media, an unknown result key, and an unsupported assessment render a consistent cover or text-only fallback without affecting score or saved history. - [ ] Pilot catalog cards, detail pages, and result pages use the same asset language and remain coherent in light and dark themes. - [ ] Every bundled assessment visual has the declared intrinsic size and meaningful bilingual alt text; no explanatory text is embedded in the bitmap. - [ ] Anonymous “did this image help?” feedback accepts yes/no once per rendered result state and stores no account id, answers, attempt id, or result copy. ## Journal creation and recovery - [ ] A signed-in but unverified account cannot create a draft, request an upload batch, upload, or publish; verification completion unlocks the flow. - [ ] Create and publish valid journals with exactly 1, 3, and 6 images. - [ ] A missing title, zero images, more than 6 images, or a non-decorative image without alt text cannot publish and receives actionable feedback. - [ ] Optional body, per-image caption, content language, comment toggle, decorative flag, and alt text save and reopen correctly. - [ ] Autosave handles rapid edits without losing the newest revision or overwriting a newer server revision. - [ ] Refresh or close during editing, then return and verify interrupted-session recovery restores words and image order without publishing them. - [ ] Upload progress is visible; processing remains distinct from upload completion; a processing image cannot be published. - [ ] A network-interrupted transfer can retry from the client-held file; a server-side processing failure requires a newly selected replacement because the original was discarded. Neither path creates duplicate visible images or an invalid order slot. - [ ] Drag reordering works as an enhancement; move-up and move-down buttons produce the same persisted order with keyboard only. - [ ] Private preview reflects the latest draft; public preview clearly represents what an explicit publication would expose. ## Media validation and privacy - [ ] Valid static JPEG, PNG, and WebP files are accepted below 8 MiB and 25 MP. - [ ] SVG, GIF, HEIC, animated WebP, remote URL input, corrupt files, MIME spoofing, files over 8 MiB, and images over 25 MP are rejected. - [ ] File names and crafted ids cannot escape `private`, `public`, or `tmp` media roots; path traversal attempts return an error and create no outside file. - [ ] Output variants are WebP at requested 320, 960, and 1600 pixel bounds without upscaling beyond source dimensions. - [ ] Output contains no EXIF, GPS, device, orientation, or original-filename metadata; the original upload is removed after processing. - [ ] Private media requires an authenticated owner request and is not directly served by Caddy. - [ ] Daily 20-upload, daily 3-publication, and 250 MiB total-account quotas persist across process restarts. - [ ] Fixed one-minute API rate-limit windows persist across process restarts, expire automatically, and store only hashed keys rather than raw IP or account identifiers. - [ ] Concurrent upload or publish requests cannot bypass quotas, create more than 6 ordered images, or double-consume one upload batch. - [ ] A claimed processing job recovers after worker interruption, stale leases are reclaimed, and terminal failures expose a retryable failed state. ## Publication lifecycle - [ ] First publication creates a public immutable revision with the account display name and default-enabled comments. - [ ] Editing a published journal changes only the private draft until “Update public version” is explicitly confirmed. - [ ] Updating the public version creates a new immutable revision and does not mutate the previous snapshot in place. - [ ] Unpublishing removes the item from Feed, public detail, direct public media, OG metadata, and sitemap while retaining the private draft. - [ ] Deleting removes the journal from the owner library and public surfaces and schedules all associated private/public media for tombstone-backed cleanup. - [ ] Account deletion removes journal records and interactions, then replays pending media tombstones without restoring deleted files. - [ ] Hidden, unpublished, and deleted content returns a real unavailable/not-found response to non-owners; no cached HTML or direct media URL remains usable from the application origin. ## Community and interactions - [ ] Image-journal Feed cards show only cover, title, author display name, image count, date, and excerpt; full images and interactions appear only on detail. - [ ] Assessment cards appear under the `assessment` filter and never expose raw answers. - [ ] Resonance add/remove, comment creation, one-level reply, owner deletion, and closed-comments behavior work for both supported content types. - [ ] Read-only, suspended, and banned accounts cannot create community writes; upload-blocked accounts can still perform allowed non-upload writes. - [ ] Report dialogs have a name, initial focus, Escape behavior, focus containment, focus return, and recoverable submission feedback. ## Badges - [ ] A signed-in account completing a public assessment sees the earned result badge appear in its profile collection, grouped by assessment family, with matching labels in both UI languages. - [ ] Wearing works by tapping a badge chip, removing by tapping again, and a fourth simultaneous wear is rejected with a clear in-page message and no partial save. - [ ] A variant the account never earned, or a badge from a non-public internal route, is rejected with distinct feedback. - [ ] While the visibility switch stays off, other readers and guests never see worn badges anywhere; after opting in, worn badges appear next to the author name on community posts, comments, and image posts in the viewer's language, linking to the assessment page. - [ ] Guests see a quiet sign-in nudge on the result page instead of any badge UI, with no dialog interrupting the share flow. - [ ] Deleting the underlying attempt through a cloud replace removes the badge from the collection and silently filters the stale worn row on the next read. - [ ] Account deletion cascades to the worn-badge rows. - [ ] A worn badge label equals the label a public share of the same attempt prints, in both Chinese and English. ## Moderation and complaints - [ ] One high-risk report (`illegal`, `minor_sexual`, `nonconsensual_intimate`, `privacy`, or `explicit_harm`) hides the target immediately. - [ ] Three distinct reporters are required to auto-hide an ordinary category; duplicate reports from one account do not increase the threshold. - [ ] An environment-configured administrator can list hidden journal entries, journal comments, assessment shares, and assessment comments. - [ ] Admin restore makes eligible content public again; permanent removal keeps it unavailable and cleans public media where applicable. - [ ] Account states normal, upload-blocked, read-only, suspended, and banned take effect across journal and assessment-community writes. - [ ] Every system/admin hide, restore, removal, account-state change, complaint-state change, and cleanup action appends an audit record. - [ ] `/complaints/` accepts privacy or copyright complaints without authentication, rate-limits abuse, and exposes them in the admin queue without leaking contact details publicly. ## Narrow viewports and zoom - [ ] At 360px, 390px, and 412px widths, home, assessment catalog, editor, vertical journal detail, all community filters, report dialog, and account verification have no horizontal scroll, clipped text, or overlapping controls. - [ ] At those widths, image previews keep stable aspect ratios and processing overlays do not resize surrounding layout. - [ ] At those widths, all primary actions and icon controls remain at least 44 by 44 CSS pixels. - [ ] Mobile navigation identifies the current page and does not cover final content or editor actions. - [ ] Quiz and result routes suppress mobile primary navigation as intended. - [ ] At 200% browser zoom, text reflows, the editor remains operable, modal content remains reachable, and no label or button text is clipped. ## Keyboard and screen reader - [ ] The first Tab reveals the skip link and moves focus to `#main-content` when activated. - [ ] Every interactive control is reachable in a logical order with visible focus, including upload, replacement, ordering, preview, publish, unpublish, delete, reaction, comment, report, and moderation controls. - [ ] Assessment number keys and arrow keys work outside editable controls and do not override browser or dialog interactions. - [ ] Moving between assessment questions focuses the new question heading without stealing focus on initial load. - [ ] Windows Narrator announces one main landmark and a clear page-level heading on every public route. - [ ] Navigation landmarks have localized names and current destination; tabs announce selected state. - [ ] Upload/processing/saved/error/recovery messages are announced once, without duplicate speech. - [ ] Decorative assessment and journal images are absent from the accessibility tree; meaningful user images announce authored alt text. - [ ] Heading hierarchy remains logical across results, editor previews, public journals, moderation, privacy, and complaints. ## Motion, contrast, language, and print - [ ] With reduced motion enabled, content renders in its final readable state and no ambient or entrance motion persists. - [ ] Hover and drag are never required to understand or operate a control. - [ ] Text, controls, focus indicators, selected states, processing states, and errors meet WCAG 2.2 AA contrast in both themes. - [ ] Complete assessment and journal flows work in Simplified Chinese and English UI. - [ ] Language changes update document language, navigation, statuses, errors, empty states, editor controls, and moderation labels without translating user-authored content. - [ ] Result print preview remains clean and readable; interactive controls and transient feedback are hidden. ## Data, backup, and production regression - [ ] Storage v3 export, merge import, replace import, and clear-data confirmation still work after enabling journals. - [ ] All 16 public assessments load, score, save, reopen, retake, and synchronize without image URLs entering `QuizResult` or historical records. - [ ] A daily consistency snapshot contains SQLite, private/public media, and pending deletion tombstones; it excludes raw queued/running uploads and marks those snapshot jobs failed for re-selection; rotation retains no more than 30 daily snapshots. - [ ] Restore validates and stages a complete database/media set, rejects symlinks or malformed scopes without touching live data, replays deletion tombstones, and removes the restore marker before public service resumes. - [ ] Production `/healthz` returns `ok`; `/api/auth/get-session` returns JSON `null` when unauthenticated. - [ ] Production smoke tests cover `/`, `/assessments/`, one pilot detail/result route, `/journal/`, `/community/`, `/complaints/`, `/privacy/`, `robots.txt`, and `sitemap.xml`. - [ ] Canonical URLs use `https://knowyourself.cc.cd/`; `www` and legacy hosts return `301` while preserving path and query. - [ ] A newly published visible journal appears in the sitemap; hidden, unpublished, and deleted journals do not.