Generated from audit run on 2025-11-28.
Build passes with 0 errors. Lint reports 4 warnings (React Hook Form watch() incompatibility with React Compiler). Key issues: missing env validation, Prisma client committed to git, large ai-service.ts file, scattered console.error calls.
Status: ✅ Completed
Issue: Non-null assertions on env vars in lib/services/r2-storage.ts (lines 14-17) and missing validation for DATABASE_URL in lib/prisma.ts.
Action:
- Create
lib/env.tswith Zod schema validating:DATABASE_URL,R2_ACCOUNT_ID,R2_ACCESS_KEY_ID,R2_SECRET_ACCESS_KEY,R2_BUCKET_NAME,R2_PUBLIC_URL(optional) - Export typed getters (e.g.,
env.DATABASE_URL) - Update
lib/services/r2-storage.tsto use validated env - Update
lib/prisma.tsto use validated env - Test:
pnpm build+ manually test R2 upload and DB connection
Risk: Low
Status: ✅ Completed
Issue: lib/prisma/ contains ~25K lines of generated code with /* eslint-disable */ in every file. This bloats the repo and risks drift.
Action:
- Add
lib/prisma/to.gitignore -
"db:generate": "prisma generate"script already inpackage.json - Remove
lib/prisma/*from git tracking:git rm -r --cached lib/prisma/ - CI/CD generates Prisma client via
prebuildscript - Test:
pnpm install && pnpm db:generate && pnpm build
Risk: Medium — requires CI update
Status: ✅ Completed
Issue: lib/services/ai-service.ts is 968 lines combining prompts, sanitization, retry logic, and streaming.
Action:
- Create
lib/services/ai/directory - Extract
lib/services/ai/sanitize.ts(sanitizeInput function) - Extract
lib/services/ai/prompts.ts(system prompts, prompt builders) - Extract
lib/services/ai/streaming.ts(streamPositionDescription helper) - Extract
lib/services/ai/retry.ts(withRetry, withTimeout) - Extract
lib/services/ai/types.ts(AIGenerationError, interfaces) - Keep
lib/services/ai/core.tswith AIQuizService class - Create
lib/services/ai/index.tswith re-exports - Keep
lib/services/ai-service.tsas backward-compatible re-export - Test:
pnpm buildpasses
Risk: Medium — many imports to update
Status: ✅ Completed
Issue: components/ui/input-with-tag.tsx has eslint-disable-next-line react-hooks/exhaustive-deps.
Action:
- Review the useEffect dependencies in
input-with-tag.tsx - Fixed by extracting
onChangeto stable callback withuseCallback - Added
notifyParentto dependency array - Test:
pnpm lintno longer shows the eslint-disable
Risk: Low
Status: ✅ Completed
Issue: depcheck reports potentially unused deps: @aws-sdk/s3-request-presigner, @neondatabase/serverless, autoprefixer, pg, tw-animate-css.
Action:
- Verified each dependency:
@aws-sdk/s3-request-presigner- unused, removed@neondatabase/serverless- unused, removedautoprefixer- not needed with Tailwind v4, removedpg- required by@prisma/adapter-pg, kepttw-animate-css- used inglobals.css, kept
- Removed unused packages:
pnpm remove @aws-sdk/s3-request-presigner @neondatabase/serverless autoprefixer - Test:
pnpm install && pnpm buildpasses
Risk: Low
Status: ✅ Completed (Already Implemented)
Issue: Repeated per-question create loops in lib/actions/questions.ts and lib/actions/quizzes.ts.
Action:
- Reviewed:
prepareQuestionForCreateutility already exists inlib/utils/question-utils.ts -
createQuestionActionuses typedCreateQuestionInputschema (intentionally different) - Quiz actions use
prepareQuestionForCreateforFlexibleQuestionconversion - Separation is appropriate: entity schema vs AI-generated question format
Risk: Medium — DB semantics may change
Status: ✅ Completed
Issue: Inconsistent cache invalidation patterns across actions.
Action:
- Create
lib/utils/cache-utils.tswith helpers likeinvalidateQuizCache() - Added
CacheTagsconstants andentityTaghelper for consistent tag naming - Created invalidation helpers for all entities: quiz, question, position, candidate, interview, evaluation, preset
- Updated
lib/utils/cache.tsto re-export new utilities with deprecation notices - Updated all action files to use centralized cache utilities:
lib/actions/positions.ts- usesinvalidatePositionCache()lib/actions/presets.ts- usesinvalidatePresetCache()lib/actions/quizzes.ts- usesinvalidateQuizCache()lib/actions/candidates.ts- usesinvalidateCandidateCache()lib/actions/interviews.ts- usesinvalidateInterviewCache()lib/actions/questions.ts- usesinvalidateQuestionCache()andinvalidateQuizCache()lib/actions/evaluation-entity.ts- usesinvalidateEvaluationCache()lib/actions/profile.ts- usesinvalidateProfileCache()lib/actions/seed-presets.ts- usesinvalidatePresetCache()lib/actions/candidate-quiz-assignment.ts- usesinvalidateInterviewCache()
- Test:
pnpm buildpasses, UI pages update after mutations
Risk: Low
Status: ✅ Completed
Issue: 20+ console.error calls scattered across hooks, actions, and components with inconsistent logging.
Action:
- Create
lib/services/logger.tswithlogger.error(),logger.warn(),logger.info(),logger.debug() - Made env-aware (verbose with colors in dev, structured JSON in prod, suppressed in test)
- Added scoped loggers:
aiLogger,dbLogger,authLogger,storageLogger - Updated high-impact files:
lib/services/r2-storage.ts- usesstorageLoggerlib/auth-server.ts- usesauthLoggerlib/actions/evaluations.ts- usesaiLoggerlib/services/error-handler.ts- uses centrallogger
- Test:
pnpm buildpasses, errors appear in dev console with context
Risk: Low
- ✅ Add Environment Validation - Created
lib/env.ts, updated r2-storage.ts and prisma.ts - ✅ Remove Generated Prisma Client - Added to .gitignore, removed from git tracking
- ✅ Split AI Service - Created
lib/services/ai/with modular components - ✅ Fix ESLint Disables - Fixed input-with-tag.tsx useEffect deps
- ✅ Review Unused Dependencies - Removed 3 unused packages
- ✅ Consolidate Question Creation - Already properly implemented
- ✅ Centralize Cache Invalidation - Created
lib/utils/cache-utils.tswith helpers - ✅ Add Centralized Logger - Created
lib/services/logger.tswith scoped loggers
- React Hook Form
watch()warnings are known limitations with React Compiler — low priority - All changes should be tested with
pnpm buildbefore commit - Large refactors (tasks 2, 3, 7) should be separate PRs