WORKFLOW 1: LEAD CREATIONWORKFLOW 2: LEAD STATUS TRANSITIONWORKFLOW 3: ADMISSION CREATIONWORKFLOW 4: FEE PAYMENT RECORDINGWORKFLOW 5: INSTALLMENT VOIDINGWORKFLOW 6: STUDENT STATUS TRANSITION (LIFECYCLE)WORKFLOW 7: STUDENT RE-ENROLLMENTWORKFLOW 8: STUDENT PROMOTIONWORKFLOW 9: STUDENT REINSTATEMENTWORKFLOW 10: HOSTEL OUTING REQUEST (PARENT)WORKFLOW 11: OUTING REVIEW (WARDEN/ADMIN)WORKFLOW 12: OUTING RETURN (WARDEN/ADMIN)WORKFLOW 13: MEDICAL REQUEST SUBMISSION (PARENT)WORKFLOW 14: MEDICAL REQUEST ACKNOWLEDGMENT (WARDEN/ADMIN)WORKFLOW 15: MEDICAL REQUEST COMPLETION/REJECTION (WARDEN/ADMIN)WORKFLOW 16: SESSION ACTIVATIONWORKFLOW 17: FEE REMINDER CRONWORKFLOW 18: NOTIFICATION QUEUE PROCESSINGWORKFLOW 19: USER CREATION (ADMIN)WORKFLOW 20: PARENT ACCOUNT CREATION
v1.0
Reference
Admin
Counselor
Warden
DAC Academy — Workflow Catalog
WORKFLOW 1: LEAD CREATION
| Aspect | Detail |
|---|---|
| Trigger | Staff clicks "New Lead" on /leads or navigates to /leads/new |
| Actor | Admin or Counselor |
| Screen | /leads/new — Lead Form component |
| Inputs | studentName, targetExam, class, parentName, parentPhone, branchId, probability, status, optional: dateOfBirth, placeCity, schoolName, mediumBoard, strengthSubject, weakSubject, parentOccupation, parentHasWhatsapp, notes, assignedToUserId, source, alternatePhone, alternateHasWhatsapp, state, fullAddress, medicalCheckUp |
| Validations | Phone via isValidPhone (libphonenumber-js), WhatsApp consistency (if alternatePhone provided but blank, must equal parentHasWhatsapp), status transitions enforced, registration payment required if status='registered' |
| System Actions | 1. Validate via createLeadSchema (Zod safeParse) 2. Normalize phone to E.164 3. Insert into leads table 4. Write audit log 5. If status='registered', also create receipt and registration record inside a transaction |
| Outputs | New leads row. If registered: receipts row, registrations row |
| Notifications | None at this stage |
| Audit | lead.create — afterData with all lead fields |
| Failure Conditions | Duplicate lead (branch+phone+name unique constraint), invalid phone number |
| Recovery | Edit the existing lead instead of creating duplicate |
WORKFLOW 2: LEAD STATUS TRANSITION
| Aspect | Detail |
|---|---|
| Trigger | Staff updates lead status on edit form or via Register button |
| Actor | Admin or Counselor |
| Screen | Lead Form (/leads/[id]/edit) or Register Lead Dialog on lead detail |
| Valid Statuses | new → contacted → interested → registered → admitted (automatic), lost (from any non-terminal state) |
| Registered Path | Registering requires payment details: amountPaise (default 300000), paymentMode, transactionId, paymentScreenshot |
| System Actions | For registered: 1. Validate payment 2. Create receipt (REG kind) 3. Create registration record 4. Update lead status 5. Fire-and-forget receipt PDF generation 6. Fire-and-forget WhatsApp notification 7. Audit log |
| Outputs | Updated lead, registration record, receipt with number |
| Notifications | WhatsApp to parent: registration confirmation with receipt number |
| Audit | lead.status_change — before and after status |
WORKFLOW 3: ADMISSION CREATION
This is the most complex workflow in the system. It creates 10+ database records in a single transaction.
| Aspect | Detail |
|---|---|
| Trigger | Staff submits the admission form on /admissions/new |
| Actor | Admin or Counselor |
| Screen | /admissions/new — Multi-section admission form |
| Pre-requisites | Active academic session must exist. Active checklist items must exist. Batch must not be completed/cancelled. |
| Inputs | See Phase 5 Admissions section for complete field list |
| Transaction Flow | 1. Lock batch row (FOR UPDATE) 2. Check batch capacity 3. Create/verify parent user (if email provided) 4. Hash Aadhaar (if provided) 5. Create Student record 6. Update lead status to 'admitted' 7. Create student_session row 8. Create hostel allocation (if applicable) 9. Generate receipt (ADM kind) 10. Create Admission record 11. Write fee_components from batch templates 12. Create FeeRecord 13. Create paid installment for initial payment 14. Create future installments 15. Initialize document checklist 16. Insert admission items 17. Increment batch version (optimistic lock) 18. Audit log |
| Post-Transaction | 1. Fire WhatsApp admission notification 2. Generate and store receipt PDF (async) |
| Concurrency | Batch row locked FOR UPDATE inside transaction. Capacity re-checked after lock. Version increment on batch. |
| Outputs | Student, Admission, FeeRecord, Installments, Receipt, StudentSession, HostelAllocation (if needed), AdmissionChecklist, AdmissionItems, FeeComponents |
| Notifications | WhatsApp to parent: admission confirmation with receipt details, items given/remaining, parent login credentials |
| Audit | admission.submit — full afterData snapshot |
WORKFLOW 4: FEE PAYMENT RECORDING
| Aspect | Detail |
|---|---|
| Trigger | Staff clicks "Record Payment" on fee/student page, or selects an unpaid installment |
| Actor | Admin or Counselor |
| Screen | Add Payment Dialog (from /fees or /students/[id]) |
| Inputs | feeRecordId, amountPaise, paymentMode, transactionId, paymentScreenshotUrl, optional: installmentId (to resolve specific installment) |
| Transaction Flow | 1. Lock fee_record row (FOR UPDATE) 2. Verify remainingPaise >= payment amount 3. Create receipt (ADM kind) 4. Create paid installment row 5. Update fee_record: totalPaidPaise += amount, remainingPaise -= amount (version check) 6. Mark any matching installment as paid 7. Audit log |
| Financial Invariants | totalFeePaise = totalPaidPaise + remainingPaise (DB-enforced CHECK) |
| Outputs | Receipt, paid installment, updated fee_record |
| Notifications | WhatsApp to parent: payment confirmation |
| Failure Conditions | Overpayment (amount > remaining), duplicate transaction ID |
| Recovery | Void the payment if recorded in error |
WORKFLOW 5: INSTALLMENT VOIDING
| Aspect | Detail |
|---|---|
| Trigger | Staff clicks "Void" on a paid installment |
| Actor | Admin or Counselor |
| Screen | Payment History on /students/[id] |
| Inputs | Installment ID, version, void reason |
| Transaction Flow | 1. Lock fee_record 2. Mark installment as voided (voidedAt, voidedBy, voidReason) 3. Recalculate fee_record aggregates 4. Audit log |
| Financial Impact | Voiding reverses the payment: totalPaidPaise -= amount, remainingPaise += amount |
| Receipt Status | Voiding an installment does NOT void the receipt. Receipts are immutable. |
| Outputs | Voided installment, recalculated fee_record |
WORKFLOW 6: STUDENT STATUS TRANSITION (LIFECYCLE)
| Aspect | Detail |
|---|---|
| Trigger | Staff uses Status Transition Dialog on student detail page |
| Actor | Admin or Counselor |
| Available Transitions | active → left (with leftDate, reason), active → tc_issued (with tcNumber), active → removed (with reason), active → completed (with completedDate) |
| Transaction Flow | 1. Lock student_session row 2. Update status, set appropriate date fields 3. Clear batchId on left/tc_issued/removed 4. Audit log |
| Business Rules | Cannot leave if fee arrears exist (app-enforced). TC issuance requires fee clearance. |
| Outputs | Updated student_session row |
WORKFLOW 7: STUDENT RE-ENROLLMENT
| Aspect | Detail |
|---|---|
| Trigger | Staff clicks "Re-enroll" on student detail page |
| Actor | Admin or Counselor |
| Pre-requisites | Student must have a terminal status (left/tc_issued/removed/completed) |
| Inputs | studentId, batchId, optional: new sessionId |
| Transaction Flow | 1. Verify student's latest session is in terminal status 2. Create new student_session row with status='active' for current/selected session 3. Set student's batchId to new batch 4. Set student isActive=true 5. Audit log |
| Outputs | New active student_session, updated student |
WORKFLOW 8: STUDENT PROMOTION
| Aspect | Detail |
|---|---|
| Trigger | Staff clicks "Promote" on student detail page |
| Actor | Admin or Counselor |
| Pre-requisites | Next academic session must exist. Student must be active in current session. |
| Transaction Flow | 1. Create new student_session for next session with status='active' 2. Create fee_record for new session 3. Carry forward any unpaid fee balance 4. Audit log |
| Outputs | New student_session and fee_record for new session |
WORKFLOW 9: STUDENT REINSTATEMENT
| Aspect | Detail |
|---|---|
| Trigger | Staff clicks "Reinstate" on student detail page |
| Actor | Admin or Counselor |
| Transaction Flow | 1. Find the student's most recent student_session 2. Update its status back to 'active' 3. Clear leftDate/tcNumber/removalReason 4. Set student isActive=true 5. Audit log |
| Outputs | Reactivated student_session, updated student |
WORKFLOW 10: HOSTEL OUTING REQUEST (PARENT)
| Aspect | Detail |
|---|---|
| Trigger | Parent submits outing form on /parent/hostel-outing |
| Actor | Parent (must own the student) |
| Screen | /parent/hostel-outing — Outing Form |
| Inputs | studentId, startDate, endDate, reason, type, accompaniedBy, accompaniedByDetails, expectedReturnDate, expectedReturnTime |
| Validations | End date >= start date, reason 1-1000 chars, parent must own student (requireOwnership), student must be hostel-opted and have active session |
| System Actions | 1. Validate via requestOutingSchema 2. Verify ownership 3. Verify hostel-opted and active session 4. Insert into hostel_outings (status='pending') 5. Audit log 6. Fire-and-forget WhatsApp notification to warden |
| Outputs | New hostel_outings row |
WORKFLOW 11: OUTING REVIEW (WARDEN/ADMIN)
| Aspect | Detail |
|---|---|
| Trigger | Warden/admin opens outing detail page and clicks Approve/Reject |
| Actor | Warden or Admin |
| Screen | /hostel/outings/[id] — Review Form |
| Inputs | status (approved/rejected), comment (optional) |
| Scoping | Warden: only outings for students in their hostel. Admin: all outings via branch scope. |
| System Actions | 1. Scoping check 2. Update outing status, reviewedByUserId, reviewedAt, reviewNotes 3. Audit log 4. Fire-and-forget WhatsApp notification to parent |
| Outputs | Updated outing status |
WORKFLOW 12: OUTING RETURN (WARDEN/ADMIN)
| Aspect | Detail |
|---|---|
| Trigger | Warden/admin marks an approved outing as returned |
| Actor | Warden or Admin |
| Pre-requisites | Outing must be in 'approved' status |
| System Actions | 1. Scoping check 2. Update status to 'returned', set returnedAt timestamp 3. Audit log |
| Outputs | Updated outing — status changes from 'approved' to 'returned' |
WORKFLOW 13: MEDICAL REQUEST SUBMISSION (PARENT)
| Aspect | Detail |
|---|---|
| Trigger | Parent submits medical request form on /parent/medical |
| Actor | Parent |
| Screen | /parent/medical |
| Inputs | studentId, disease, medicineName, doseQuantity, doseTime, optional: consultedDoctor, notes |
| Validations | Student must be hostel-opted, have active session, parent must own student |
| System Actions | 1. Validate via submitRequestSchema 2. Verify ownership 3. Verify hostel-opted and active session 4. Insert into medical_requests (status='pending') 5. Audit log |
| Outputs | New medical_requests row |
WORKFLOW 14: MEDICAL REQUEST ACKNOWLEDGMENT (WARDEN/ADMIN)
| Aspect | Detail |
|---|---|
| Trigger | Warden/admin clicks "Acknowledge" on medical request in queue |
| Actor | Warden or Admin |
| Screen | Medical Requests tab on /hostel or /warden/medical |
| Pre-requisites | Request status must be 'pending'. Warden: request must be for student in their hostel. |
| System Actions | 1. Scoping check (warden hostel filter) 2. Update status to 'acknowledged' 3. Set acknowledgedByUserId, acknowledgedAt 4. Optimistic lock via version 5. Audit log 6. Fire-and-forget WhatsApp notification to parent |
| Outputs | Updated medical request (pending → acknowledged) |
WORKFLOW 15: MEDICAL REQUEST COMPLETION/REJECTION (WARDEN/ADMIN)
| Aspect | Detail |
|---|---|
| Trigger | Warden/admin clicks Complete or Reject on acknowledged request |
| Actor | Warden or Admin |
| Pre-requisites | Request must be in 'acknowledged' status |
| Completion | Status → 'completed'. No additional fields. |
| Rejection | Status → 'rejected'. Requires rejectionReason. |
| System Actions | 1. Scoping check 2. Validate status transition 3. Update with optimistic lock 4. Audit log |
| Outputs | Updated medical request |
WORKFLOW 16: SESSION ACTIVATION
| Aspect | Detail |
|---|---|
| Trigger | Admin clicks "Activate" on a session in Settings |
| Actor | Admin |
| Screen | /settings → Sessions tab |
| Transaction Flow | 1. Begin transaction 2. Deactivate all currently active sessions 3. Activate the selected session 4. Audit log |
| Business Rules | Only one session can be active at a time. Cannot deactivate a session that has active students. |
| Outputs | Updated academic_sessions rows |
WORKFLOW 17: FEE REMINDER CRON
| Aspect | Detail |
|---|---|
| Trigger | Cron job calls /api/cron/fee-reminders |
| Actor | System (cron) |
| Logic | 1. Find all unpaid/past-due installments 2. For each, check if reminderSent=false 3. Enqueue WhatsApp notification 4. Set reminderSent=true |
| Outputs | Enqueued notification jobs |
WORKFLOW 18: NOTIFICATION QUEUE PROCESSING
| Aspect | Detail |
|---|---|
| Trigger | Cron job calls /api/cron/process-notifications |
| Actor | System (cron, ~every 2 minutes) |
| Logic | 1. Fetch up to 5 pending jobs with scheduledAt <= now 2. Atomically claim (UPDATE status='processing' WHERE status='pending') 3. For each job: send WhatsApp via WATI API 4. On success: mark 'completed' 5. On failure: retry with exponential backoff (2^attempt minutes), up to 3 attempts |
| Safety | Atomic claim prevents duplicate sends across overlapping cron invocations |
| Outputs | Processed notification jobs |
WORKFLOW 19: USER CREATION (ADMIN)
| Aspect | Detail |
|---|---|
| Trigger | Admin fills user creation form |
| Actor | Admin |
| Screen | /users — User Dialog |
| Inputs | email, password (auto-generated or custom), name, role, branchId, hostelId, phone |
| System Actions | 1. Validate input via createUserSchema 2. Create Better Auth user via auth.api.signUpEmail 3. Update users table with role/branch/hostel 4. Set emailVerified=true 5. Audit log |
| Outputs | New users row and Better Auth account |
WORKFLOW 20: PARENT ACCOUNT CREATION
| Aspect | Detail |
|---|---|
| Trigger | Admission submission (auto) OR staff clicks "Create Parent Account" button |
| Actor | System (auto) or Admin/Counselor (manual) |
| Logic | 1. If email doesn't exist in users: create via Better Auth signUpEmail 2. Generate random password Parent@XXXX 3. Set role='parent', emailVerified=true 4. Link to student via parentUserId 5. Return credentials for display |
| Outputs | New parent users row and Better Auth account |