# ZXDB Guide This document explains how the ZXDB Explorer works in this project, how to set up the database connection, and how to use the built‑in API and UI for software discovery. ## What is ZXDB? ZXDB (https://github.com/zxdb/ZXDB) is a community‑maintained database of ZX Spectrum software, publications, and related entities. In this project, we connect to a MySQL ZXDB instance in read‑only mode and expose a fast, cross‑linked explorer UI under `/zxdb`. ## Prerequisites - MySQL server with ZXDB data (or at minimum the tables; data is needed to browse). - Ability to run the helper SQL that builds search tables (required for efficient LIKE searches). - A read‑only MySQL user for the app (recommended). - The `ZXDB` submodule is checked in for schemas/scripts; use `pnpm setup:zxdb-local` after cloning to keep local SQL dumps untracked. ## Database setup 1. Import ZXDB data into MySQL. - Extract and import https://github.com/zxdb/ZXDB/blob/master/ZXDB_mysql.sql.zip 2. Create helper search tables (required). - Run `https://github.com/zxdb/ZXDB/blob/master/scripts/ZXDB_help_search.sql` on your ZXDB database. - This creates `search_by_titles`, `search_by_names`, `search_by_authors`, `search_by_publishers`, `search_by_aliases`, `search_by_origins`, `search_by_magrefs`, `search_by_magazines`, and `search_by_issues` tables used for search scopes and magazine references. 3. Create a read‑only role/user (recommended). - Create user `zxdb_readonly`. - Grant `SELECT, SHOW VIEW` on your `zxdb` database to the user. ## Environment configuration Set the connection string in `.env`: ``` ZXDB_URL=mysql://zxdb_readonly:password@hostname:3306/zxdb ``` Notes: - The URL must start with `mysql://`. Env is validated at boot by `src/env.ts` (Zod), failing fast if misconfigured. - The app uses a singleton `mysql2` pool (`src/server/db.ts`) and Drizzle ORM for typed queries. ## Running ``` pnpm install pnpm dev # open http://localhost:4000 and navigate to /zxdb ``` ## Explorer UI overview - `/zxdb` — Search entries by title and filter by genre, language, and machine type; sort and paginate results. - `/zxdb/entries` — Entries search with scope toggles (titles/aliases/origins) and facets. - `/zxdb/entries/[id]` — Entry details with related releases, downloads, origins, relations, and media. - `/zxdb/releases` — Releases search + filters. - `/zxdb/releases/[entryId]/[releaseSeq]` — Release detail: magazine references, downloads, scraps, and issue files. - `/zxdb/labels` and `/zxdb/labels/[id]` — Browse/search labels (people/companies), permissions, licenses, and authored/published entries. - `/zxdb/genres`, `/zxdb/languages`, `/zxdb/machinetypes` — Category hubs with linked detail pages listing entries. - `/zxdb/magazines` and `/zxdb/magazines/[id]` — Magazine list and issue navigation. - `/zxdb/issues/[id]` — Issue detail with contents and references. Cross‑linking: All entities are permalinks using stable IDs. Navigation uses Next `Link` so pages are prefetched. Performance: Detail and index pages are server‑rendered with initial data and use ISR (`revalidate = 3600`) to reduce time‑to‑first‑content. Queries select only required columns and leverage helper tables for text search. ## HTTP API reference (selected) All endpoints are under `/api/zxdb` and validate inputs with Zod. Responses are JSON. - Search entries - `GET /api/zxdb/search` - Query params: - `q` — string (free‑text search; normalized via helper tables) - `page`, `pageSize` — pagination (default pageSize=20, max=100) - `genreId`, `languageId`, `machinetypeId` — optional filters - `sort` — `title` or `id_desc` - `scope` — `title`, `title_aliases`, or `title_aliases_origins` - `facets` — boolean; if truthy, includes facet counts for genres/languages/machines - Entry detail - `GET /api/zxdb/entries/[id]` - Returns: entry core fields, joined genre/language/machinetype names, authors and publishers. - Labels - `GET /api/zxdb/labels/search?q=...` - `GET /api/zxdb/labels/[id]?page=1&pageSize=20` — includes `authored` and `published` lists. - Categories - `GET /api/zxdb/genres` and `/api/zxdb/genres/[id]?page=1` - `GET /api/zxdb/languages` and `/api/zxdb/languages/[id]?page=1` - `GET /api/zxdb/machinetypes` and `/api/zxdb/machinetypes/[id]?page=1` Runtime: API routes declare `export const runtime = "nodejs"` to support `mysql2`. ## Implementation notes - Drizzle models map ZXDB lookup table column `text` to property `name` for ergonomics (e.g., `languages.text` → `name`). - Next.js 15 dynamic params must be awaited in App Router pages and API routes. Example: ```ts export default async function Page({ params }: { params: Promise<{ id: string }> }) { const { id } = await params; // ... } ``` - Repository queries parallelize independent calls with `Promise.all` for lower latency. ## Troubleshooting - 400 from dynamic API routes: ensure you await `ctx.params` before Zod validation. - Missing facets or scope toggles: ensure helper tables from `ZXDB_help_search.sql` exist. - Unknown column errors for lookup names: ZXDB tables use column `text` for names; Drizzle schema must select `text` as `name`. - Slow entry page: confirm server‑rendering is active and ISR is set; client components should not fetch on the first paint when initial props are provided. - MySQL auth or network errors: verify `ZXDB_URL` and that your user has read permissions. ## Roadmap - Issue-centric media grouping and richer magazine metadata. - Additional cross-links for tags, relations, and permissions as UI expands. - A11y polish and higher-level navigation enhancements.