Files
schulos/REFACTOR_PLAN.md
T

12 KiB
Raw Blame History

ExaMetra Refactor Action Plan

PRD v1 → v2 → Production Ready

Current State Analysis:

  • 70+ view components
  • 100+ API routes
  • Estimated 40% code duplication
  • 4 major PRD v2 modules not implemented
  • Multiple memory leak patterns (detected but mostly fixed)

Phase 1: Quick Wins (Week 1)

1.1 Implement Centralized API Fetching Hook

File: src/hooks/use-api.ts

Replace the 60+ identical fetch patterns with SWR:

// Before: Repeated in every component
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
  fetch(`/api/xyz`)
    .then(r => r.json())
    .then(d => setData(d))
    .catch(e => setError(e))
    .finally(() => setLoading(false));
}, []);

// After: Single hook in 60+ places
const { data, isLoading, error, mutate } = useApi('/api/xyz');

Impact: Reduces component code by 30%, fixes data sync issues, enables optimistic updates.

Affected Files: 60+ components


1.2 Extract Reusable UI Components

src/components/ui/data-table.tsx

Used in: analytics, attendance, competitions, behavior-tracking, grade-analytics

  • Sorting, filtering, pagination
  • Configurable columns
  • Batch actions

src/components/forms/form-builder.tsx

Used in: student entry, grade entry, assessment creation, subject management

  • Schema-driven validation
  • Reusable field types
  • Error handling

src/components/dialogs/confirm-dialog.tsx

Used in: 12+ places (delete confirmations, cancel actions)

  • Consistent styling
  • Accessibility
  • Custom actions

Impact: Eliminates 25+ duplicate component implementations.


1.3 Standardize API Response Format

Current inconsistency: Some routes return { data: [...] }, others return bare array

Standard format:

{
  "success": true,
  "data": [...],
  "error": null,
  "pagination": {
    "total": 100,
    "limit": 20,
    "offset": 0
  }
}

Create middleware: src/lib/api-response.ts

Impact: Simplifies error handling, enables consistent pagination, better client-side caching.


1.4 Create API Route Middleware

Problem: Every route duplicates:

const session = await getSession();
if (!session?.user?.id) return unauthorized();
await logAudit(session.user.id, action);

Solution: Higher-order middleware wrapper

// Before
export async function GET(req: Request) {
  const session = await getSession();
  if (!session?.user?.id) return unauthorized();
  // 50+ lines of actual logic
  await logAudit(...);
}

// After
export const GET = withAuth(withAudit(async (req, context) => {
  // Just the business logic
  const data = await db.xyz.findMany();
  return apiResponse(data);
}));

Affected: All 100+ API routes

Impact: Reduces average route size by 40%, eliminates repeated auth/audit code.


Phase 2: Fix Architectural Issues (Weeks 2-3)

2.1 Consolidate Grading Logic

Current duplication: 3 implementations

  • src/components/grading-view.tsx — Main grading UI
  • src/components/tablet-grading-view.tsx — Tablet variant
  • src/components/grade-analytics-view.tsx — Analytics view

Problem: Logic inconsistencies, hard to maintain

Solution:

  1. Extract grading engine → src/lib/grading-engine.ts

    • Pure functions for grade computation
    • Unit tested
    • Reusable everywhere
  2. Create UI layer → src/components/grading/

    • GradingForm.tsx — Input component (reusable)
    • GradingView.tsx — Desktop view (uses GradingForm)
    • TabletGradingView.tsx — Tablet view (uses GradingForm + responsive)
    • GradeAnalytics.tsx — Analytics (uses grading-engine)

Impact: Single source of truth for grading logic, easier to test, consistent across UI.


2.2 Unify Assessment Creation

Current duplication: 3 implementations

  • assessments-view.tsx — Standard assessments
  • ai-tests-view.tsx — AI-generated tests
  • exam-calendar-view.tsx — Exam scheduling + creation

Solution:

  1. Create AssessmentForm.tsx — Reusable form component
  2. Create AssessmentType.tsx — Form variant selector (standard/AI-generated/exam)
  3. Refactor views to use form component

2.3 Implement Single Competency Renderer

Current duplication: 4 implementations

  • competence-flower-view.tsx — Radar chart
  • competency-grid-view.tsx — Grid view
  • mastery-matrix-view.tsx — Matrix view (duplicate of above)
  • curriculum-coverage-view.tsx — Coverage view

Solution:

// New component with configurable layout
<CompetencyViewer
  layout="flower"  // or "grid" or "matrix" or "coverage"
  competencies={competencies}
  config={config}
/>

Impact: Single source of truth for competency data rendering.


2.4 Unify Calendar Implementations

Current: 3 separate calendar components

  • calendar-view.tsx — General calendar
  • exam-calendar-view.tsx — Exam-specific calendar
  • lesson-plans-view.tsx — Lesson scheduling calendar

Solution: Single calendar with event type filtering

<Calendar
  events={allEvents}
  eventTypeFilters={['lesson', 'exam', 'deadline']}
  config={config}
/>

Phase 3: Implement Missing PRD v2 Modules (Weeks 4-6)

3.1 Module B — Digital Signage (Emergency Alerts, TV Displays)

Required tables:

  • SignageDisplay — Physical displays
  • SignageSlide — Content slides
  • SignagePlaylist — Rotation config
  • EmergencyAlert — Alert system

Implementation:

  1. Create admin interface: /admin/signage/displays, /admin/signage/slides
  2. Create display client: /signage/display/[displayId] (fullscreen kiosk)
  3. Create push notifications for emergency alerts (integrate with Module H)
  4. Add approval workflow for teacher-submitted slides

Safety requirement: Emergency alerts must override all displays immediately with push notification to staff.

Effort: 4–5 days

Files to create:

  • src/app/admin/signage/ — Admin pages
  • src/app/signage/display/ — Display client
  • src/components/signage/ — Reusable components
  • src/lib/signage-engine.ts — Rotation logic

3.2 Module H — Centralized Notifications

Required tables:

  • Notification — Unified notification model
  • NotificationPreference — Per-user settings
  • NotificationSubscription — Service worker subscriptions

Implementation:

  1. Create Notification model unified for all alert types
  2. Implement service worker + Web Push API
  3. Create notification center UI: /notifications
  4. Add real-time delivery via WebSocket
  5. Refactor all modules to emit into this system instead of creating own alerts

Current alerts to consolidate:

  • Exam warnings (from exam-calendar-view)
  • Messages (from communication-view)
  • System alerts (scattered)
  • Signage emergencies (new from Module B)

Effort: 3–4 days

Files to create:

  • src/app/api/notifications/ — Notification API
  • src/app/api/push-subscriptions/ — Web Push setup
  • src/components/notification-center.tsx
  • src/lib/notification-engine.ts
  • src/lib/push-service-worker.ts

3.3 Module J — Dashboard Widget System (Customizable Home)

Current issue: Dashboard monolithic (241KB), not reusable per spec

Required tables:

  • DashboardWidget — Widget definitions
  • UserDashboardPreference — Per-user layout
  • WidgetData — Cached widget data (optional)

Implementation:

  1. Create widget registry system
  2. Create Widget wrapper component (read-only data consumer)
  3. Create customization UI: /dashboard/customize
  4. Refactor dashboard-view.tsx to use widget system
  5. Make dashboard widgets available elsewhere (student portal, parent portal)

Widgets to create (examples):

  • AttendanceWidget — Pulls from canonical attendance data
  • UpcomingExamsWidget — Pulls from calendar
  • GradeWidget — Pulls from grading system
  • RecentActivitiesWidget — Pulls from audit log
  • WeatherWidget — Optional external data

Each widget must:

  • Fetch from single canonical source (no duplication)
  • Be read-only in dashboard context
  • Have configurable options (hidden by user preference)
  • Load independently with skeleton state

Effort: 2–3 days

Files to create:

  • src/components/dashboard-widgets/ — Widget implementations
  • src/app/dashboard/customize/ — Customization page
  • src/lib/widget-registry.ts — Widget system

3.4 Module F — Exam Mode (Kiosk Lockdown + Proctoring)

Required tables:

  • ExamSession — Active exam session
  • ExamWarning — Warning log
  • ExamIncidentEvent — Incident tracking

Implementation:

  1. Create ExamSession model + lifecycle (started → paused → resumed → ended)
  2. Implement fullscreen kiosk UI: /exam/[sessionId]
  3. Add browser-level lockdown:
    • Service worker intercepts navigation
    • Fullscreen API lock
    • Tab/window switching detection
  4. Create teacher control panel: /exam/monitor
  5. Implement warning system (3-strike auto-pause)
  6. Add bathroom request flow + distress signal
  7. Create incident logging + parent visibility

Safety requirements:

  • Bathroom requests pause only that student's session
  • Distress signal triggers immediate teacher alert
  • 3rd warning auto-pauses (not teacher-initiated)
  • All incidents logged for audit trail

Effort: 5–6 days (complex client-side security)

Files to create:

  • src/app/exam/[sessionId]/ — Kiosk page
  • src/app/exam/monitor/ — Teacher control panel
  • src/components/exam-mode/ — Exam UI components
  • src/lib/exam-lockdown.ts — Kiosk logic
  • src/lib/service-worker-exam.ts — Browser lockdown

Phase 4: Consolidate Duplicates (Weeks 7-8)

After Phases 1-3, apply architectural changes:

  1. Merge grading implementations → Single engine + UI variants
  2. Merge assessment creation → Unified form component
  3. Merge competency renderers → Configurable component
  4. Merge calendar implementations → Single calendar with filters
  5. Delete 12+ duplicate utility functions → Use shared lib

Result: Code reduction 30-40%.


Phase 5: Configuration & Compliance (Week 9)

5.1 Database Configuration System

Migrate hardcoded values to database:

Create SystemConfig table:

{
  key: string (PK),
  value: string | number | boolean | JSON,
  description: string,
  editable: boolean,
  schoolId: string? (null = system-wide)
}

Migrate:

  • Escalation wait period: "3 business days" → Config["escalation.wait_days"]
  • Grading scales: hardcoded 1–6 → configurable per school
  • Mastery levels: hardcoded 4 levels → configurable
  • Report templates: hardcoded phrases → DB-driven

Effort: 2 days


5.2 Role-Based Permission UI

Implement UI-level permission checks:

// Before: Just hidden, not prevented
{userRole === 'ADMIN' && <AdminButton />}

// After: Proper permission check
<ProtectedFeature feature="admin.grading" fallback={<LockedIcon />}>
  <AdminButton />
</ProtectedFeature>

Effort: 1 day


Timeline Summary

Phase Duration Completion
Phase 1 (Quick Wins) 1 week Reduce duplication by 30%
Phase 2 (Architecture) 2 weeks Consolidate major duplicates
Phase 3 (Missing Modules) 3 weeks Implement B, H, J, F
Phase 4 (Consolidation) 1 week Final cleanup
Phase 5 (Config) 1 week Database config system
Total ~9 weeks Production ready

Immediate Next Steps

  1. Create use-api.ts hook — Replace 60+ fetch patterns
  2. Extract DataTable, FormBuilder, ConfirmDialog — Eliminate 25+ duplicates
  3. Standardize API responses — Middleware wrapper
  4. Start Module B (Signage) — Critical safety feature

Success Metrics

  • Codebase reduced by 30% (duplication eliminated)
  • All 11 PRD v2 modules implemented
  • Zero memory leaks (verified with Chrome DevTools)
  • All API responses standardized
  • Role-based permissions enforced UI + backend
  • Configuration system working
  • Dashboard customization working
  • Emergency alert system tested
  • Exam mode kiosk tested
  • Full test coverage for critical paths (>80%)