End-to-end ZXDB integration with environment validation, Drizzle ORM MySQL
setup, typed repositories, Zod-validated API endpoints, and a deep, cross‑
linked Explorer UI under `/zxdb`. Also update dynamic route pages to the
Next.js 15 async `params` API and align ZXDB lookup table columns (`text` vs
`name`).
Summary
- Add t3.gg-style Zod environment validation and typed `env` access
- Wire Drizzle ORM to ZXDB (mysql2 pool, singleton) and minimal schemas
- Implement repositories for search, entry details, label browsing, and
category listings (genres, languages, machinetypes)
- Expose a set of Next.js API routes with strict Zod validation
- Build the ZXDB Explorer UI with search, filters, sorting, deep links, and
entity pages (entries, labels, genres, languages, machinetypes)
- Fix Next 15 “sync-dynamic-apis” warning by awaiting dynamic `params`
- Correct ZXDB lookup model columns to use `text` (aliased as `name`)
Details
Env & DB
- example.env: document `ZXDB_URL` with readonly role notes
- src/env.ts: Zod schema validates `ZXDB_URL` as `mysql://…`; fails fast on
invalid env
- src/server/db.ts: create mysql2 pool from `ZXDB_URL`; export Drizzle instance
- drizzle.config.ts: drizzle-kit configuration (schema path, mysql2 driver)
Schema (Drizzle)
- src/server/schema/zxdb.ts:
- entries: id, title, is_xrated, machinetype_id, language_id, genretype_id
- helper tables: search_by_titles, search_by_names, search_by_authors,
search_by_publishers
- relations: authors, publishers
- lookups: labels, languages, machinetypes, genretypes
- map lookup display columns from DB `text` to model property `name`
Repository
- src/server/repo/zxdb.ts:
- searchEntries: title search via helper table with filters (genre, language,
machine), sorting (title, id_desc), and pagination
- getEntryById: join lookups and aggregate authors/publishers
- Label flows: searchLabels (helper table), getLabelById, getLabelAuthoredEntries,
getLabelPublishedEntries
- Category lists: listGenres, listLanguages, listMachinetypes
- Category pages: entriesByGenre, entriesByLanguage, entriesByMachinetype
API (Node runtime, Zod validation)
- GET /api/zxdb/search: search entries with filters and sorting
- GET /api/zxdb/entries/[id]: fetch entry detail
- GET /api/zxdb/labels/search, GET /api/zxdb/labels/[id]: label search and detail
- GET /api/zxdb/genres, /api/zxdb/genres/[id]
- GET /api/zxdb/languages, /api/zxdb/languages/[id]
- GET /api/zxdb/machinetypes, /api/zxdb/machinetypes/[id]
UI (App Router)
- /zxdb: Explorer page with search box, filters (genre, language, machine), sort,
paginated results & links to entries; quick browse links to hubs
- /zxdb/entries/[id]: entry detail client component shows title, badges
(genre/lang/machine), authors and publishers with cross-links
- /zxdb/labels (+ /[id]): search & label detail with "Authored" and "Published"
tabs, paginated lists linking to entries
- /zxdb/genres, /zxdb/languages, /zxdb/machinetypes and their /[id] detail pages
listing paginated entries and deep links
- Navbar: add ZXDB link
Next 15 dynamic routes
- Convert Server Component dynamic pages to await `params` before accessing
properties:
- /zxdb/entries/[id]/page.tsx
- /zxdb/labels/[id]/page.tsx
- /zxdb/genres/[id]/page.tsx
- /zxdb/languages/[id]/page.tsx
- /registers/[hex]/page.tsx (Registers section)
- /api/zxdb/entries/[id]/route.ts: await `ctx.params` before validation
ZXDB schema column alignment
- languages, machinetypes, genretypes tables use `text` for display columns;
models now map to `name` to preserve API/UI contracts and avoid MySQL 1054
errors in joins (e.g., entry detail endpoint).
Notes
- Ensure ZXDB helper tables are created (ZXDB/scripts/ZXDB_help_search.sql)
— required for fast title/name searches and author/publisher lookups.
- Pagination defaults to 20 (max 100). No `select *` used in queries.
- API responses are `cache: no-store` for now; can be tuned later.
Deferred (future work)
- Facet counts in the Explorer sidebar
- Breadcrumbs and additional a11y polish
- Media assets and download links per release
Signed-off-by: Junie@lucy.xalior.com
Signed-off-by: Junie@lucy.xalior.com
122 lines
5.0 KiB
Markdown
122 lines
5.0 KiB
Markdown
# AGENT.md
|
||
|
||
This document provides an overview of the Next Explorer project, its structure, and its implementation details.
|
||
|
||
## Project Overview
|
||
|
||
Next Explorer is a web application for browsing and exploring the registers of the Spectrum Next computer. It is built with Next.js (App Router), React, and TypeScript.
|
||
|
||
The application reads register data from `data/nextreg.txt`, parses it on the server, and displays it in a user-friendly interface. Users can search for specific registers and view their details, including per-register notes and source snippets.
|
||
|
||
## Project Structure
|
||
|
||
The project is a Next.js application with the following structure:
|
||
```
|
||
|
||
next-explorer/
|
||
├── eslint.config.mjs
|
||
├── next.config.ts
|
||
├── package.json
|
||
├── pnpm-lock.yaml
|
||
├── tsconfig.json
|
||
├── data/
|
||
│ ├── nextreg.txt
|
||
│ ├── custom_parsers.txt
|
||
│ └── wikilinks.txt
|
||
├── node_modules/...
|
||
├── public/...
|
||
└── src/
|
||
├── middleware.js
|
||
├── app/
|
||
│ ├── layout.tsx
|
||
│ ├── page.module.css
|
||
│ ├── page.tsx
|
||
│ └── registers/
|
||
│ ├── page.tsx
|
||
│ ├── RegisterBrowser.tsx
|
||
│ ├── RegisterDetail.tsx
|
||
│ └── [hex]/
|
||
│ └── page.tsx
|
||
├── components/
|
||
│ ├── Navbar.tsx
|
||
│ └── ThemeDropdown.tsx
|
||
├── scss/
|
||
│ ├── _bootswatch.scss
|
||
│ ├── _explorer.scss
|
||
│ ├── _variables.scss
|
||
│ └── nbn.scss
|
||
├── services/
|
||
│ └── register.service.ts
|
||
└── utils/
|
||
├── register_parser.ts
|
||
└── register_parsers/
|
||
├── reg_default.ts
|
||
└── reg_f0.ts
|
||
```
|
||
- **`data/`**: Contains the raw input data for the Spectrum Next explorer.
|
||
- `nextreg.txt`: Main register definition file.
|
||
- `custom_parsers.txt`, `wikilinks.txt`: Auxiliary configuration/data used by the parser.
|
||
- **`src/app/`**: Next.js App Router entrypoint.
|
||
- `layout.tsx`: Root layout for all routes.
|
||
- `page.tsx`: Application home page.
|
||
- `registers/`: Routes and components for the register explorer.
|
||
- `page.tsx`: Server Component that loads and lists all registers.
|
||
- `RegisterBrowser.tsx`: Client Component implementing search/filter and listing.
|
||
- `RegisterDetail.tsx`: Client Component that renders a single register’s details, including modes, notes, and source modal.
|
||
- `[hex]/page.tsx`: Dynamic route that renders details for a specific register by hex address.
|
||
- **`src/components/`**: Shared UI components such as `Navbar` and `ThemeDropdown`.
|
||
- **`src/services/register.service.ts`**: Service layer responsible for loading and caching parsed register data.
|
||
- **`src/utils/register_parser.ts` & `src/utils/register_parsers/`**: Parsing logic for `nextreg.txt`, including mode/bitfield handling and any register-specific parsing extensions.
|
||
|
||
## Implementation Details
|
||
|
||
Comment what the code does, not what the agent has done. The documentation's purpose is the state of the application today, not a log of actions taken.
|
||
|
||
### Data Parsing
|
||
|
||
- `getRegisters()` in `src/services/register.service.ts`:
|
||
- Reads `data/nextreg.txt` from disk.
|
||
- Uses `parseNextReg()` from `src/utils/register_parser.ts` to convert the raw text into an array of `Register` objects.
|
||
- Returns the in-memory representation of all registers (and can be extended to cache results across calls).
|
||
|
||
- `parseNextReg()` and related helpers in `register_parser.ts`:
|
||
- Parse the custom `nextreg.txt` format into structured data:
|
||
- Register addresses (hex/dec).
|
||
- Names, notes, and descriptive text.
|
||
- Per-mode read/write/common bitfield views.
|
||
- Optional source lines and external links (e.g. wiki URLs).
|
||
- Delegate special-case parsing to functions in `src/utils/register_parsers/` (e.g. `reg_default.ts`, `reg_f0.ts`) when needed.
|
||
|
||
### React / Next.js Patterns
|
||
|
||
- **Server Components**:
|
||
- `src/app/registers/page.tsx` and `src/app/registers/[hex]/page.tsx` are Server Components.
|
||
- They call `getRegisters()` on the server and pass the resulting data down to client components as props.
|
||
|
||
- **Client Components**:
|
||
- `RegisterBrowser.tsx`:
|
||
- Marked with `'use client'`.
|
||
- Uses React state to manage search input and filtered results.
|
||
- Renders a list or grid of registers.
|
||
- `RegisterDetail.tsx`:
|
||
- Marked with `'use client'`.
|
||
- Renders a single register with tabs for different access modes.
|
||
- Uses a modal to show the original source lines for the register.
|
||
|
||
- **Dynamic Routing**:
|
||
- `src/app/registers/[hex]/page.tsx`:
|
||
- Resolves the `[hex]` URL segment.
|
||
- Looks up the corresponding register by `hex_address`.
|
||
- Calls `notFound()` when no matching register exists.
|
||
|
||
### Working Patterns***
|
||
|
||
- git branching:
|
||
- Do not create new branches
|
||
- git commits:
|
||
- Create COMMIT_EDITMSG file, await any user edits, then commit using that
|
||
commit note, and then delete the COMMIT_EDITMSG file.
|
||
- git commit messages:
|
||
- Use imperative mood (e.g., "Add feature X", "Fix bug Y").
|
||
- Include relevant issue numbers if applicable.
|
||
- Sign-off commit message as Junie@<hostname> |