- Introduction
- Pitch
- Hogwarts
- Live Demo
- MVP
- Roadmap
- Launch Sprint
- PRD
- Get Started
- Localhost
- Architecture
- Structure
- Pattern
- Page
- Layout
- Content
- Types
- Config
- Actions
- Queries
- Authorization
- Validation
- Form
- Table
- Detail
- Card
- Util
- Hooks
- List Params
- Views
- README.md
- ISSUE.md
- Technology Stack
- Database
- File
- CDN Assets
- Entry Points
- Dashboard
- Authentication
- Credentials
- OAuth
- Flow Diagrams
- Multi-Tenancy
- Offline
- Onboarding
- Onboarding Videos
- Add Values
- Admission
- Application
- Attendance
- Compliance
- Profile
- Exams
- Exam Wizard
- Timetable
- Classrooms
- Notifications
- Conference
- LMS (Lumos)
Finance
- Finance
- Fee Management
- Invoice
- Wallet
- Salary
- Payroll
- Timesheet
- Expenses
- Budget
- Receipt
- Accounts
- Banking
- Reports
- Dashboard
- Permissions
- Messages
- Integration Flow
- Provision
- AI Document Processing
- Document Intelligence
- Internationalization
- Translation
- Translation Guide
- Icons
- Docs Factory
- Inspiration
- Listings
- Teachers
- Students
- Catalog
- Library
- Contributing
- Code of conduct
- GitHub Workflow
- Database Seeds
- Database Safety
- Test Accounts
- Playwright
- Prettier
- Block Rebound
Sales & GTM
A single extraction service, processing queue, and budget enforcer that any domain can plug into. Today it runs admission documents and bank receipts; the foundation supports 8 future domains tracked in Document Intelligence.
Architecture
Domain features (Admission, Bank Receipts, …)
│
▼
extractWithSchema<T>(schema, prompt, fileUrl) ← PDF / Word / Excel / CSV / Image
│
┌────┼─────────────┐
▼ ▼ ▼
Handler Queue Runner Budget Enforcer
Registry (async + (per-school caps,
retry) domain toggles)
│
▼
/api/document-processing/run (cron, DEVELOPER/ADMIN only)
Core layers
| Layer | Location | Responsibility |
|---|---|---|
| Generic Extraction Service | src/lib/document-extraction/ | Accepts any Zod schema + prompt; returns validated structured data |
| Handler Registry | src/lib/document-extraction/handlers/ | Strategy pattern — each domain registers a handler |
| Queue Runner | src/lib/document-extraction/queue-runner.ts | Async jobs, exponential backoff (30s, 60s, 120s) |
| Budget Enforcement | src/lib/ai/budget.ts | Monthly spend caps, per-domain toggles, usage tracking |
| Processing API | /api/document-processing/run | Cron trigger endpoint |
Processing flow
- File uploads via S3 / CloudFront pipeline.
- Domain feature classifies the document type (or accepts user-provided).
DocumentProcessingJobrow created withPENDING.- Queue runner sets
PROCESSINGand delegates to the registered handler. - Handler calls
extractWithSchema()with schema + prompt. - Results stored as JSON; status set to
COMPLETED. - Cost logged to
AIUsageLogand checked against the school budget.
Database models
DocumentProcessingJob
| Field | Type | Purpose |
|---|---|---|
id | String @id | Primary key |
schoolId | String | Tenant isolation |
userId | String | Initiator |
jobType | String | ADMISSION_DOCUMENT, BANK_RECEIPT, … |
status | Enum | PENDING, PROCESSING, COMPLETED, FAILED |
inputFileUrl | String | Source file |
inputData | Json? | Extra context |
resultData | Json? | Extracted data |
errorMessage | String? | On failure |
retryCount | Int @default(0) | Attempts |
maxRetries | Int @default(3) | Cap |
processingTimeMs | Int? | Duration |
costUsd | Decimal? | Cost |
AIUsageLog
| Field | Type |
|---|---|
schoolId | String |
jobType | String |
model | String (e.g., claude-sonnet-4-20250514) |
provider | String (e.g., anthropic) |
inputTokens, outputTokens | Int |
costUsd | Decimal |
createdAt | DateTime |
School extensions
| Field | Type | Purpose |
|---|---|---|
aiMonthlyBudget | Decimal? | Monthly cap; null = unlimited |
aiEnabledDomains | Json | Array, e.g. ["admission", "bank_receipt"] |
Active domains
Admission documents (EPIC-1)
| Capability | Detail |
|---|---|
| Classification | degree, transcript, national_id, resume, other |
| Extraction | Per-type Zod schemas with .describe() annotations |
| Arabic-aware prompts | Latin transliteration, Hijri→Gregorian, bilingual fields |
| Completeness | Cross-references campaign requiredDocuments |
| Merit engine | Weighted scoring from GPA, entrance exam, interview |
Server actions: processApplicationDocument, getDocumentProcessingStatus, classifyDocument.
Bank receipts
| Capability | Detail |
|---|---|
| Extraction | Amount, date, reference number, bank name |
| Matching | Auto-match to pending Payment records |
| Validation | Cross-check amount against expected fee |
UI components
Shared
| Component | File | Behavior |
|---|---|---|
ProcessingStatusBadge | shared/processing-status-badge.tsx | PENDING amber, PROCESSING blue + spinner, COMPLETED green, FAILED red |
ConfidenceScoreDisplay | shared/confidence-score-display.tsx | HIGH (≥0.8) green, MEDIUM (≥0.5) amber, LOW (<0.5) red |
ProcessingProgressCard | shared/processing-progress-card.tsx | Composite — badge + confidence + error + retry |
AIBudgetIndicator | shared/ai-budget-indicator.tsx | Spend vs limit progress bar |
Admission AI
| Component | File |
|---|---|
DocumentCard | admission/ai/document-card.tsx |
DocumentReviewPanel | admission/ai/document-review-panel.tsx |
DocumentsSection | admission/ai/documents-section.tsx |
Settings
AISettingsForm (settings/ai-settings-form.tsx) — admin config for monthly budget, domain toggles, usage display.
Foundation files
| File | Purpose |
|---|---|
src/lib/document-extraction/types.ts | Generic types, ProcessingJobType enum |
src/lib/document-extraction/claude-extractor.ts | extractWithClaudeGeneric() |
src/lib/document-extraction/index.ts | extractWithSchema<T>() public API |
src/lib/document-extraction/queue-runner.ts | Async job runner |
src/lib/document-extraction/handlers/index.ts | Handler registry |
src/lib/document-extraction/handlers/admission.ts | Admission handler |
src/lib/document-extraction/handlers/bank-receipt.ts | Bank receipt handler |
prisma/models/document-processing.prisma | DocumentProcessingJob, AIUsageLog |
src/lib/ai/budget.ts | canUseAI(), trackAIUsage(), getAIUsageSummary() |
src/app/api/document-processing/run/route.ts | Cron endpoint |
Configuration
ANTHROPIC_API_KEY=sk-ant-...
Set aiMonthlyBudget (null = unlimited) and toggle domains in AI Settings.
Cost estimates
| Operation | Estimated cost |
|---|---|
| Document classification | ~$0.01 / doc |
| Document extraction | ~$0.02–0.05 / doc |
| Bank receipt extraction | ~$0.02–0.03 / doc |
| Full application (5 docs) | ~$0.15 |
| 200 applications / campaign | ~$30 |
When the budget is exhausted, AI operations return AI_BUDGET_EXCEEDED and the UI prompts manual processing.
Adding a new domain
// 1. src/components/school-dashboard/<domain>/ai/schemas.ts
export const textbookMetadataSchema = z.object({
title: z.string().describe("Book title"),
author: z.string().describe("Author name"),
isbn: z.string().optional().describe("ISBN"),
edition: z.string().optional(),
publisher: z.string().optional(),
})- Add a handler in
src/lib/document-extraction/handlers/mapping the job type to schema + prompt. - Import the handler in
queue-runner.tsso it auto-registers. - Server actions in
<domain>/ai/actions.tscallcreateProcessingJob()with the job type. - Add the domain string to the school's
aiEnabledDomainsvia AI Settings.
Roadmap
| Epic | Name | Story points | Status |
|---|---|---|---|
| 0 | Foundation | 34 | Done |
| 1 | Admission Documents | 49 | Done |
| 2 | Exam Paper Intelligence | 36 | Planned |
| 3 | Textbook & Curriculum | 28 | Planned |
| 4 | Library & Book Management | 24 | Planned |
| 5 | Attendance Intelligence | 20 | Planned |
| 6 | School Onboarding Intelligence | 20 | Planned |
| 7 | Invoice & Expense | 22 | Planned |
Total: 233 story points.