Starter Docs

Product System Design

Product architecture, data model, services, and security model.

Last updated: 2026-05-21

Status: working architecture blueprint. This is the target design for turning the current starter monorepo into the product described in the portfolio/spec notes: a mobile-first trust engine for schools, starting with smart attendance and growing into an AI-first operating system.

Inputs Read

Product inputs:

  • /home/shabir/Documents/Portfolio/School Management OS.md
  • /home/shabir/Documents/Portfolio/School Management OS - Spec.md
  • /home/shabir/Documents/Starter AI-First Smart System README.md

Repo inputs:

  • README.md, PROJECT.md, AGENTS.md, DESIGN.md
  • /docs/ai-first-workflow
  • /docs/architecture
  • /docs/architecture/adr-0001-strong-default-overridable
  • App code in apps/web, apps/mobile, apps/nest-api, apps/docs, and apps/rust
  • Installed Next.js docs under apps/web/node_modules/next/dist/docs/

External research was refreshed on 2026-05-21. References are listed at the end.

Executive Direction

Starter should be built as a secure modular monolith first, with event-driven seams and clear module boundaries, then split into independent services only when load, team ownership, or compliance pressure justifies it.

The highest-value product loop is:

Student arrives -> attendance event -> parent alert -> live dashboard -> AI risk/update signal

The safest engineering loop is:

Write source-of-truth change in Postgres
-> write outbox event in same transaction
-> worker delivers notifications, realtime updates, AI jobs, and analytics
-> every side effect is idempotent and auditable

Day one should not run Postgres, MySQL, Kafka, Redis, multiple API frameworks, and AI services as equal peers. That would add distributed-system cost before the product has stable workflows. The best initial production stack is:

  • Next.js web dashboard.
  • Expo mobile app for parents, teachers, guards, and bus conductors.
  • Hono API as the primary product API.
  • Postgres as the only source-of-truth database.
  • Redis for cache, rate limits, short-lived locks, and lightweight queues.
  • A worker process for outbox delivery, scheduled jobs, reminders, and AI pipelines.
  • S3-compatible object storage for files, report cards, receipts, and media.
  • Optional FastAPI AI service once model workflows need Python ML libraries.
  • Kafka or Redpanda later, only after multiple independent consumers need durable event streams.

Product Boundaries

Starter is not a full ERP, LMS content marketplace, social network, or accounting system. It is a school trust, communication, attendance, operations, finance, and intelligence platform.

Primary personas:

PersonaPrimary surfaceCore need
School owner/principalWeb dashboard, mobile summariesTrust, admissions, finance, risk visibility
Admin staffWeb dashboardFees, admissions, documents, parent follow-ups
TeacherMobile first, web secondaryAttendance, homework, grading, parent communication
Gate guardMobile scannerFast and reliable arrival/departure scan
Bus conductorMobile scanner + GPSBus check-in/out and route safety
Parent/guardianMobile app + WhatsAppChild safety, homework, fees, communication
StudentMobile/web laterTimetable, homework, feedback

High-Level Architecture

                    +----------------------+
                    |   apps/docs          |
                    |   product docs       |
                    +----------+-----------+
                               |
+----------------+     +-------v--------+      +------------------+
| apps/web       |     | apps/hono-api  |      | apps/mobile      |
| Next dashboard |<--->| Product API    |<---->| Expo app         |
+----------------+     +-------+--------+      +------------------+
                               |
               +---------------+----------------+
               |                                |
       +-------v--------+              +--------v---------+
       | Postgres       |              | Redis            |
       | source of truth|              | cache/locks/jobs |
       +-------+--------+

			  +--------+---------+
               |                                |
       +-------v-------------------------------v---------+
       | Worker runtime                                  |
       | outbox, schedules, notifications, AI jobs        |
       +---+------------+----------------+----------------+
           |            |                |
   +-------v--+  +------v------+  +------v------+  +----------------+
   | WhatsApp |  | Email/SMS   |  | Payments    |  | Object storage |
   | provider |  | providers   |  | gateway     |  | S3/R2          |
   +----------+  +-------------+  +-------------+  +----------------+

Later:
  apps/fastapi AI service, Kafka/Redpanda event bus, dedicated realtime gateway.

Service Design

Stage 1: MVP Production Services

RuntimeRepo locationResponsibilityNotes
Web appapps/webPrincipal/admin/teacher web workflowsKeep route composition in src/app, feature UI in src/modules
Mobile appapps/mobileParent, teacher, guard, bus workflowsUse role-specific route groups and secure token storage
Product APIapps/hono-apiAuth, tenancy, domain APIs, webhooksPrimary backend for production
Workerapps/hono-api/src/workersOutbox, reminders, notification dispatch, AI jobsSame codebase at first to avoid a premature service split
Docs appapps/docsInternal/product docsPublish architecture and API docs here later
PostgresDocker/cloud managedPrimary data storeTenant-scoped relational source of truth
RedisDocker/cloud managedCache, rate limit, locks, queue bufferNever source of truth for business records
Object storageS3/R2Files, PDFs, mediaPrivate buckets, signed URLs only

Stage 2: Services To Split Only When Needed

ServiceWhen to splitResponsibility
AI servicePython ML/RAG workflows become non-trivialFeature computation, model calls, scoring, RAG, evals
Notification serviceWhatsApp/SMS/email volume growsProvider routing, retries, templates, delivery status
Realtime gatewayLive dashboard/bus tracking gets high trafficWebSocket/SSE fanout
Analytics serviceReports affect API latencyMaterialized rollups, cohort reports, BI exports
Import/integration serviceMany schools import legacy dataCSV/Excel/SIS connectors, MySQL import adapters

Stage 3: Microservice Candidates

Only split after clear operational pressure:

  • identity-service: users, sessions, memberships, roles, permissions.
  • attendance-service: attendance sessions, scans, daily summaries.
  • communication-service: announcements, chat, notification commands.
  • finance-service: invoices, payments, ledger, receipts.
  • academics-service: timetable, homework, assessments, report cards.
  • transport-service: routes, trips, locations, bus attendance.
  • ai-intelligence-service: student profiles, risk signals, actions, agent runs.

Until then, keep them as modules inside apps/hono-api/src/modules.

Internal Communication

Synchronous Calls

Use HTTP JSON for direct request/response flows:

  • Browser/mobile -> Hono API.
  • Hono API -> payment provider, WhatsApp provider, map provider, object storage.
  • Hono API -> FastAPI AI service later, only through a typed internal client.

Rules:

  • Every request has x-request-id.
  • Authenticated requests derive tenantId, userId, and role from the session, not from the body.
  • Service-to-service calls use service JWTs or mTLS once split.
  • Public contracts use OpenAPI. TypeScript internal clients may use Hono RPC where useful.

Asynchronous Events

Start with a transactional outbox table in Postgres:

domain write + outbox_events insert in one transaction
worker polls pending outbox events
worker marks processing/sent/failed with retry count
consumer side effects use idempotency keys

This is enough for the MVP and protects against lost notifications without Kafka.

Add Kafka/Redpanda when all are true:

  • More than two independent consumers need the same events.
  • Replaying historical events becomes useful.
  • Worker polling becomes a bottleneck.
  • Analytics, AI, notification, and audit pipelines need independent scaling.

Kafka does not remove the need for idempotency. External APIs such as WhatsApp, SMS, email, and payment providers are still at-least-once from our perspective.

Database Strategy

Primary Decision

Use Postgres as the only source-of-truth database.

Do not add MySQL as a second operational database for the core product. It increases migration, query, backup, consistency, and team complexity without improving the MVP. Use MySQL only as an integration target/source when a school or acquirer has legacy MySQL data.

Use Redis as cache and coordination, not as a database for records that must survive or be audited.

Use pgvector in Postgres for early AI/RAG search. Move to a dedicated vector database only if Postgres vector indexes cannot meet recall, latency, memory, or filtering requirements.

Tenancy Model

Use a shared Postgres database and shared tables with tenant_id on every tenant-owned table.

Why:

  • Affordable private schools are small to mid-size.
  • Shared tables simplify migrations and cross-tenant product analytics.
  • Tenant isolation can be enforced with app authorization and Postgres row-level security.
  • Enterprise isolation can still be offered later with dedicated DB/schema deployments.

Tenant rules:

  • Every business table has tenant_id.
  • Every query includes tenant scope at the repository layer.
  • Postgres Row Level Security should be enabled for high-risk tables before production.
  • tenant_id from the client body is ignored for authenticated writes.
  • Cross-tenant admin access requires explicit platform role and audit trail.

Shared Columns

Most tenant-owned tables should have:

ColumnTypeNotes
idUUID or stable text IDPrefer one standard ID generator before production
tenant_idUUID/text FKRequired for tenant-owned records
created_attimestamptzDefault now
updated_attimestamptzUpdated on mutation
created_byuser FK nullableNull for system imports/jobs
updated_byuser FK nullableNull for system imports/jobs
deleted_attimestamptz nullableSoft delete for business records

Hard-delete only ephemeral records such as expired verification codes, sessions, temporary files, and completed idempotency keys after retention.

Core Database Tables

This is a product-level data model, not a final Prisma migration. Final schema should be added in bounded modules with tests.

Identity, Tenancy, And Authorization

TablePurposeKey columns and constraints
tenantsOne school organization or chainid, name, slug unique, status, timezone, default_locale
campusesPhysical campuses under a tenanttenant_id, name, address, geo_lat, geo_lng
academic_yearsSchool year boundarytenant_id, name, starts_on, ends_on, unique active year
termsAcademic termstenant_id, academic_year_id, name, dates
usersLogin identityExisting table, add phone, status, last_login_at later
user_profilesPerson-specific profile datauser_id, display_name, avatar_file_id, locale
membershipsUser access to tenant/campustenant_id, user_id, campus_id nullable, status; unique active membership
rolesTenant role definitionstenant_id nullable, code, name; platform defaults plus tenant custom roles
permissionsPermission catalogcode unique, module, description
role_permissionsPermission assignmentrole_id, permission_id; unique pair
membership_rolesRole assignmentmembership_id, role_id; unique pair
sessionsAuth sessionsExisting table; add device metadata, IP hash, revoked_at
verification_codesEmail, reset, 2FA codesExisting table; TTL cleanup
consentsParent/school consent recordstenant_id, subject_type, subject_id, purpose, status, source

Authorization model:

  • RBAC for coarse permissions.
  • ABAC for record-level checks: teacher sees assigned sections, parent sees linked students, conductor sees assigned route, principal sees campus/tenant.
  • Policy files live beside each module: attendance.policy.ts, finance.policy.ts, etc.

People And School Structure

TablePurposeKey columns and constraints
studentsStudent profiletenant_id, campus_id, student_code, names, dob, gender, status; unique (tenant_id, student_code)
guardiansParent/guardian persontenant_id, names, phone, email, preferred_channel
student_guardiansLink students to guardiansstudent_id, guardian_id, relationship, can_pickup, is_primary; unique pair
staffTeachers/admin/guards/driverstenant_id, user_id nullable, employee_code, role_type, status
classesGrade leveltenant_id, name, sort_order
sectionsClass sectiontenant_id, class_id, academic_year_id, name, homeroom_teacher_id
enrollmentsStudent in section/yeartenant_id, student_id, section_id, academic_year_id, status; unique active enrollment
subjectsSubject catalogtenant_id, code, name
section_subjectsSubject taught in sectionsection_id, subject_id, teacher_staff_id

Attendance

TablePurposeKey columns and constraints
attendance_sessionsDaily/class/gate/bus attendance windowtenant_id, session_type, section_id nullable, campus_id, date, starts_at, ends_at
attendance_marksCurrent attendance state per student/sessiontenant_id, session_id, student_id, status, marked_at, marked_by, unique (session_id, student_id)
attendance_eventsAppend-only scan/status event logtenant_id, session_id, student_id, event_type, source, source_event_id, unique source id
attendance_daily_summariesDashboard counterstenant_id, campus_id, date, counts, generated_at
student_qr_tokensRotating QR token metadatatenant_id, student_id, token_hash, expires_at, revoked_at
attendance_exceptionsManual correctionstenant_id, mark_id, reason, approved_by, audit fields

Statuses:

  • present, absent, late, excused, left_early, unknown.

Event types:

  • arrival_scanned, departure_scanned, manual_marked, absence_detected, parent_confirmed_absence, correction_approved.

Communication And Notifications

TablePurposeKey columns and constraints
notification_templatesWhatsApp/SMS/email/push templatestenant_id nullable, channel, code, locale, provider_template_id
notificationsLogical notification commandtenant_id, audience_type, priority, template_code, status
notification_deliveriesPer-recipient delivery attemptsnotification_id, recipient_type, recipient_id, channel, status, provider_message_id, idempotency key
announcementsSchool/class announcementstenant_id, author_user_id, audience, title, body, priority, published_at
conversationsTeacher-parent/admin chat threadstenant_id, conversation_type, student_id nullable, status
conversation_participantsChat participantsconversation_id, user_id, role
messagesChat messagestenant_id, conversation_id, sender_user_id, body, status
message_attachmentsFiles attached to messagesmessage_id, file_id
calendar_eventsEvents, PTMs, exams, reminderstenant_id, title, starts_at, ends_at, audience

Academics

TablePurposeKey columns and constraints
timetable_slotsRecurring timetable slotstenant_id, section_id, subject_id, teacher_staff_id, weekday, times
substitutionsTeacher substitutionslot_id, original_teacher_id, substitute_teacher_id, date
homework_assignmentsHomework assigned by teachertenant_id, section_subject_id, title, due_at, status
homework_recipientsStudent-specific assignment varianthomework_id, student_id, variant_level, status
homework_submissionsStudent submissionhomework_id, student_id, submitted_at, status, score
assessmentsExams/quizzes/micro-assessmentstenant_id, section_subject_id, type, title, date
assessment_itemsQuestions/conceptsassessment_id, concept_id, max_score
assessment_resultsScores per student/itemassessment_id, student_id, item_id, score
conceptsLearning concept maptenant_id, subject_id, name, parent_concept_id
student_concept_masteryLive learning gap datatenant_id, student_id, concept_id, mastery_score, confidence
report_cardsGenerated term reportstenant_id, student_id, term_id, status, file_id
report_card_commentsTeacher/AI commentsreport_card_id, subject_id nullable, author_type, body, approval status

Finance And Admin

TablePurposeKey columns and constraints
fee_plansFee structuretenant_id, name, academic_year_id, class/section scope
fee_componentsTuition, transport, exam, etc.fee_plan_id, name, amount, frequency
student_fee_assignmentsFee plan assigned to studentstudent_id, fee_plan_id, effective dates
invoicesAmount duetenant_id, student_id, invoice_no, due_on, status, unique invoice number
invoice_linesInvoice detailinvoice_id, fee_component_id, amount, discount
paymentsProvider payment recordtenant_id, student_id, provider, amount, status, provider_payment_id unique
payment_allocationsPayment applied to invoice linespayment_id, invoice_line_id, amount
ledger_entriesAppend-only finance ledgertenant_id, entry_type, amount, currency, source_type, source_id
receiptsGenerated receiptspayment_id, receipt_no, file_id
admission_leadsAdmissions CRMtenant_id, lead contact, source, stage, score, assigned_to
lead_interactionsFollow-upslead_id, channel, notes, next_follow_up_at

Finance rules:

  • Payments are append-only; corrections use adjustment entries.
  • Verify payment webhooks with provider signatures.
  • Use idempotency keys for all payment create/capture/webhook flows.
  • Do not store card data.

Transport

TablePurposeKey columns and constraints
transport_routesBus routetenant_id, name, campus_id, status
vehiclesBus/vantenant_id, registration_no, capacity, status
driversDriver profiletenant_id, staff_id, license metadata
bus_stopsStop pointsroute_id, name, sequence, geo_lat, geo_lng
student_transport_assignmentsStudent to route/stopstudent_id, route_id, stop_id, effective dates
bus_tripsOne route runroute_id, vehicle_id, driver_id, trip_date, direction, status
bus_trip_eventsBoarding/deboarding scantrip_id, student_id, event_type, scanned_at, scanned_by
bus_locationsGPS samplestrip_id, geo_lat, geo_lng, speed, captured_at
eta_predictionsCached ETA per stoptrip_id, stop_id, eta_at, confidence

Location retention should be short. Store detailed GPS samples for operational windows, then roll up or delete according to policy.

AI, Intelligence, And Automation

TablePurposeKey columns and constraints
student_intelligence_profilesCurrent computed profiletenant_id, student_id, scores JSON, generated_at, model_version
student_signalsAtomic facts used by AI/rulestenant_id, student_id, signal_type, severity, occurred_at, source
risk_scoresHistorical score snapshotstenant_id, subject_type, subject_id, score_type, score, reason_codes
ai_actionsHuman-reviewable suggested actionstenant_id, agent_type, title, risk_level, status, reasoning JSON
ai_action_feedbackApproval/rejection/editsai_action_id, reviewer_user_id, decision, feedback
agent_runsAI execution trace metadatatenant_id, agent_type, status, input_hash, output_ref, cost, latency
knowledge_documentsRAG documentstenant_id, file_id, document_type, status
knowledge_chunksSearchable chunksdocument_id, chunk_index, text, embedding vector, metadata
prompt_versionsVersioned system promptsagent_type, version, body, active_from
model_evalsRegression/eval resultsagent_type, dataset_version, model, score, run_at

AI actions never directly change high-risk records without either deterministic policy approval or human review. High-risk records include attendance corrections, finance actions, student risk flags, discipline notes, emergency alerts, and parent-facing academic summaries.

Platform And Operations

TablePurposeKey columns and constraints
filesObject metadatatenant_id, bucket, key, mime, size, checksum, visibility
document_signaturesPermission slips/formsfile_id, signer_user_id, signed_at, ip_hash
audit_logsAppend-only security/business audittenant_id, actor, action, resource, before/after redacted JSON, request_id
outbox_eventsReliable async event stagingtenant_id, event_type, aggregate_type, aggregate_id, payload, status, retries
webhook_eventsProvider webhook inboxprovider, event_id unique, payload, signature_valid, processed_at
idempotency_keysRequest/side-effect idempotencytenant_id, key, scope, request_hash, response_hash, expires_at
rate_limit_bucketsOptional persisted rate-limit statesubject, route, window, count
feature_flagsTenant/platform flagstenant_id nullable, flag, enabled, rules JSON

API Route Design

Expose versioned product APIs under /api/v1. The current /auth/* Hono routes can remain during transition, but new product routes should be versioned.

Response envelope:

{
	"success": true,
	"code": 200,
	"message": "OK",
	"data": {},
	"requestId": "req_..."
}

Error envelope:

{
	"success": false,
	"code": 400,
	"message": "Validation failed",
	"errorCode": "VALIDATION_ERROR",
	"errors": [{ "field": "email", "message": "Invalid email" }],
	"requestId": "req_..."
}

Core Routes

AreaRoutes
HealthGET /health, GET /ready
AuthPOST /api/v1/auth/register, POST /api/v1/auth/login, POST /api/v1/auth/logout, POST /api/v1/auth/refresh, GET /api/v1/auth/me
Sessions/2FAGET /api/v1/auth/sessions, DELETE /api/v1/auth/sessions/:id, POST /api/v1/auth/2fa/setup, POST /api/v1/auth/2fa/enable, POST /api/v1/auth/2fa/disable
TenancyGET /api/v1/tenants/current, PATCH /api/v1/tenants/current, GET /api/v1/campuses, POST /api/v1/campuses
RolesGET /api/v1/roles, POST /api/v1/roles, GET /api/v1/permissions, PUT /api/v1/memberships/:id/roles

Product Routes

AreaRoutes
StudentsGET /api/v1/students, POST /api/v1/students, GET /api/v1/students/:id, PATCH /api/v1/students/:id, GET /api/v1/students/:id/feed
GuardiansGET /api/v1/guardians, POST /api/v1/guardians, PUT /api/v1/students/:id/guardians
StaffGET /api/v1/staff, POST /api/v1/staff, PATCH /api/v1/staff/:id
ClassesGET /api/v1/classes, POST /api/v1/classes, GET /api/v1/sections, POST /api/v1/sections, PUT /api/v1/sections/:id/students
AttendancePOST /api/v1/attendance/sessions, GET /api/v1/attendance/sessions, POST /api/v1/attendance/scan, PUT /api/v1/attendance/marks/:id, GET /api/v1/attendance/daily, GET /api/v1/attendance/reports
CommunicationPOST /api/v1/announcements, GET /api/v1/announcements, POST /api/v1/conversations, GET /api/v1/conversations/:id/messages, POST /api/v1/conversations/:id/messages
NotificationsGET /api/v1/notifications, POST /api/v1/notifications/test, GET /api/v1/notification-deliveries/:id
AcademicsGET /api/v1/timetable, POST /api/v1/homework, GET /api/v1/homework, POST /api/v1/homework/:id/submissions, POST /api/v1/assessments, PUT /api/v1/assessments/:id/results
Report cardsPOST /api/v1/report-cards/generate, GET /api/v1/report-cards, POST /api/v1/report-cards/:id/share
FinanceGET /api/v1/fee-plans, POST /api/v1/fee-plans, GET /api/v1/invoices, POST /api/v1/invoices, POST /api/v1/payments/checkout, POST /api/v1/webhooks/payments/:provider
AdmissionsGET /api/v1/admissions/leads, POST /api/v1/admissions/leads, POST /api/v1/admissions/leads/:id/interactions, PATCH /api/v1/admissions/leads/:id/stage
TransportGET /api/v1/transport/routes, POST /api/v1/transport/routes, POST /api/v1/transport/trips, POST /api/v1/transport/trips/:id/events, POST /api/v1/transport/trips/:id/locations
AIGET /api/v1/ai/briefings/today, GET /api/v1/ai/students/:id/profile, GET /api/v1/ai/actions, POST /api/v1/ai/actions/:id/approve, POST /api/v1/ai/actions/:id/reject, POST /api/v1/ai/chat
FilesPOST /api/v1/files/presign-upload, GET /api/v1/files/:id/download-url, DELETE /api/v1/files/:id
AuditGET /api/v1/audit-logs

Route rules:

  • Use plural nouns for resources.
  • Use path params only for identity, not filters.
  • Use query params for filters: ?sectionId=&date=&status=.
  • Use commands for non-CRUD actions: /approve, /reject, /generate, /share.
  • Every mutating route accepts an optional Idempotency-Key header.
  • Pagination uses cursor-based pagination: ?limit=50&cursor=....

Frontend And Mobile Route Map

Next.js Web

Use App Router route groups:

apps/web/src/app
+-- (public)
|   +-- page.tsx
|   +-- login/page.tsx
|   +-- register/page.tsx
+-- (dashboard)
|   +-- dashboard/page.tsx
|   +-- attendance/page.tsx
|   +-- students/page.tsx
|   +-- communication/page.tsx
|   +-- academics/page.tsx
|   +-- finance/page.tsx
|   +-- transport/page.tsx
|   +-- admissions/page.tsx
|   +-- ai-actions/page.tsx
|   +-- settings/page.tsx
+-- api/...

Next.js guidance from the installed docs supports route groups for organization without changing URLs, route handlers for backend-for-frontend endpoints, and a dedicated data access layer for server-side authorization and minimal DTOs. For Starter, use direct Hono API calls through a small DAL/client and do not pass full database objects into client components.

Expo Mobile

Use role-oriented route groups:

apps/mobile/src/app
+-- (auth)/login.tsx
+-- (teacher)/home.tsx
+-- (teacher)/attendance-scan.tsx
+-- (teacher)/homework.tsx
+-- (parent)/home.tsx
+-- (parent)/children/[studentId].tsx
+-- (parent)/fees.tsx
+-- (parent)/messages.tsx
+-- (guard)/scan.tsx
+-- (bus)/trip.tsx

Mobile storage rules:

  • Store refresh/session handles in expo-secure-store, not plain async storage.
  • Do not treat device storage as the source of truth.
  • Sync write actions through server idempotency keys.
  • Queue offline scans locally with signed scan payloads and expire them quickly.

Event And Kafka Design

Domain Event Names

Use past-tense names for facts:

  • attendance.arrival_scanned.v1
  • attendance.departure_scanned.v1
  • attendance.absence_detected.v1
  • notification.delivery_requested.v1
  • notification.delivery_succeeded.v1
  • finance.invoice_issued.v1
  • finance.payment_received.v1
  • academics.homework_assigned.v1
  • transport.bus_location_recorded.v1
  • ai.student_signal_created.v1
  • ai.action_suggested.v1
  • audit.security_event_recorded.v1

Event envelope:

{
	"eventId": "evt_...",
	"eventType": "attendance.arrival_scanned.v1",
	"occurredAt": "2026-05-21T09:00:00Z",
	"tenantId": "ten_...",
	"actor": { "type": "user", "id": "usr_..." },
	"aggregate": { "type": "student", "id": "stu_..." },
	"requestId": "req_...",
	"payload": {}
}

Kafka Topics Later

If Kafka/Redpanda is introduced:

TopicKeyConsumers
school.attendance.events.v1tenantId:studentIdnotifications, AI, dashboards, audit
school.notification.commands.v1tenantId:recipientIdnotification service
school.notification.deliveries.v1tenantId:notificationIddashboard, audit, analytics
school.finance.events.v1tenantId:studentIdreceipts, AI, ledger analytics
school.transport.locations.v1tenantId:tripIdrealtime, ETA, parent app
school.ai.actions.v1tenantId:actionIdapproval queue, audit
school.audit.events.v1tenantId:resourceIdimmutable audit storage

Partition by tenant plus aggregate when ordering matters. Keep consumers idempotent with unique processed-event records.

Cache, Queue, And Memory Strategy

Use cache-aside for read-heavy data:

Cache keyTTLInvalidated by
tenant:{tenantId}:settings10 minutestenant updated
user:{userId}:memberships5 minutesrole/membership changed
section:{sectionId}:students5 minutesenrollment changed
attendance:{tenantId}:{date}:summary30 secondsattendance event
timetable:{sectionId}:{week}1 hourtimetable/substitution changed
student:{studentId}:profile-summary5 minutesstudent/guardian/AI signal changed

Rules:

  • Do not cache payment mutation results as authority.
  • Do not use write-behind for attendance, finance, or consent records.
  • Use Redis locks only for short critical sections, not long business workflows.
  • Use process memory only for static config, compiled templates, and permission maps with short TTLs.

Core Algorithms

QR Attendance

Use signed, rotating QR payloads:

payload = tenantId + studentId + tokenId + expiresAt + nonce
signature = HMAC(payload, tenantAttendanceSecret)

Rules:

  • QR tokens expire.
  • Do not expose raw student IDs without signature.
  • Scans are idempotent by (session_id, student_id, direction, source_event_id).
  • Late/absent classification is deterministic from bell schedule and grace period.

Attendance State Machine

unknown -> present
unknown -> absent
unknown -> late
present -> left_early
absent -> excused
any -> corrected, with approval/audit

Automated absence job:

for each active attendance session after grace window:
  find enrolled students without present/late mark
  create absence_detected event
  create absence mark
  enqueue parent notification
  update daily summary
  create student signal if pattern threshold reached

Bus ETA

Start simple:

  • Haversine distance from current bus location to ordered stops.
  • Rolling average speed by route segment.
  • Geofence arrival/departure when bus enters/leaves stop radius.

Improve later:

  • Map matching with provider APIs.
  • Kalman smoothing for noisy GPS.
  • Route-specific historical ETA model.

Timetable Scheduling

Phase 1:

  • Manual timetable editor.
  • Deterministic conflict detection: teacher overlap, room overlap, section overlap, working hours.

Phase 2:

  • Constraint solver such as OR-Tools CP-SAT for auto-scheduling.
  • Hard constraints: teacher availability, class hours, room capacity, subject frequency.
  • Soft constraints: avoid teacher overload, distribute hard subjects, minimize gaps.

Student Intelligence Score

Start with explainable deterministic scoring, not black-box prediction.

Inputs:

  • Attendance trend.
  • Late frequency.
  • Homework completion.
  • Assessment trajectory.
  • Concept mastery decline.
  • Parent engagement.
  • Fee stress signal, used carefully and never as an academic punishment.
  • Behavior notes.

Output:

{
	"studentId": "stu_...",
	"lifeScore": 84,
	"attendanceRisk": "medium",
	"learningRisk": "low",
	"parentEngagement": 72,
	"reasonCodes": [
		"absent_2_mondays_in_4_weeks",
		"math_score_declined_12_percent"
	],
	"confidence": 0.74
}

Principles:

  • Show reason codes.
  • Track score version.
  • Allow human feedback.
  • Monitor false positives.
  • Do not use risk score as punishment or exclusion.

Notification Routing

Algorithm:

choose channel from priority + consent + parent preference + message urgency
dedupe by recipient + template + aggregate + time window
send through provider
retry with exponential backoff
fail over channel when allowed
record provider status

Priority order:

  • Emergency: app push + WhatsApp + SMS, with admin confirmation.
  • Attendance safety: WhatsApp first, SMS fallback.
  • Finance: WhatsApp/email, payment link signed and expiring.
  • General announcements: app push + WhatsApp/email based on preference.

Parent Channel Preference

Phase 1:

  • Rule-based preference from explicit settings and recent response history.

Phase 2:

  • Thompson sampling or another conservative multi-armed bandit for send-time/channel choice.
  • Optimize response probability, not pressure.
  • Respect consent and quiet hours.

AI And RAG

Use AI as a supervised assistant:

  • Generate report card comments for teacher approval.
  • Draft parent messages.
  • Summarize daily/Friday briefings.
  • Explain student risk signals.
  • Generate homework/test variants from approved curriculum context.
  • Answer parent questions only from tenant-approved knowledge.

Implementation:

  • Use structured outputs for any AI result consumed by code.
  • Use tenant-filtered retrieval from Postgres/pgvector.
  • Store prompt versions and model versions.
  • Run evals before changing prompts/models.
  • Use human approval for high-risk actions.

RAG retrieval:

query -> tenant filter -> vector search -> permission filter -> rerank -> answer with citations

Do not let AI tools call unrestricted product APIs. Each tool must have:

  • A typed schema.
  • Permission checks.
  • Tenant scope.
  • Rate limits.
  • Audit logging.
  • Dry-run mode for sensitive actions.

Security And Privacy Design

Starter handles minors, location, attendance, education records, parent contact data, and payment events. Treat it as high-sensitivity software from the start.

Security Baseline

AreaRequired design
AuthenticationPasswords/passkeys, email verification, TOTP/WebAuthn for admins, session revocation
Password storageArgon2id preferred or bcrypt with reviewed cost; breached password screening before production
SessionsHttpOnly, Secure, SameSite cookies; no production auth tokens in localStorage
CSRFCSRF token or signed double-submit cookie plus origin/fetch metadata checks for cookie APIs
AuthorizationRBAC + ABAC + object-level checks in every service method
Tenant isolationRepository tenant scope plus Postgres RLS on high-risk tables
Input validationZod schemas at route boundary; reject unknown dangerous fields
Output filteringDTOs only; never return raw ORM rows to clients
Rate limitingPer IP, account, tenant, and route group
Security headersCSP, frame denial, HSTS, no x-powered-by, strict CORS allowlist
SecretsEnvironment/KMS, never checked in, rotated provider credentials
FilesPrivate object storage, signed URLs, MIME validation, malware scan later
WebhooksSignature verification, idempotency, replay window
AuditAppend-only audit for auth, permissions, attendance corrections, payments, AI actions

The current web auth context supports Hono cookie auth but still supports Python/Rust bearer tokens stored in localStorage. Before production, standardize on cookie/BFF style auth for the web and SecureStore-backed sessions for mobile.

Privacy And Compliance

Build for these obligations even before formal legal review:

  • Data minimization: collect only what is required for school operations.
  • Purpose limitation: student data is used for the school service, not advertising.
  • Parental/school consent tracking for minors.
  • Guardian access controls: guardians only see linked students.
  • Location privacy: short retention for bus GPS samples.
  • Biometric caution: face recognition should be optional, consented, region-aware, and off by default. Avoid it in the MVP unless a pilot specifically requires it.
  • Export/delete workflows for legal requests.
  • Vendor registry for WhatsApp/SMS/email/payment/AI processors.
  • Regional data residency option later for enterprise deals.

AI Safety

Rules:

  • AI cannot silently mark students risky without evidence and human-visible reason codes.
  • AI cannot send high-impact parent messages without review unless it is a pre-approved template filled with deterministic facts.
  • AI cannot make payment, discipline, enrollment, or exclusion decisions.
  • Every AI output used in the product stores prompt version, model, input references, output, and reviewer decision where applicable.
  • RAG answers must be tenant-scoped and cite internal sources.
  • Prompt injection tests become part of evals for parent chatbot and admin assistant.

Observability And Operations

Use OpenTelemetry for traces, metrics, and logs once services move beyond simple local development.

Minimum telemetry:

  • Request count, latency, and error rate by route.
  • DB query latency by module.
  • Outbox queue depth and retry count.
  • Notification send latency, provider status, and delivery success.
  • Attendance scan latency.
  • Payment webhook processing time and duplicate count.
  • AI cost, latency, refusal/error rate, approval rate, and edit rate.
  • Tenant-level rate limit events.

Operational targets for the attendance MVP:

FlowTarget
QR scan API responsep95 under 300 ms inside target region
Parent alert enqueueunder 1 second after scan commit
Parent alert delivery to providerp95 under 5 seconds, provider dependent
Principal dashboard updateunder 2 seconds
Outbox event losszero, verified by retry/idempotency

Backups:

  • Postgres point-in-time recovery.
  • Daily logical backup drill.
  • Object storage versioning for important generated documents.
  • Restore test before production pilots.

Naming Conventions

Database

  • Table names: snake_case, plural nouns.
  • Columns: snake_case.
  • Foreign keys: `<entity>_id`.
  • Join tables: `<left>_<right>` or domain phrase such as student_guardians.
  • Enum values: lowercase snake case in product docs; map to ORM enum style as needed.
  • Indexes: `idx_<table>_<columns>`.
  • Unique constraints: `uniq_<table>_<columns>`.

API

  • Paths: lowercase kebab-case or simple plural nouns.
  • JSON fields: camelCase.
  • Route resources: plural nouns.
  • Commands: verb suffix routes only when not plain CRUD, for example /approve, /generate.
  • Error codes: uppercase snake case, for example AUTH_TOKEN_NOT_FOUND.

TypeScript

  • Components: PascalCase file and export names.
  • Hooks: useThing.
  • Services: ThingService.
  • Repositories: ThingRepository.
  • Validators: thing.validator.ts.
  • Policies: thing.policy.ts.
  • Events: thing.events.ts.
  • Tests: colocated *.test.ts.

Recommended module layout:

apps/hono-api/src/modules/attendance
+-- attendance.routes.ts
+-- attendance.controller.ts
+-- attendance.service.ts
+-- attendance.repository.ts
+-- attendance.validator.ts
+-- attendance.policy.ts
+-- attendance.events.ts
+-- attendance.test.ts

Shared packages to add when implementation starts:

PackagePurpose
@school-os/contractsShared API/event DTO types and schemas
@school-os/authzPermission constants and policy helpers
@school-os/eventsEvent envelope, outbox helpers, event names
@school-os/configTyped environment/config helpers
@school-os/idStandard ID generation

Build Roadmap

Phase 0: Architecture Foundation

  • Pick one production API: Hono.
  • Keep FastAPI/Rust/Nest as labs until a concrete service split is justified.
  • Add product schema plan and module boundaries.
  • Add shared contracts package.
  • Add tenant/membership/role model.
  • Add request ID, audit logging, rate limit, and secure headers.

Phase 1: Smart Attendance MVP

  • Tenants, campuses, academic years, classes, sections, students, guardians.
  • Auth and role-based access.
  • QR token generation and scanner.
  • Attendance sessions, marks, events, summaries.
  • WhatsApp/SMS/email notification pipeline through outbox worker.
  • Principal live dashboard.
  • Parent mobile attendance feed.

Phase 2: Communication And Parent Trust

  • Announcements.
  • Teacher-parent conversations.
  • Documents and signed permission slips.
  • Event calendar and reminders.
  • Emergency alert workflow with step-up authentication.

Phase 3: Academics

  • Timetable.
  • Homework.
  • Assessments and marks.
  • Report card generation.
  • AI-drafted comments with teacher approval.
  • Learning gap concept map.

Phase 4: Finance And Admissions

  • Fee plans, invoices, payments, receipts.
  • Payment gateway webhooks and reconciliation.
  • Due reminders.
  • Basic expense ledger.
  • Admission inquiry CRM and next-best-action reminders.

Phase 5: AI-First Intelligence Layer

  • Student intelligence profiles.
  • Daily and Friday briefings.
  • AI action approval queue.
  • Parent chatbot with tenant-scoped RAG.
  • Early warning system with reason codes and fairness review.
  • Intervention playbook.

Phase 6: Scale And Enterprise Readiness

  • Kafka/Redpanda if event volume requires it.
  • Dedicated notification service.
  • Dedicated AI service.
  • Enterprise tenant isolation options.
  • Data residency controls.
  • Security review, penetration test, and compliance package.

Key Technical Decisions

DecisionRecommendation
Primary databasePostgres
MySQLIntegration/import target only, not core product DB
CacheRedis cache-aside plus rate limits, locks, and lightweight queues
KafkaNot MVP; add after outbox/worker is insufficient
API frameworkHono for primary product API
Python/FastAPIUse later for AI/ML service, not core CRUD
RustUse later for high-throughput edge scanner/realtime/infra work if needed
Vector searchpgvector first
AI orchestrationServer-owned orchestration with typed tools, guardrails, approvals, evals
Auth storage webHttpOnly cookies/BFF style
Auth storage mobileSecureStore-backed session handles
TenancyShared tables with tenant_id, policy layer, and RLS on sensitive tables
Service styleModular monolith first, microservices later

Open Decisions Before Implementation

  1. Standard ID format: migrate from current string CUID-style IDs to UUIDv7, or standardize CUID2 text IDs across all services.
  2. WhatsApp provider: Meta WhatsApp Cloud API directly, Twilio, or a regional BSP.
  3. Payment provider priority by market: Stripe, Razorpay, Paymob, Flutterwave, or local PSPs.
  4. AI provider policy: OpenAI first with abstraction, or provider-neutral from day one.
  5. Biometric attendance: explicitly out of MVP unless consent/legal review and a pilot demand it.
  6. Data residency target for first market.
  7. Whether to put generated report cards in object storage only or also store normalized snapshots.

Research References

On this page