Date: 2026-05-20 Sources: claudeAudit.md (Claude) + codexAudit.md (Codex) Goal: Lean, navigable codebase by August 2026
withDb() pattern (local SQLite, just fix the access pattern).These are the highest-leverage fixes. Every later phase builds on them.
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.tsnext.config.mjssrc/lib/seo.tssrc/lib/content.tssrc/lib/graph.tssrc/app/sitemap.tssrc/app/api/content/search/route.tssrc/app/api/content/md/[slug]/route.tssrc/app/api/system/utils/route.tspublic/scripts/dev/syncContent.jspublic/scripts/dev/slugCollisions.jspublic/scripts/prod/magic-urls.jspublic/scripts/dev/generateMetadata.jsFix: 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:
seo.ts, content.ts, sitemap.ts, api/content/searchProblem: 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.jspublic/scripts/dev/blogActivity.jspublic/scripts/prod/magic-urls.jsFix: 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.
Problem: Sexy URLs are implemented in 3 places that can disagree:
next.config.mjs builds rewrite rules from content.dbsrc/lib/canonical-url.ts mirrors type list and reserved slug rules/${slug} locally in table.tsx, directory.tsx, mediaCard.tsxFix: 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.
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.
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:
(tracking)/{anime,film,tv,games,manga}/page.tsx + watched/read/played subpagesapi/tracking/{anime,film,tv,manga,media}/route.ts (150-187 lines each, same pattern)Fix:
(tracking)/layout.tsx with shared styles(tracking)/[medium]/ route/api/tracking/[medium]/ APITrackingGridBrowser component for watched/read/played liststracking-overview.tsx shared rendererProblem: 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.tsxRepeated: 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.
Problem: Authored content lives inside src/app/:
src/app/(content)/til/content/*.mdxsrc/app/(content)/now/content/*.mdxsrc/app/(misc)/surveys/content/*.survey.mdFix: Move to src/content/ or external content repo. Extract src/lib/til.ts and src/lib/now.ts loaders first, then move files.
Delete:
(info) -- completely empty(media) -- completely emptyDecide:
(updates) -- has layout.tsx + CSS but zero routes. Delete if no plans.sequences/categories/page.tsx (58 lines) vs sequences/category/page.tsx (26 lines, empty placeholder) -- delete the empty oneContains 9+ distinct sub-components, data fetching, state management, API calls, rendering. Split into:
reading/ directory with sub-componentsuseReading and useReadingData hooksForm state, validation, conditional rendering, answer tracking all in one file. Split into:
useSurvey)Kitchen-sink API endpoint. Split into discrete endpoints by concern.
Catch-all CSS file. Extract to src/app/styles/core/:
base.css (viewport, tokens)typography.csscode.csscomments.cssfootnotes.csssidenotes.cssprint.csscards.cssmotion.cssKeep globals.css as the import root plus true app-wide tokens only.
Split by domain once content registry exists:
lib/db/films.tslib/db/anime.tslib/db/games.tslib/db/reading.tslib/db/tv.tslib/db/music.tsSplit: metadata, quotes, supporters.
layout/header.tsx is "use client" but imported by server pages. Split into:
Owns too many jobs: markdown-link parsing, icon lookup, modal state, sounds, compact/expanded modal markup. Extract:
parseMarkdownLinks helper| 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 |
TilEntry in both data.ts and system-db.ts (different id field)NowEntry in both data.ts and system-db.tsMovie in media-db.ts vs film-utils.ts (snake_case vs camelCase)Consolidate to src/lib/types/.
getMovies() defined in both media-db.ts and film-utils.tscitation.tsx and print.tsxunoptimized={image?.includes('krisyotam.com')} repeated in 7 filessyncContent.js still documents public/scripts/keep (deleted)generateMetadata.js hardcodes PROJECT_ROOT = '/home/krisyotam/dev/krisyotam.com'Delete: components/changelog/, components/media/anime/ (if empty)
Move: contribution-graph.tsx from components root to home/
cookie-sign.ts:3 has hardcoded default 'krisyotam-cookie-secret-change-in-prod'. Should throw in production if COOKIE_SECRET not set.
Zero error.tsx files. Add to at minimum: (content), (tracking), (misc), root.
typography/tikz.tsx renders SVG via dangerouslySetInnerHTML without DOMPurify. Low risk (server-rendered from own API) but worth hardening.
csrf.ts allows localhost:3000 and localhost:3080 unconditionally. Gate behind NODE_ENV === 'development'.
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.
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.
globals.css code block styles (lines 32-67) use excessive !important. Refactor cascade to avoid.
Vitest config exists but no test files. Priority tests to write:
data/ by defaultsrc/config/contentRegistry.tsseo.ts, content.ts, sitemap.ts, api/content/searchscripts/lib/paths.mjssyncDocs.js, syncNotebooks.js, blogActivity.js, magic-urls.js pathspublic/data/*.dbreference-db.ts to withDb()generateMetadata.js hardcoded PROJECT_ROOTreading.tsx into sub-components + hookssurvey.tsx into form logic + presentationapi/system/utils into discrete endpointsglobals.css into styles/core/* modulesitem.urltable.tsx, directory.tsx, mediaCard.tsx to use passed URLsuseContentListingState hookcollectionShell.tsxpublic/ (after path helper + docs update)media-db.ts and system-db.ts by domain (after registry)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
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) |