~kris/dots

srice

ref: 4471d164e01750db50f2d73d2a7c8af0e2318591 srice/doc/files/audit.md -rw-r--r-- 14.5 KiB
4471d164 — Kris Yotam wallpapermenu: pass -no-config so ambient rofi theme can't override the picker 2 months ago

#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

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)