OPEN PANEL — Web App Spec (`SPEC_WEB.md`)
OPEN PANEL — Web App Spec (SPEC_WEB.md)
Section titled “OPEN PANEL — Web App Spec (SPEC_WEB.md)”Surface spec for the WEB client. Derives from
CANON.md(§3 product, §4 stack, §6 contracts, §9 terminology). Where this doc and CANON disagree, CANON wins. Status: DRAFT v0.1 — 2026-06-13. Brand nouns ALL-UPPERCASE in prose per style guide.
1. Goals & role of WEB
Section titled “1. Goals & role of WEB”WEB is the primary reach surface and the free reading front door for OPEN PANEL.
- Reach: zero-install, linkable, the canonical URL for any STANDARD ISSUE. Every share, search result, and embed resolves here first.
- SEO discovery: the only surface crawlers see. Series, issues, and creator pages are server-rendered so the FOUNDATION catalog is fully indexable.
- Free-first: every STANDARD ISSUE reads with no account, no paywall, no DRM (CANON §4).
- Commerce on-ramp (not the focus): WEB hosts the VARIANT store, the licensing-portal entry, and donations — but reading is the hero. One identity, two contexts (reader vs. collector/buyer/licensee), per CANON §3.
- Non-goal: WEB is not the heavy offline-reading surface (that is MOBILE) nor the collector’s-library / creator-tooling host (that is DESKTOP). WEB does lightweight PWA offline only (read-later, §6).
2. Route map / page inventory
Section titled “2. Route map / page inventory”Rendering: SSR = server-rendered for SEO/first-paint; CSR = client-rendered (auth/
interactive); ISR = incrementally regenerated static. Reader engine = @openpanel/reader.
| Route | Page | Render | Notes |
|---|---|---|---|
/ | Home / Discover | SSR (ISR) | Featured, new STANDARD ISSUES, curated rails. Indexable. |
/discover | Browse / genres / filters | SSR (ISR) | Faceted catalog; filter state in URL. |
/series/[slug] | Series page | SSR | Synopsis, issue list, credits, ratings, OG + structured data. |
/series/[slug]/[issue] | Issue reader | SSR shell → CSR reader | SSR metadata + first page for crawl/LCP; reader hydrates. |
/search?q= | Search results | SSR (query) | Postgres FTS (CANON §4); shareable result URLs. |
/creator/[slug] | Creator page | SSR | Bio, bibliography, links; structured Person data. |
/account | Account home | CSR (auth) | Profile, reading history, entitlements, prefs. |
/account/library | My library / read-later | CSR (auth) | Progress-synced; offline-cached subset. |
/store | VARIANT store | SSR (ISR) | Premium VARIANT EDITIONS catalog; indexable. |
/store/[product] | VARIANT product | SSR | Stripe checkout entry; OG product data. |
/license | Licensing portal entry | SSR | Marketing + entry to LEDGER-backed portal (handoff to backend portal). |
/donate | Donate (FOUNDATION) | SSR → CSR | Stripe (separate FOUNDATION account per CANON §4). |
/u/[handle] | Public reader profile (optional) | SSR | Shareable shelves; privacy-gated. |
/legal/*, /about | Static | SSG | Mission, governance summary, policies. |
/auth/* | Sign in / callback | CSR | Supabase Auth; magic link + OAuth. |
/api/* | BFF route handlers | server | Thin proxy to Content API / entitlements; never expose service keys. |
URL = identity: slugs are stable, human-readable, locale-prefixed for i18n (/[locale]/...).
3. The WEB reader
Section titled “3. The WEB reader”Built on the shared @openpanel/reader TS engine (CANON §4) consuming CPF (CANON §6.1).
- Page view: full-page reading, single/double-page spreads, fit-width / fit-height / original. Responsive image tiles served from R2/CDN.
- Guided view: panel-by-panel pan/zoom along the authored CPF reading path (panel regions + order). Smooth animated transitions; tap/click or arrow to advance panel. Falls back to page view if a CPF has no guided regions.
- Keyboard nav:
←/→page or panel,Space/Shift+Spaceadvance/back,Ffullscreen,Gtoggle guided/page,+/-zoom,Home/Endfirst/last,?shortcut help. Full focus management and visible focus ring (WCAG, §7). - Fullscreen: Fullscreen API; chrome auto-hides, reveals on pointer move / key.
- Progress sync: current page/panel persisted to the Content API (CANON §6.2) for
signed-in readers, debounced; resumable across surfaces. Anonymous readers get
localStorageprogress that can be claimed on sign-in. - Prefetch: next N pages/tiles prefetched (idle + network-aware); guided view prefetches
the next panel’s tile. Uses
<link rel=prefetch>+ engine-driven cache warming. - Low-bandwidth mode: user toggle + auto via
navigator.connection(Save-Data / slow effective type) → lower-resolution tiles, no animated guided transitions, lazy prefetch off. - Reader prefs (persisted): background (paper/ink/sepia), reading direction (LTR/RTL per
CPF locale), dyslexia-friendly UI font, reduced-motion (honors
prefers-reduced-motion). - Accessibility in-reader: per-panel alt-text from CPF surfaced to screen readers in guided order; “read alt-text” mode (CANON §3).
4. PWA / offline
Section titled “4. PWA / offline”- Installable: Web App Manifest (name, icons, theme,
display: standalone, shortcuts to Home + My Library). Install prompt surfaced contextually, not nagging. - Service worker strategy:
- App shell + static assets → stale-while-revalidate.
- Catalog/series JSON → network-first (fallback to cache offline).
- Comic page tiles → cache-first with an explicit “save for offline / read-later” action that bulk-caches a STANDARD ISSUE’s tiles + its CPF into a named cache.
- Auth/entitlement calls → network-only (never cached).
- Read-later quota: capped cache with LRU eviction + user-visible storage usage in
/account/library; eviction never silently drops an explicitly saved issue without notice. - Scope boundary: WEB offline is for casual read-later; the durable offline-library experience is MOBILE/DESKTOP (CANON §3). Premium VARIANT content is not cached offline on WEB (entitlement-gated, §5).
5. Auth & entitlements
Section titled “5. Auth & entitlements”Per CANON §6.3 (Identity & Entitlements) and §4 (Supabase Auth, one identity).
- Free is always granted. STANDARD ISSUES require no auth and no entitlement check. Auth only unlocks personalization (progress sync, library, prefs) and premium VARIANT.
- Auth: Supabase Auth — magic-link primary + OAuth providers. One identity spans reader/buyer/licensee contexts; context is a UI mode, not a separate login.
- Premium gating: VARIANT EDITIONS are gated by entitlement checks, not hard DRM (CANON §4 DRM stance). The reader requests an entitlement token from the Content API; gated tiles served via short-lived signed CDN URLs. No client-side secret ever.
- Minors / COPPA (CANON §7.7): age-gated account creation, restricted data collection and no behavioral profiling for minors; default content rating filter on.
- Server enforcement: entitlements enforced server-side (RLS + Rust services); the client UI gating is convenience only, never the security boundary.
6. SEO / discoverability
Section titled “6. SEO / discoverability”- SSR catalog (CANON §4) for home, discover, series, issue shell, creator, store.
- Open Graph / Twitter cards: per series/issue/creator/product — cover art, title, synopsis, creator credits.
- Structured data (JSON-LD):
ComicSeries,ComicIssue,Person(creators),Product+Offer(VARIANT store),BreadcrumbList,Organization(FOUNDATION). - Sitemaps: auto-generated, segmented (series, issues, creators, store),
lastmodfrom catalog; submitted viarobots.txt. Canonical URLs +hreflangfor locales. - Crawlability: issue reader ships SSR metadata + a crawlable first-page/cover so the free catalog is fully indexed even though the reader itself hydrates client-side.
7. Performance, accessibility, i18n
Section titled “7. Performance, accessibility, i18n”Performance budgets (Core Web Vitals targets):
- LCP ≤ 2.5s (p75, mobile 4G); INP ≤ 200ms; CLS ≤ 0.1.
- Initial JS (reader route) ≤ ~180KB gzip; route-level code splitting; reader engine lazy-loaded.
- Images: responsive
srcset+ tiled comic pages from R2/CDN; AVIF/WebP with fallback; explicit dimensions to prevent CLS; priority hint on the cover/first page. - Edge caching for SSR/ISR catalog; CDN for all assets (CANON §4).
Accessibility — WCAG 2.2 AA:
- Full keyboard operability (§3); visible focus; logical focus order; skip links.
- Reader exposes alt-text per panel (CPF) to assistive tech; landmark + ARIA roles.
- Color contrast AA on both ink and paper themes; respects
prefers-reduced-motionandprefers-color-scheme; dyslexia-friendly font option; targets ≥ 24×24px.
i18n:
- Locale-prefixed routes; UI strings externalized; RTL layout support (drives reader
direction with CPF locale); localized metadata +
hreflang; per-CPF locale content.
8. Component / design system
Section titled “8. Component / design system”- Sourced from
brand/BRAND_IDENTITY.md(CANON §1): panel-grid + gutter motif, ink-black / paper-white base, FOUNDATION = signal/ink blue, VARIANT = collectible gold/foil, newsprint texture; monospace + humanist sans system, display face for logos. - Reader chrome is a distinct, minimal component set (top bar, page/panel scrubber, settings sheet, fullscreen toggle) that recedes during reading. Catalog/store/account use the standard system components.
- Tailwind design tokens mirror BRAND_IDENTITY; two sub-brand accent themes (FOUNDATION / VARIANT) toggled by context. No bespoke per-page CSS outside the token system.
9. Analytics & security
Section titled “9. Analytics & security”Analytics events (privacy-respecting, CANON §6.7 / §4 — no third-party ad trackers, COPPA-aware):
page_view,series_view,issue_open,reader_start,page_turn,panel_advance,guided_toggle,reading_complete,progress_sync.save_for_offline,pwa_install,low_bandwidth_toggle.search_query(terms hashed/aggregated),search_result_click.auth_sign_in,entitlement_check,variant_view,checkout_start,donate_start.- Minors: engagement events stripped of identifiers; no behavioral profiling.
Security:
- CSP: strict
default-src 'self'; explicit allowlist for R2/CDN, Stripe, Supabase; no inline scripts (nonce/hash);frame-ancestors 'none'; HSTS;Referrer-Policy. - RLS reliance: all reader/entitlement/account data behind Supabase RLS + server
enforcement; the WEB BFF (
/api/*) holds no service-role key client-side (CANON §4 / RINA rule: non-NEXT_PUBLIC_vars are server-only). - Signed, short-lived CDN URLs for any gated VARIANT tile; Stripe via hosted/Elements only, no raw card data touches our origin; separate Stripe accounts for VARIANT vs. FOUNDATION donations (CANON §4).
10. Acceptance criteria — MVP definition of done
Section titled “10. Acceptance criteria — MVP definition of done”- Anonymous user can open
/series/[slug]/[issue]and read a full STANDARD ISSUE in both page and guided view, with keyboard + touch nav and fullscreen — no account. - Home, discover, series, creator, and issue pages are SSR and indexable, with valid
OG tags, JSON-LD (
ComicSeries/ComicIssue/Person), and a generated sitemap. - Search returns relevant series/issues via Postgres FTS at a shareable URL.
- Signed-in reader gets progress sync that resumes across a reload and is claimable from prior anonymous reading.
- PWA is installable; a saved STANDARD ISSUE is readable offline (read-later), with visible storage usage and no silent eviction of saved issues.
- A premium VARIANT EDITION is entitlement-gated: blocked without entitlement, readable with one; enforcement is server-side, no client secret.
/store,/donate,/licenseentries function; VARIANT checkout and FOUNDATION donation route to the correct separate Stripe accounts.- CWV targets met at p75 on a mid-tier mobile device (LCP ≤2.5s, INP ≤200ms, CLS ≤0.1).
- WCAG 2.2 AA passes automated + manual keyboard/screen-reader audit on reader + catalog; reduced-motion and dyslexia-friendly options work.
- CSP enforced with no violations in normal flows; no service-role key reachable client-side; gated tiles only via short-lived signed URLs.
- At least one non-English locale renders end-to-end (UI + a localized CPF), with
hreflangand RTL verified.