A comprehensive comic book character and team library — a one-stop reference for getting into comics, returning after time away, or exploring a specific era. Find any character or team, understand their full history across eras and story arcs, and know exactly how to read, watch, or listen to every connected piece of media.
Every character. Every era. Every arc.
| Layer | Choice |
|---|---|
| Framework | Next.js 15 (App Router, RSC) |
| Language | TypeScript (strict, no any) |
| Styling | Tailwind CSS v4 (CSS-first @theme) |
| Database | Supabase (Postgres) — optional, see below |
| Data fetching | TanStack Query v5 |
| Search | Fuse.js (client-side fuzzy search) |
| Icons | Lucide React |
This stack requires Node.js ≥ 18.18 (Node 20 LTS recommended). Next.js 15, Tailwind v4's native
oxide engine, and @supabase/storage-js all refuse older runtimes.
The machine this was built on runs Node 18.13.0, which is too old to run
next dev/next build. The full codebase type-checks cleanly (npm run typecheck) and the data pipeline is verified, but you must upgrade Node before the app will start.
# with nvm (an .nvmrc pinning 20 is included)
nvm install 20 && nvm use 20
node -v # should print v20.xThe app ships with a complete local seed dataset (81 entities — characters, teams, and their supporting casts). No database or accounts are needed to run it.
npm install
npm run dev
# open http://localhost:3000The footer shows a “Local seed” indicator when running without Supabase.
The data layer (lib/data/repository.ts) automatically switches to Supabase the moment
NEXT_PUBLIC_SUPABASE_URL + NEXT_PUBLIC_SUPABASE_ANON_KEY are present.
- Create a project at supabase.com.
- Add env vars — copy
.env.exampleto.env.localand fill in:NEXT_PUBLIC_SUPABASE_URL=https://xxxx.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=... SUPABASE_SERVICE_ROLE_KEY=... # server-only; for scripts/admin - Run the schema — paste
supabase/migrations/0001_init.sqlinto the Supabase SQL editor. It creates every table (UUID PKs, FKs, indexes) and Row-Level Security (public read, authenticated write). - Load the seed — paste
supabase/seed.sql(1,170 rows, generated from the same data the offline app uses, with identical UUIDs). - (optional) Regenerate DB types for end-to-end type safety:
npx supabase gen types typescript --project-id <id> > lib/supabase/types.ts
- Create the admin user — in Supabase → Authentication → Users → “Add user” (email/password).
Then sign in at
/admin/login.
Images: real cover/logo art goes in Supabase Storage (public bucket). Until an entity has a
cover_image_url, the UI renders an on-brand, publisher-tinted placeholder.next.config.tsauto-allows your Supabase Storage hostname fornext/image.
A lightweight CMS so content scales without code changes. Protected by Supabase Auth.
/admin— dashboard: entity counts per publisher + a full entity table/admin/entities/new— create a character or team/admin/entities/[id]— edit an entity/admin/entities/[id]/eras— manage eras and arcs/admin/entities/[id]/media— manage media entries/admin/entities/[id]/relationships— manage allies / enemies / members
When Supabase isn’t configured the dashboard is read-only (it shows the local seed) and editing is disabled with a clear notice.
npm run dev # start the dev server (needs Node 20+)
npm run build # production build
npm run typecheck # tsc --noEmit (works on Node 18.13 too)
npm run seed:assemble # rebuild lib/data/seed/content.json from lib/data/seed/generated/*.json
npm run seed:sql # regenerate supabase/seed.sql from the seed contentlib/data/seed/generated/*.json ← authored per-entity content
│ npm run seed:assemble
▼
lib/data/seed/content.json ← deduped, reference-validated authoring data
│ lib/data/seed/build.ts (deterministic UUIDs via lib/data/ids.ts)
├────────────────────────────────────────────┐
▼ ▼
lib/data/local.ts (in-memory backend) npm run seed:sql → supabase/seed.sql
│ │
└──────────► lib/data/repository.ts ◄─────────┘ (lib/data/supabase-repo.ts)
(picks backend by env)
│
RSC pages ────────┤
app/api/* ────────┘──► TanStack Query hooks (hooks/*.ts) ──► client tabs
Because both backends are driven by the same deterministic build, the offline app and a real Supabase database hold byte-for-byte identical records.
app/ routes (home, [publisher], character/team, search, admin, api)
components/ui/ design-system primitives (badges, cards, toggles, states)
components/library/ home + publisher grids and search
components/entity/ hero, tabs, era accordion, arc card, spoiler toggle, …
components/search/ global search + result rows
components/admin/ admin shell, entity form, era/media/relationship managers
hooks/ TanStack Query hooks + search/debounce
lib/data/ repository, local + supabase backends, seed build pipeline
lib/supabase/ browser/server clients, middleware session, config, types
lib/search/ Fuse.js config
lib/ui/ labels, sort, placeholder, classnames helpers
types/ shared TypeScript types matching the DB schema
supabase/ migrations + generated seed.sql
scripts/ seed assembler + SQL generator (run via tsx)
Dark, editorial, cinematic — comic long box meets digital archive. Near-black surfaces, deep ink navy borders, condensed display type (Bebas Neue), Inter body, JetBrains Mono for numbers/dates.
The signature ink-yellow accent (#E8C840) is used in exactly three disciplined ways:
era-timeline highlights, active navigation indicators, and selected-name underlines. Everything
else is handled with surface elevation and border contrast.
- 4 publishers — DC, Marvel, Image, BOOM! (Image/BOOM are entry points for future content)
- 10 primary characters — Batman, Superman, Wonder Woman, The Flash, Green Lantern (DC); Spider-Man, Iron Man, Captain America, Thor, Wolverine (Marvel)
- 4 teams — Justice League, Teen Titans, X-Men, Avengers
- Supporting cast — each hero’s rogues gallery and each team’s roster are seeded as real, navigable entities (81 entities total), so Allies/Enemies/Members tabs link to full pages
- 119 eras · 190 arcs · 221 reading entries · 186 relationships · 255 media entries
Manga support, user accounts / reading progress, community data, character comparison, a mobile app,
and a public read API. See the-index-claude-code.md for the full original brief.