refactor: fix all P0/P1/P2 bugs and architecture issues

Bug fixes (from bugs/ directory):

- Fix cross-module DB queries in 9 modules (homework, grades, parent, diagnostic, elective, proctoring, notifications, scheduling, classes) by routing through data-access functions

- Fix shared/lib <-> auth circular dependency via new session.ts module

- Fix divide-by-zero guard in grades data-access

- Fix audit export data truncation (paginated fetch for full datasets)

- Fix missing transactions in homework grading and elective lottery

- Fix missing revalidatePath in course-plans actions

- Fix frontend permission checks using requirePermission instead of requireAuth

- Fix dashboard role routing using session.user.roles

- Fix student auth pattern (migrate getDemoStudentUser to users module)

- Fix ActionState return type handling in components

Code quality fixes:

- Remove 60+ as type assertions (replace with type guards)

- Remove non-null assertions (use optional chaining or explicit checks)

- Convert dynamic imports to static imports (grades, diagnostic)

- Add React.cache() wrapping for read functions

- Parallelize independent queries with Promise.all

- Add explicit return types to 30+ arrow functions

- Replace any with unknown + type guards

- Fix import type for type-only imports

- Add Zod validation schemas for classes and diagnostic modules

- Extract duplicate code (normalizeRoleName, normalizeBcryptHash, logger IP extraction)

- Add console.error to silent catch blocks

- Fix permission naming consistency (exam:proctor_read -> exam:proctor:read)

Architecture doc sync:

- Update 004_architecture_impact_map.md and 005_architecture_data.json

- Update management-modules-audit.md for P0-7 cross-module fix

Moved deleted proctoring event route to deletes/ folder.
This commit is contained in:
SpecialX
2026-06-19 05:13:09 +08:00
parent 063baffe4c
commit 49291fcc31
114 changed files with 12548 additions and 3395 deletions

View File

@@ -239,6 +239,7 @@ export async function deleteCoursePlanItemAction(
try {
await requirePermission(Permissions.COURSE_PLAN_MANAGE)
await deleteCoursePlanItem(id)
revalidatePlanPaths()
return { success: true, message: "Week plan deleted" }
} catch (e) {
return handleError(e)
@@ -255,6 +256,7 @@ export async function toggleCoursePlanItemCompletedAction(
isCompleted: completed,
completedAt: completed ? new Date().toISOString().slice(0, 10) : null,
})
revalidatePlanPaths()
return {
success: true,
message: completed ? "Marked as completed" : "Marked as incomplete",

View File

@@ -146,7 +146,7 @@ export const getCoursePlans = cache(
if (params?.teacherId) conditions.push(eq(coursePlans.teacherId, params.teacherId))
if (params?.subjectId) conditions.push(eq(coursePlans.subjectId, params.subjectId))
if (params?.status)
conditions.push(eq(coursePlans.status, params.status as CoursePlanStatus))
conditions.push(eq(coursePlans.status, params.status))
const query = buildPlanSelect()
const rows = await (conditions.length > 0
@@ -155,7 +155,8 @@ export const getCoursePlans = cache(
).orderBy(desc(coursePlans.createdAt))
return rows.map(mapPlanRow)
} catch {
} catch (error) {
console.error("getCoursePlans failed:", error)
return []
}
}
@@ -180,7 +181,8 @@ export const getCoursePlanById = cache(
...mapPlanRow(planRow),
items: itemRows.map(mapItemRow),
}
} catch {
} catch (error) {
console.error("getCoursePlanById failed:", error)
return null
}
}
@@ -314,7 +316,8 @@ export const getSubjectOptions = cache(async (): Promise<{ id: string; name: str
.from(subjects)
.orderBy(asc(subjects.order), asc(subjects.name))
return rows.map((r) => ({ id: r.id, name: r.name }))
} catch {
} catch (error) {
console.error("getSubjectOptions failed:", error)
return []
}
})