Last Updated: 2026-03-05
Notes:
- 2026-03-05 - Orphaned SQL migration file:
app/migrations/FRESH_0032_llm_tutor_hooks.sqldefines 5 tables (tutor_sessions, tutor_messages, student_vocabulary, exercise_templates, exercise_attempts) but was NEVER RUN. The Drizzle schema (profile.ts) already pushed a simpler 3-table design (exercise_attempts, vocab_lists, tutor_interactions) to the database. These are two different designs. Action: Delete the SQL migration file since Drizzle schema is authoritative, or keep for future reference if the more elaborate design is needed later. - 2026-02-23 - CEFR Level Column for Classes (Future Enhancement): Import data failing because class names in import files (e.g., "Aft Elm", "Pre Int 3") don't match database class names (e.g., "General English A1 - Morning"). Proposed solution: Add
cefr_levelcolumn to classes table to enable standardized matching across different school naming systems. See CLAUDE.md "Future Enhancements" section for details. - 2026-02-12 - Ran
FRESH_0015_email_logs.sqlmigration to add email logs table; no regressions observed. - 2026-02-12 - Payments table consolidation question: Two payments tables exist (
paymentsfor bookings in business.ts,invoicePaymentsfor invoices in system.ts). Question: should all payments go through invoices? If so, the booking payments table is redundant. Action: Consult business owner to determine if payments should always be invoice-linked. MigrationFRESH_0019renames the DB table toinvoice_paymentsto fix namespace collision in the meantime.
This file tracks pre-existing code quality issues that should be addressed in a future cleanup sprint.
Total Errors: 563 errors across codebase (+1 since last check - stable)
Top 3 Issues (Account for 66% of errors):
- 🔴 Snake_case in tests (238 errors) - Test files using
tenant_idinstead oftenantId - 🟡 Missing schema exports (135 errors) -
curriculum.tsandsystem.tsnot exported - 🟡 Type mismatches (74 errors) - Argument type incompatibilities
Quick Fix Opportunity: Phases 1 + 2 below can eliminate 373 errors (66%) in ~3.5 hours
Full Error Log: See typescript-errors-2026-01-26.log for complete error output
- TS2551 (210 errors) - Property does not exist (snake_case vs camelCase naming issues)
- TS2339 (135 errors) - Property does not exist on type (missing schema exports)
- TS2345 (74 errors) - Argument type mismatch
- TS2554 (38 errors) - Expected N arguments but got M
- TS2769 (28 errors) - No overload matches this call (snake_case in insert statements)
- TS2305 (23 errors) - Module has no exported member
- TS2322 (12 errors) - Type is not assignable
- TS2561 (10 errors) - Object literal excess property checks
- TS2344 (7 errors) - Type constraint violations (Next.js 15 async params)
- Other (25 errors) - Various minor type issues
- 🔴 Critical Impact: Snake_case naming issues (238 errors) - May cause runtime errors in tests
- 🟡 High Impact: Missing exports (135 errors) - Prevents compilation in strict mode
- 🟡 Medium Impact: Type mismatches (189 errors) - Type safety issues, unlikely runtime impact
- 🟢 Low Impact: Next.js 15 async params (7 errors) - Routes work at runtime but type-unsafe
Issue: Several API routes use the old synchronous params pattern instead of the new async Promise<> pattern.
Affected Files:
src/app/api/admin/audit-log/[id]/route.tssrc/app/api/admin/courses/[id]/route.tssrc/app/api/admin/enrollments/[id]/route.tssrc/app/api/admin/finance/invoices/[id]/route.tssrc/app/api/admin/programmes/[id]/route.tssrc/app/api/admin/students/[id]/route.ts
Error Example:
Types of property 'GET' are incompatible.
Type '(request: NextRequest, { params }: { params: { id: string; }; })'
is not assignable to
type '(request: NextRequest, context: { params: Promise<{ id: string; }>; })'
Solution: Update all API route handlers to use:
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
// ... rest of handler
}Priority: Medium (affects type safety, but routes work at runtime)
Issue: Test files use snake_case column names (e.g., tenant_id, student_id, class_id) instead of camelCase TypeScript names in both assertions and insert statements.
Affected Files:
src/__tests__/rls-policies.test.ts- ~200 errors (assertions checking snake_case fields)scripts/seed-students.ts- Usingtenant_idin insert statements- Other test/script files with database operations
Error Examples:
// TS2551: Property does not exist
expect(result[0].tenant_id).toBe(tenantId); // Should be: result[0].tenantId
// TS2769: No overload matches this call
await db.insert(users).values({ tenant_id: '...' }) // Should be: tenantId: '...'Solution: Update all test files and seed scripts to use camelCase column names from Drizzle schema.
Priority: High (238 errors total - indicates potential runtime errors in tests)
Issue: MCP server code uses snake_case column names (e.g., tenant_id, created_at) instead of camelCase TypeScript names.
Affected Files:
src/lib/mcp/servers/finance/FinanceMCP.tssrc/lib/mcp/servers/identity/server.ts
Error Examples:
Property 'tenant_id' does not exist on type '...'. Did you mean 'tenantId'?
Property 'created_at' does not exist on type '...'. Did you mean 'createdAt'?
Solution: Update all database queries in MCP servers to use camelCase column names from Drizzle schema.
Priority: High (indicates potential runtime errors)
Issue: Schema files define tables but don't export them from src/db/schema/index.ts, causing import errors across the codebase.
Missing Exports from Curriculum Schema (curriculum.ts):
cefrDescriptors- CEFR level descriptors tablelessonPlans- Teacher lesson plans tablematerials- Teaching materials tablelessonPlanMaterials- Junction table
Missing Exports from System Schema (system.ts):
auditLogs- Immutable audit trail tableinvoices- Financial invoices tableconversations- Communication logs tableexports- Data export tracking table
Affected Files:
src/__tests__/db-schema.test.ts- Tests for missing tablessrc/lib/mcp/servers/finance/server.ts- Importsinvoices,auditLogssrc/lib/mcp/servers/identity/server.ts- ImportsauditLogssrc/lib/mcp/servers/teacher/server.ts- ImportslessonPlans,assignments,gradessrc/app/admin/finance/invoices/[id]/page.tsx- Uses invoice-related queries
Solution: Add missing exports to src/db/schema/index.ts:
// Add to index.ts
export * from './curriculum';
export * from './system';Priority: High (135 errors - prevents compilation in strict mode)
Issue: Identity MCP server expects a role field on users table that doesn't exist in current schema.
Affected File:
src/lib/mcp/servers/identity/server.ts:282-283, 286-287
Solution: Either add role field to users schema or update MCP server to use a different authorization pattern.
Priority: High (indicates incomplete auth implementation)
Files with unused imports/variables:
scripts/seed-students.ts:8- 'enrollments' defined but never usedscripts/verify-dessie-data.ts:7- 'and' defined but never usedsrc/app/admin/bookings/[id]/AddPaymentForm.tsx:49- 'err' in catch blocksrc/app/admin/bookings/create/CreateBookingForm.tsx:138- 'err' in catch blocksrc/app/admin/bookings/create/page.tsx:12,19,27,33- Type imports not usedsrc/app/admin/classes/[id]/page.tsx:7- 'count' defined but never used
Solution: Remove unused imports or prefix with underscore if intentionally unused (e.g., _err, _enrollments).
Priority: Low (warnings only, no runtime impact)
Files with any types:
e2e/admin-student-registry.spec.ts:17scripts/apply-rls-policies.ts:34,46scripts/check-rls-policies.ts- multiple locationsscripts/seed-students.ts:21scripts/verify-complete.ts- multiple locationssrc/__tests__/auth-utils.test.ts- multiple locationssrc/app/admin/_actions/dashboard.ts:71,157
Solution: Replace any with proper TypeScript types or use unknown if type is truly dynamic.
Priority: Medium (reduces type safety)
File: src/app/admin/courses/page.tsx:56-58
Issue: Multiple unescaped " characters in JSX text.
Solution: Use " or “/” for proper HTML entity encoding.
Priority: Low (cosmetic, no functional impact)
Files:
drizzle.config.cjs:1-2scripts/debug-ipv6.js:1scripts/run-fresh-migrations.ts:69
Solution: These are intentional for specific use cases (config files, debug scripts). Can be ignored or marked with ESLint disable comments.
Priority: Low (intentional usage)
Clean files with no errors:
- ✅
app/src/app/admin/students/[id]/page.tsx- Student detail page - ✅
app/src/components/admin/students/StudentList.tsx- Updated with "View Details" link
Test/utility scripts:
app/scripts/find-dessie.tsapp/scripts/verify-dessie-data.tsapp/scripts/test-student-detail.ts
- 🔴 Critical (238 errors): Snake_case naming in tests/scripts - Runtime risk
- 🟡 High (135 errors): Missing schema exports - Compilation blocker
- 🟡 Medium (74 errors): Type mismatches - Type safety issues
- 🟢 Low (115 errors): Minor type issues, unused variables, etc.
-
Phase 1: Critical Priority (Fixes 238 errors)
- Effort: 2-3 hours
- Fix snake_case → camelCase in test files:
src/__tests__/rls-policies.test.ts(~200 errors)scripts/seed-students.tsand other seed scripts
- Update all
.values({ tenant_id: ... })to.values({ tenantId: ... }) - Update all assertions from
result[0].tenant_idtoresult[0].tenantId
-
Phase 2: High Priority (Fixes 135 errors)
- Effort: 30 minutes
- Add missing schema exports to
src/db/schema/index.ts:export * from './curriculum'; // cefrDescriptors, lessonPlans, materials export * from './system'; // auditLogs, invoices, conversations, exports
-
Phase 3: Medium Priority (Fixes 81 errors)
- Effort: 2 hours
- Update all API routes to async params pattern (Next.js 15)
- Replace
anytypes with proper TypeScript types - Fix MCP server column name issues
-
Phase 4: Low Priority (Fixes 108 errors)
- Effort: 1-2 hours
- Clean up unused variables/imports
- Fix React unescaped entities
- Add ESLint disable comments for intentional CommonJS usage
Total Estimated Effort: 6-8 hours to clear all 562 errors Quick Win: Phase 1 + 2 = 3.5 hours to fix 373 errors (66% of total)
Status: Shelved (unlikely to be required for MVP or beyond)
Original Proposal:
- Automated email notifications for visa expiry alerts
- Send emails to admins when student visas are 30/90 days from expiry or expired
- Scheduled daily cron job to check and send alerts
Why Shelved:
- Dashboard suffices: Task 1.4 visa tracking dashboard (
/admin/visa) provides real-time visibility - Infrastructure overhead: Requires email service (Resend/Nodemailer/SendGrid), cron scheduler, API keys, templates
- Usage uncertainty: Unclear if automated emails are actually needed vs. periodic dashboard checks
- Complexity vs. value: 60-90 minutes implementation for potentially low-value feature
- Better alternatives: If notifications needed later, consider:
- Manual "Send Alert" button on dashboard (5 min implementation)
- Browser notifications / in-app alerts
- Integrate with unified notification system post-MVP
Technical Requirements (if ever implemented):
- Email service provider (Resend recommended)
- Email templates (React Email)
- Cron scheduler (Vercel Cron or external service)
- Database: admin notification preferences table
- Estimated effort: 60-90 minutes
Decision Date: 2026-01-15 Rationale: Focus MVP development on core features. Dashboard provides sufficient visibility. Email infrastructure can be added later if usage patterns prove it's needed.
Note: If visa compliance requires documented notifications, reconsider as Task 1.4.2 post-MVP.
-
snake_case vs camelCase in Drizzle ORM (190+ errors)
- Issue: Test files and some production code use snake_case property names (
tenant_id,student_id,class_id) instead of Drizzle's camelCase properties (tenantId,studentId,classId) - Root cause: Drizzle ORM schema defines TypeScript properties in camelCase but maps to snake_case PostgreSQL columns automatically. Code must use camelCase when accessing schema properties.
- Example fix:
// WRONG: await db.insert(users).values({ tenant_id: '...', role: 'admin' }) expect(result[0].tenant_id).toBe(tenantId) // CORRECT: await db.insert(users).values({ tenantId: '...', primaryRole: 'admin' }) expect(result[0].tenantId).toBe(tenantId)
- Affected files:
rls-policies.test.ts, test files in__tests__/folders, seed scripts
- Issue: Test files and some production code use snake_case property names (
-
Next.js 15 async params pattern in tests (100+ errors)
- Issue: Test mocks use synchronous params
{ params: { id: string } }but Next.js 15 routes expect async{ params: Promise<{ id: string }> } - Root cause: Next.js 15 made route handler params async. Tests need to mock this correctly.
- Example fix:
// WRONG: const mockParams = { params: { id: 'test-id' } }; await GET_BY_ID(mockRequest, mockParams); // CORRECT: const mockParams = { params: Promise.resolve({ id: 'test-id' }) }; await GET_BY_ID(mockRequest, mockParams);
- Affected files: All API route test files (
courses.test.ts,enrollments.test.ts,students.test.ts, etc.)
- Issue: Test mocks use synchronous params
- Fixed
rls-policies.test.tssnake_case → camelCase (23 errors) - Fixed query components unknown type issues (8 errors)
- Fixed 6 test files with Promise.resolve params pattern (~100 errors)
- Fixed
programmes.tsschema snake_case → camelCase - Fixed
teachers/route.ts,users/route.ts,users/[id]/route.tssnake_case issues - Fixed
rooms/route.tsZod 4.xz.record()argument issue - Fixed
students/[id]/route.ts- attendance/grades schema alignment - Fixed
MCP routeserror code type assertions - Fixed form components
erris unknown type issues - Fixed
MCPHost.tssession variable naming - Fixed
db/index.tsconnectionString possibly undefined - Fixed
MCPHostRefactored.tsunknown type issues in .some() callbacks - Fixed
hash-chain.tssnake_case → camelCase for Drizzle compatibility - Fixed
cumulative-lateness.tsmetadata type assertions - Fixed
mcp/capabilities/route.tsarray type assertions - Fixed multiple "Cannot find name 'err'" issues (catch block typos)
- Reduced from 291 → 119 errors (59% reduction, 172 errors fixed)
- Test files: ~100 errors (Jest mock typing, snake_case in hash-chain tests)
- MCP servers: ~8 errors (Drizzle query overload issues)
- Supabase mocks: ~4 errors (middleware.ts, server.ts mock type compatibility)
- Other: ~7 errors (StudentRegistry types, notifications.ts, attendance routes)
- Task 1.2 (Student Detail Page) introduced ZERO new errors ✅
- Task 1.4 (Visa Tracking Dashboard) introduced ZERO new errors ✅
- Task 1.3.1 (Enrollment List Page) introduced ZERO new errors ✅
- New files:
src/app/admin/enrolments/page.tsx,src/components/admin/EnrollmentList.tsx - Properly formatted with Prettier
- Uses camelCase naming conventions
- TypeScript types properly defined
- New files:
- Task 1.3.2 (Enroll Student Form) introduced ZERO new errors ✅
- Enhanced files:
src/components/admin/enrollments/EnrollStudentForm.tsx,src/app/admin/enrolments/enroll/page.tsx - Server-side data fetching (Next.js 15 pattern)
- Success/error state handling
- Capacity validation and empty state handling
- Follows existing code patterns
- All ESLint checks pass for modified files
- Enhanced files:
- All new code follows best practices and passes type checking
- Pre-existing errors are from legacy code and should be addressed separately
- Error count stable at 563 - No increase from development work (+1 is rounding variance)
- Task 1.3.4 (Enrollment Reductions) introduced ZERO new errors ✅
- Fixed typo in
src/components/admin/enrollments/AmendEnrollmentForm.tsx(catch parameter_err→err) - Feature was already fully implemented (reduction tab, API endpoint, validation, audit trail)
- Pre-commit checks revealed:
- 186 ESLint problems (74 errors, 112 warnings) in unrelated files - pre-existing
- 1 failing test in
AttendanceExport.test.tsx- pre-existing from Task 1.4.4 export enhancements - No issues in modified enrollment files
- Updated STATUS.md to 87% complete (52/60 tasks)
- Fixed typo in