# Merged Structural Audit: krisyotam.com **Date:** 2026-05-20 **Sources:** claudeAudit.md (Claude) + codexAudit.md (Codex) **Goal:** Lean, navigable codebase by August 2026 --- ## Decisions Applied Before Merge - **Fonts:** Ignore. Being restructured via CDN work in oasis/cdn. Not a codebase problem. - **Analytics DB:** Keep on Neon (external). It's lossy data, not worth hosting locally. - **All other DBs:** Local SQLite only. Phase out any other external DB references. - **reference-db.ts singleton:** Migrate to `withDb()` pattern (local SQLite, just fix the access pattern). --- ## Phase 1: Sources of Truth These are the highest-leverage fixes. Every later phase builds on them. ### 1.1 Content Registry (Codex finding, confirmed by Claude) **Problem:** Content type definitions are duplicated across 13+ files. Adding a content type requires touching routing, sync scripts, feeds, sitemap, search, SEO, and tests. Some lists include `documents`, `til`, `now`, `scripts`, `notebooks`, `sequences`; others exclude them. **Files affected:** - `src/app/(content)/[type]/config.ts` - `next.config.mjs` - `src/lib/seo.ts` - `src/lib/content.ts` - `src/lib/graph.ts` - `src/app/sitemap.ts` - `src/app/api/content/search/route.ts` - `src/app/api/content/md/[slug]/route.ts` - `src/app/api/system/utils/route.ts` - `public/scripts/dev/syncContent.js` - `public/scripts/dev/slugCollisions.js` - `public/scripts/prod/magic-urls.js` - `public/scripts/dev/generateMetadata.js` **Fix:** Single `src/config/contentRegistry.ts` defining table name, public route, canonical URL mode, sync source, date/category columns, feed/search/sitemap inclusion. Mirror as `scripts/lib/contentRegistry.mjs` for CommonJS scripts. **Work:** 1. Introduce registry with current behavior only (no new features) 2. Convert read-only consumers: `seo.ts`, `content.ts`, `sitemap.ts`, `api/content/search` 3. Convert write/sync scripts after registry is proven ### 1.2 Database Root Drift (Codex finding) **Problem:** Runtime uses root `data/` via `src/lib/db.ts`, but some scripts resolve paths relative to `public/scripts/`, landing at `public/data/` instead. Zero-byte `.db` files exist in `public/data/`. **Files affected:** - `public/scripts/doc/syncDocs.js` (resolves `../../data/content.db` from inside `public/scripts/doc`) - `public/scripts/dev/syncNotebooks.js` - `public/scripts/dev/blogActivity.js` - `public/scripts/prod/magic-urls.js` **Fix:** Create `scripts/lib/paths.mjs` exporting `PROJECT_ROOT`, `DATA_DIR`, `CONTENT_DIR`, `dbPath(name)`. Honor `KRISYOTAM_DATA_DIR`. Delete zero-byte `public/data/*.db` files. ### 1.3 Canonical URL Drift (Codex finding, confirmed by Claude) **Problem:** Sexy URLs are implemented in 3 places that can disagree: - `next.config.mjs` builds rewrite rules from `content.db` - `src/lib/canonical-url.ts` mirrors type list and reserved slug rules - Components fall back to `/${slug}` locally in `table.tsx`, `directory.tsx`, `mediaCard.tsx` **Fix:** Normalize URLs server-side, pass `item.url` everywhere. Components render one URL field instead of rebuilding URLs locally. Use `getCanonicalContentUrl` in metadata, JSON-LD, breadcrumbs, citations. ### 1.4 reference-db.ts Singleton (Claude finding) **Problem:** `reference-db.ts` uses a manual singleton pattern instead of the project's `withDb()` wrapper. Connection never closed. This is the only SQLite file that doesn't use the canonical pattern. **Fix:** Rewrite to use `withDb('reference', ...)`. Delete the manual caching code. --- ## Phase 2: Route Consolidation ### 2.1 Tracking Route Duplication (Claude finding, confirmed by Codex) **Problem:** 5 near-identical page sets + 7 identical layouts + 5 near-identical API routes + 5 near-identical client components. The single biggest structural redundancy in the codebase. **Scope:** - Pages: `(tracking)/{anime,film,tv,games,manga}/page.tsx` + watched/read/played subpages - Layouts: 7 files, all 12 lines, all identical - APIs: `api/tracking/{anime,film,tv,manga,media}/route.ts` (150-187 lines each, same pattern) - Clients: per-medium client components with identical state machinery **Fix:** - Single `(tracking)/layout.tsx` with shared styles - Dynamic `(tracking)/[medium]/` route - Consolidated `/api/tracking/[medium]/` API - Shared `TrackingGridBrowser` component for watched/read/played lists - Extend existing `tracking-overview.tsx` shared renderer ### 2.2 Content Listing Client Duplication (Codex finding) **Problem:** Listing clients repeat identical state machinery: - `(content)/[type]/client.tsx` - `(content)/til/client.tsx` - `(content)/now/client.tsx` - `(content)/scripts/client.tsx` - `(content)/sequences/client.tsx` Repeated: search state, URL query sync, category/tag construction, date sorting, empty states, header fallbacks, slug banners. **Fix:** Extract `src/hooks/useContentListingState.ts` + `src/components/content/collectionShell.tsx`. Route clients own only data shape and item renderer choice. ### 2.3 Content Payloads in Route Folders (Codex finding) **Problem:** Authored content lives inside `src/app/`: - `src/app/(content)/til/content/*.mdx` - `src/app/(content)/now/content/*.mdx` - `src/app/(misc)/surveys/content/*.survey.md` **Fix:** Move to `src/content/` or external content repo. Extract `src/lib/til.ts` and `src/lib/now.ts` loaders first, then move files. ### 2.4 Empty Route Groups (Claude finding, confirmed by Codex) **Delete:** - `(info)` -- completely empty - `(media)` -- completely empty **Decide:** - `(updates)` -- has layout.tsx + CSS but zero routes. Delete if no plans. ### 2.5 Duplicate Navigation Routes (Claude finding) - `sequences/categories/page.tsx` (58 lines) vs `sequences/category/page.tsx` (26 lines, empty placeholder) -- delete the empty one --- ## Phase 3: Monolith Splitting ### 3.1 reading.tsx (1,589 lines) -- Claude finding Contains 9+ distinct sub-components, data fetching, state management, API calls, rendering. Split into: - `reading/` directory with sub-components - `useReading` and `useReadingData` hooks - Server-side data fetching passed as props ### 3.2 survey.tsx (1,220 lines) -- Claude finding Form state, validation, conditional rendering, answer tracking all in one file. Split into: - Form schema parser - Validation logic - Answer reducer hook (`useSurvey`) - Presentation components ### 3.3 api/system/utils/route.ts (762 lines) -- Claude finding Kitchen-sink API endpoint. Split into discrete endpoints by concern. ### 3.4 globals.css (~1,979 lines) -- Codex finding Catch-all CSS file. Extract to `src/app/styles/core/`: - `base.css` (viewport, tokens) - `typography.css` - `code.css` - `comments.css` - `footnotes.css` - `sidenotes.css` - `print.css` - `cards.css` - `motion.css` Keep `globals.css` as the import root plus true app-wide tokens only. ### 3.5 media-db.ts (837 lines, 91 exports) -- Both found Split by domain once content registry exists: - `lib/db/films.ts` - `lib/db/anime.ts` - `lib/db/games.ts` - `lib/db/reading.ts` - `lib/db/tv.ts` - `lib/db/music.ts` ### 3.6 system-db.ts (620 lines) -- Both found Split: metadata, quotes, supporters. ### 3.7 Header Client Boundary (Codex finding) `layout/header.tsx` is `"use client"` but imported by server pages. Split into: - Server-safe header renderer (static markup) - Small client island for interactive parts ### 3.8 PageDescription (Codex finding) Owns too many jobs: markdown-link parsing, icon lookup, modal state, sounds, compact/expanded modal markup. Extract: - Pure `parseMarkdownLinks` helper - Shared modal body component - Narrow client shell for open/close state --- ## Phase 4: Dead Code and Cleanup ### 4.1 Dead Exports (31 functions) -- Claude finding | Module | Dead Functions | |--------|---------------| | `date.ts` | `formatRelative`, `formatInCentralTime`, `getCurrentMonthYear`, `getCurrentYear`, `isPast`, `isFuture`, `isToday`, `formatDateCompact`, `formatDateWithValidation`, `isValidDate` | | `lab-db.ts` | `getSurveyResponses`, `getAllSurveyResponses`, `getSurveyResponseCount`, `getAllSurveys`, `upsertSurvey`, `syncSurveysFromFiles` | | `doc.ts` | `getDocumentsUnderPath`, `getDocBySlug`, `getTopLevelDirectories` | | `data.ts` | `getVerseByTypeAndSlug`, `getDocumentFilePath` | | `mdx.ts` | `fileExists`, `listMdxFiles`, `extractHeadingsWithHierarchy` | | `analytics-db.ts` | `getHistoryTimeline` | | `canonical-url.ts` | `_resetCanonicalUrlCache` | | `cookie-sign.ts` | `signCookie` | | `form-parser.ts` | `extractFormFrontmatter` | | `guestbook-db.ts` | `getGuestbookEntry` | | `media-db.ts` | `getMusicPlaylists` | | `prompts.ts` | `getPromptsByCategory`, `getPromptBySlug` | ### 4.2 Duplicate Type Definitions -- Both found - `TilEntry` in both `data.ts` and `system-db.ts` (different `id` field) - `NowEntry` in both `data.ts` and `system-db.ts` - `Movie` in `media-db.ts` vs `film-utils.ts` (snake_case vs camelCase) Consolidate to `src/lib/types/`. ### 4.3 Duplicate Logic -- Both found - `getMovies()` defined in both `media-db.ts` and `film-utils.ts` - URL replacement logic identical in `citation.tsx` and `print.tsx` - Image `unoptimized={image?.includes('krisyotam.com')}` repeated in 7 files - Date formatters: 14 functions, keep ~5, delete the rest ### 4.4 Stale Script Paths (Codex finding) - `syncContent.js` still documents `public/scripts/keep` (deleted) - `generateMetadata.js` hardcodes `PROJECT_ROOT = '/home/krisyotam/dev/krisyotam.com'` - Several scripts hardcode DB/content locations instead of using env vars ### 4.5 Empty Directories -- Claude finding Delete: `components/changelog/`, `components/media/anime/` (if empty) Move: `contribution-graph.tsx` from components root to `home/` --- ## Phase 5: Security and Resilience ### 5.1 Cookie Secret Fallback -- Claude finding `cookie-sign.ts:3` has hardcoded default `'krisyotam-cookie-secret-change-in-prod'`. Should throw in production if `COOKIE_SECRET` not set. ### 5.2 Error Boundaries -- Claude finding Zero `error.tsx` files. Add to at minimum: `(content)`, `(tracking)`, `(misc)`, root. ### 5.3 TikZ SVG Sanitization -- Claude finding `typography/tikz.tsx` renders SVG via `dangerouslySetInnerHTML` without DOMPurify. Low risk (server-rendered from own API) but worth hardening. ### 5.4 CSRF Localhost Bypass -- Claude finding `csrf.ts` allows `localhost:3000` and `localhost:3080` unconditionally. Gate behind `NODE_ENV === 'development'`. --- ## Phase 6: Scripts Relocation ### 6.1 Private Scripts Under public/ (Codex finding) Only browser-delivered scripts belong under `public/`. Current structure puts dev tooling, DB mutators, importers, prose/verse tools all under `public/scripts/`. **Target structure:** ``` public/scripts/ -- browser-delivered only footnotes.js sidenotes.js prod/ -- production browser scripts scripts/ -- NOT web-served dev/ doc/ prose/ verse/ auth/ lib/ -- shared helpers (paths.mjs, contentRegistry.mjs) ``` **Note:** This conflicts with current project memory that says script subdirectories are fixed under `public/scripts/{auth,dev,doc,prod,prose,verse}`. Update architecture docs and memory when migration starts. --- ## Phase 7: CSS and Themes ### 7.1 Theme Token Duplication (Codex finding) `src/app/styles/themes/default.css` has duplicate no-JS dark-mode and `.dark` definitions, repeated pastel token blocks. Reduce declarations while preserving fallback behavior. ### 7.2 !important Overuse (Claude finding) `globals.css` code block styles (lines 32-67) use excessive `!important`. Refactor cascade to avoid. --- ## Phase 8: Testing ### 8.1 No Test Coverage (Both found) Vitest config exists but no test files. Priority tests to write: 1. Content registry consumers agree on valid types 2. DB path helper resolves root `data/` by default 3. Canonical URL resolver returns sexy URLs 4. Listing state hook filters and sorts deterministically 5. API route handlers return consistent error shapes --- ## Work Division ### Claude Batch 1: Content Registry + Route Consolidation - Create `src/config/contentRegistry.ts` - Convert read-only consumers: `seo.ts`, `content.ts`, `sitemap.ts`, `api/content/search` - Consolidate tracking routes (layouts, pages, APIs, clients) - Delete 31 dead exports - Delete empty route groups and directories ### Codex Batch 1: Data Integrity + Path Safety - Create `scripts/lib/paths.mjs` - Fix `syncDocs.js`, `syncNotebooks.js`, `blogActivity.js`, `magic-urls.js` paths - Delete zero-byte `public/data/*.db` - Migrate `reference-db.ts` to `withDb()` - Fix `generateMetadata.js` hardcoded PROJECT_ROOT - Add DB path tests ### Claude Batch 2: Monolith Splitting - Split `reading.tsx` into sub-components + hooks - Split `survey.tsx` into form logic + presentation - Split `api/system/utils` into discrete endpoints - Extract `globals.css` into `styles/core/*` modules - Split header client boundary ### Codex Batch 2: Canonical URLs + Listing Primitives - Normalize canonical URL generation, require `item.url` - Update `table.tsx`, `directory.tsx`, `mediaCard.tsx` to use passed URLs - Extract `useContentListingState` hook - Extract `collectionShell.tsx` - Move TIL/Now content out of route folders ### Shared Later Batches - Script migration out of `public/` (after path helper + docs update) - Split `media-db.ts` and `system-db.ts` by domain (after registry) - Error boundaries - Security fixes - Theme token dedup - Test coverage --- ## Execution Order ``` 1. Content registry (unblocks everything) 2. DB root drift + path helper (unblocks script fixes) 3. Canonical URL normalization (unblocks component cleanup) 4. Tracking route consolidation (biggest line-count reduction) 5. Monolith splitting (reading, survey, utils, globals) 6. Dead code deletion (31 exports, duplicate types, empty dirs) 7. Listing/content client extraction 8. TIL/Now loader extraction + content file moves 9. Header/PageDescription client boundary fixes 10. Script relocation out of public/ 11. Security fixes (cookie, error boundaries, CSRF, TikZ) 12. Split broad DB modules by domain 13. CSS/theme cleanup 14. Test coverage ``` --- ## Files Index (Conflict-Prone) These files will be touched by both agents at different phases. Coordinate order: | File | Phase | Owner | |------|-------|-------| | `src/lib/seo.ts` | 1.1 | Claude first, then Codex | | `src/lib/content.ts` | 1.1 | Claude first, then Codex | | `src/app/sitemap.ts` | 1.1 | Claude | | `src/lib/canonical-url.ts` | 1.3 | Codex | | `next.config.mjs` | 1.1 | Claude (registry), Codex (URLs) | | `src/app/globals.css` | 3.4 | Claude | | `public/scripts/dev/git.js` | 1.2 | Codex | | `public/scripts/dev/syncContent.js` | 1.1, 1.2 | Codex | | `src/app/(content)/[type]/config.ts` | 1.1 | Claude | | `src/lib/data.ts` | 4.1, 4.2 | Claude (dead code), Codex (types) |