- Pitch
- Balqalam
- Live Demo
- MVP
- Roadmap
- Launch Sprint
- PRD
- Marketing Brief
- Sales
- Go-to-market
- Marketing
- Product Truth
- Audience & Markets
- Offer & Funnel
- Claim Registry
- Content System
- Channels & Calendar
- 90-Day Plan
- Workflow & Templates
- Measurement
- Growth Editor Agent
- Admission — Feature Spotlight
- Pilot Program
- Leads
- Proposal
- Outreach Templates
- Case Study
- Competitors
- Landing-page teardown
- Competitor FAQ
- Business model
- Shared economy
- Traction
- Get Support
- Investor Deck
- Data Room
- Investors
- Accelerators
- Incubators
- Grants
- Sponsors
- Partners
- Competitions & Hackathons
- Universities & Training Centers
The MVP doc records what is shipped; the Roadmap records the quarter direction. This doc is narrower and time-boxed: the single sprint that ends with launch. Anchor date: 2026-06-20, HEAD febb7da3b.
The thesis is simple. After the June deploys — transportation Phase 2–5, the conference notification/attendance integration, the public features + community hubs, exam-and-grade automation, the lumos/LMS optimize pass, the saas-dashboard de-fabrication, timetable production-readiness, and demo-seed auto-provision — almost every epic is code-complete. What stands between here and launch is no longer feature-building. It is four things: making the last few correctness fixes, confirming the database, turning on the ops and credentials, and running a QA pass that actually proves it. This sprint does exactly that, for all three launch audiences at once: the King Fahad pilot (Sudan, Sept 2026), the public SaaS at ed.databayt.org, and the Aldar enterprise pilot (UAE).
For requirements see PRD. For the pilot context see Pilot.
Where we are
State verified against block records and git log at HEAD febb7da3b. The "old status" column is the last roadmap reconcile (2026-05/06-15); the gap is real because a lot shipped since.
| Epic | Old status | Now (verified) | Remaining to launch |
|---|---|---|---|
| Transportation | Built+Polish | Phase 2–5 deployed (febb7da3b); route optimization, live GPS, hazards; 331 tests; additive DB applied to Neon prod at deploy | Optional MAPBOX_SERVER_TOKEN; weather routing deferred |
| Conference | Built (link only) | Notification P0 fixed, guardian Join, attendance-from-presence deployed (9059bf77c); enum + column live on Neon; 227 tests | LiveKit SFU infra (Aldar); native OAuth creds |
| Exams + grades | Built+Audit (14 P0) | Grade automation deployed; gradebook spine, finalize → Result + notify, certificates; full route tree reachable; RBAC + calculator tests in place; AI cost cap wired | schema lang cleanup, Result↔ExamResult reconcile |
| Attendance | Phase 2 in progress | Section-centric shipped & DB-migrated; soft-delete consistency fixed; 611 tests, ~96% | e2e specs all test.skip; confirm hot-path indexes on prod |
| Lumos / LMS / Catalog | Built+Polish | Optimize pass deployed (−1,870 dead LOC, perf); 250 tests | content depth (creds-gated); confirm 3 indexes on prod |
| Messaging | Built (ops-gated) | 100% code-complete; FTS + WhatsApp bridge; 221 tests | Oracle VM not yet stood up |
| Finance | Built+Polish (~88%) | Aldar UAE P0/P1/P2 shipped; dashboard trends de-faked (empty series, not random) | invoice/expense/salary payment flows + posters (ledger fixes, payroll tax, invoice PDF/email all done) |
| SaaS dashboard | — | De-fabricated, real data (b50a8f046) | ~150 backlog items (dead Kanban/Products pages, i18n) |
| Community / Features / Profile | — | Public hub + features grid + profile deployed (2026-06-18) | — |
The launch gap
Three buckets. Bucket A is small and surgical, bucket B is mostly confirmation, bucket C is where the real lead time sits.
A — Surgical code (critical path)
| Item | Evidence | Why it matters |
|---|---|---|
| ✅ Playwright CI no-op fixed | .github/workflows/playwright.yml:52 now runs playwright test (sharded) — was playwright tests (trailing s) | e2e now actually runs in CI; the proof pass can build on it |
✅ /api/health Stripe-optional | requiredEnvVars is now ["DATABASE_URL", "AUTH_SECRET"] — STRIPE_API_KEY removed (route.ts:154) | a school-only deploy without Stripe no longer reports unhealthy to the load balancer |
Ledger toCents ×100 — fixed in code, migration pending | toCents dropped from all six posting rules (916327882); rules now store whole units, posting-rules.test.ts green | existing rows from the live postFeePayment are still ×100 — ship the fix with a one-time ÷100 migration (scoped to posting-rule rows) |
finance/content.tsx + salary/content.tsx 1/100 — fixed (5ad229722) | summed whole-unit data but formatted with the ÷100 formatCurrency | both swapped to formatMoney; they were the only two importers of the ÷100 variant |
| ✅ Finance ledger — all 6 posters wired | postFeeAssignment (2026-06-20); invoice via markInvoicePaid, expense via markExpensePaid, salary via processPayments, wallet via topupWallet (2026-06-21) | every finance money event now posts a double-entry pair; salary rule rebalanced to a withholding model (DR gross / CR net+tax+SS+AP). Remaining follow-up: invoice partial-payment-to-ledger (ledger keys on invoice id) |
postFeePayment fire-and-forget (by design) | finance/lib/accounting/actions.ts | post failure logs, no rollback; reconciliation story tracked separately — not a launch blocker |
| ✅ Payroll progressive tax | payroll/actions.ts:293 now calculateProgressiveTax(baseSalary + taxableAllowances) | the hardcoded * 0.15 is gone; marginal brackets from config.ts now drive withholding (unit-tested) |
| ✅ Invoice PDF/email wired | MarkInvoicePaidButton + school logo threaded into invoice-pdf-data.ts; branded RTL email on @react-email/components | Download/Print, school logo/signature, itemized lines, and Arabic RTL email are all in place |
| ✅ Exams reachable + RBAC/calculator tests | full route tree present (manage/qbank/generate/mark/result/…); permissions.test.ts (10) + calculator.test.ts (61) | the earlier "routes missing (BLOCKER)" + "calculator untested" claims were stale. Remaining: schema lang cleanup + Result↔ExamResult reconcile |
B — Database (audit + apply, Neon-branch-first)
Audited against prod 2026-06-21 (prisma migrate diff, read-only). The bucket reduced to a single genuinely-pending migration — everything else was already live:
| Migration | Status |
|---|---|
| Attendance hot-path indexes / Lumos composite indexes | ✅ already on prod (prior deploys) — the diff shows none missing |
saas-dashboard schools.isActive/planType + leads.nextFollowUpAt | ✅ already on prod (columns present) |
JournalEntry @@index → @@unique([schoolId, sourceModule, sourceRecordId]) | ✅ APPLIED to prod 2026-06-21, Neon-branch-first — tested on branch br-jolly-block-adtzmbb3, then promoted; 0 duplicate rows, 200 rows unchanged, index now UNIQUE |
toCents ÷100 ledger sweep (scripts/migrate-ledger-cents-to-whole-units.ts) | data script — verified no-op (0 inflated rows); run post-deploy as a safety sweep |
prisma migrate diff also surfaces pre-existing drift (live_class_* FK renames, roomName NOT NULL, index renames, live_class_events.eventId unique, PricingRule.updatedAt default) — deliberately not applied: reconciliation noise from earlier conference/live-class refactors, not this sprint's work. The catalog TOCTOU fixes, billing atomic CAS, exams AI cost cap, and RBAC/calculator tests are code-only — no DB change.
C — Ops / env / infra (the real lead time)
| Gate | What's needed | Audience |
|---|---|---|
| Sentry | NEXT_PUBLIC_SENTRY_DSN + SENTRY_DSN in Vercel | all — prod errors are invisible until set |
| Upstash Redis | UPSTASH_REDIS_REST_URL + _TOKEN | all — rate limiting is per-instance without it |
| Tap (AED) | TAP_SECRET_KEY + TAP_WEBHOOK_SECRET | UAE fees (Aldar, public SaaS UAE) |
| FCM push | FIREBASE_PROJECT_ID + _CLIENT_EMAIL + _PRIVATE_KEY | all — push silently skipped otherwise |
| Oracle VM + Evolution | socket-server/DEPLOY.md (9 phases) + 6 env vars + per-school QR | all — real-time + WhatsApp; falls back to 15s polling without it |
| LiveKit SFU | conference/RUNBOOK.md (6 gates): G42 SFU + TURN/443 + S3 me-central-1 + 8 env vars + in-school network test | Aldar — external link works without it |
| ADEK eSIS | file inquiry + request piggyback creds via Aldar compliance | Aldar — DRY_RUN runs daily until then |
The 4-week sprint
Five tracks run in parallel across all four weeks: A Code, B Data, C Ops/Infra, D QA/Proof, E Polish. Each week has a theme and an exit gate.
| Week | Theme | Exit gate |
|---|---|---|
| 1 | Reachable & Truthful | Every shipped feature has a URL, CI runs e2e, prod has error visibility, DB confirmed |
| 2 | Money & Messaging | Every financial event posts a balanced ledger entry; real-time + WhatsApp live for all tenants |
| 3 | Conference & Proof | LiveKit live (network-test scheduled), e2e green in CI, Arabic RTL clean |
| 4 | Harden & Launch | Launch gate green for all three audiences |
Week 1 — Reachable & Truthful
- A · Fix the Playwright CI command (
tests→test) so e2e runs · makeSTRIPE_API_KEYoptional in/api/health· add themanage/+paper/exam index pages and confirm sidebar surfacing. - B · Audit Neon prod vs Prisma; apply any additive drift on a Neon branch, then promote.
- C · Set Sentry + Upstash env in Vercel (immediate observability + correct rate limiting).
Week 2 — Money & Messaging
- A · ✅ Wired
postFeeAssignment(assignFee + bulkAssignFees) — the accrual fix that stops the receivable going negative. Investigation found the other three blocked beyond wiring (no invoice/expense payment-recording flow; salary rule unbalanced) and fixed a pre-existingtoCents×100 ledger-inflation P0 — rules now store whole units,posting-rules.test.tsgreen (15/15). The debit=credit invariant test already existed, and thefinance/content.tsx+salary/content.tsx1/100 display bug is fixed. ✅ payroll progressive tax (replaces flat 15% in payroll + salary, unit-tested). The ÷100 ledger migration is a verified no-op safety net — a read-only prod check found zero inflated rows (all 200 entries are seeded whole-units), so the toCents fix deploys safely alone; the script is now self-verifying/fees-scoped, run post-deploy only as a sweep. ✅ invoice PDF + branded RTL email (logo into the PDF; email rebuilt on react-email — RTL, branding, itemized, signature). ✅ invoice + expense payment flows (markInvoicePaid+markExpensePaid). ✅ salary poster — rebalanced the salary posting rule + wiredpostSalaryPaymentinprocessPayments→ 6 of 6 posters wired; the double-entry ledger is fully wired for every finance money event. Week-2 finance code is complete — and an adversarial multi-agent review of the whole finance diff found + fixed 12 money-path defects (multi-tenantschoolIdon updates, concurrent double-post races via conditional updates + aJournalEntry@@uniqueidempotency constraint, salary tax base, invoice partial-payment, anexpenses/approvepermission gate, 4 dashboards' ÷100 display, RTL discount sign). ✅ the expense list now surfaces Approve/Reject + Mark-paid (ExpenseRowActions), closing the expense flow end-to-end. What remains is ops (Track C: Oracle VM, Tap/FCM env, ADEK) and two additive deploy-pending migrations (the toCents ÷100 sweep — a verified no-op — and the JournalEntry@@unique). - C · Stand up Oracle VM + Evolution API (6 env vars; per-school QR for King Fahad + Albayan) · set Tap + FCM env · file the ADEK inquiry now (longest external lead time).
Week 3 — Conference & Proof
- C · LiveKit 6-gate provisioning; schedule gate-6 in-school network test to a King Fahad / Aldar site visit.
- D · Real e2e pass now that CI runs: triage the
test.skipbacklog, un-skip what runs headless, add a named section-grid attendance case, give the assertion-less specs realexpect()s · i18n RTL Arabic pass on the swept surfaces + parent-portal dictionary-key migration. - E · Exams schema cleanup (bilingual →
lang, reconcileResult/ExamResult, harden theExamCertificatecascade chain).
Week 4 — Harden & Launch
- E · Drain the highest-value SaaS-dashboard backlog: ✅ invoice state-machine guard + atomic CAS (
3be3506ed+ 2026-06-21 — no voiding a paid invoice, no concurrent double-transition; buttons gated) · ✅ exams RBAC + calculator test coverage + AI generation/grading cost cap (2026-06-21) · ✅ catalog TOCTOU closed (proposal reject + 4 exam-approval actions now atomic; chapter/lesson count denormalization wrapped in transactions, 2026-06-21). A two-pass adversarial review (find → verify, then re-verify the fixes) confirmed + closed 8 further correctness defects across finance/catalog/exams/billing incl. a P0 ledger-reversal no-op. Remaining: i18n sweep · the Kanban demo route (still linked from analytics nav + command menu — full removal is a product call, not dead code). - D · Per-pilot smoke on King Fahad + Albayan · load + rate-limit verification (now Redis-backed) · final
securepass · wire the hardcoded-string ratchet into the PR gate. - Run the launch gate.
Launch gate
The sprint ends when this is green. Items that are audience-specific are tagged.
- Bucket-A code DEPLOYED to prod 2026-06-21 (
febb7da3b..626b5d690→ origin/main; Verceldpl_FJzP8oBEvcYVnw3L8YiraqkfqUcr● READY on ed.databayt.org; smoke /en /ar /en/login /en/features /en/community /en/docs/sprint /en/docs/finance = 200;/api/health=healthy, Stripe-optional confirmed live) - Neon prod schema confirmed against Prisma + additive manifest applied (Neon-branch-first):
JournalEntry @@uniquelive on prod 2026-06-21; saas cols + attendance/lumos indexes already present; only the verified-no-op toCents sweep remains (post-deploy) — see bucket B - Sentry + Upstash + FCM env set; Sentry receiving events
- Playwright CI command fixed (
tests→test, sharded) — now runs; first green CI run still pending - Finance ledger correct:
toCents×100 resolved + all 6 posters wired & balanced + idempotentcreateJournalEntry+ a two-pass adversarial review closed 8 further defects (incl. the P0reverseJournalEntryno-op, negative-net Cash inversion, payroll post-before-flip recovery);posting-rules.test.tsgreen - King Fahad + Albayan tenants smoke-clean end-to-end
- Oracle VM live; WhatsApp QR scanned per pilot school
- Tap keys set — UAE / Aldar
- LiveKit network-test passes inside school WiFi — Aldar
- ADEK eSIS status acceptable (DRYRUN is fine for King Fahad / SaaS; live submission only gates Aldar compliance go-live) — _Aldar
External blockers
These sit outside the team's keyboard and are called out so launch is not falsely gated on them.
| Blocker | Owner | Acceptable launch posture |
|---|---|---|
| ADEK eSIS API / piggyback credentials | Aldar compliance team | DRY_RUN for King Fahad + SaaS; hard gate only for Aldar attendance-compliance |
| LiveKit in-school network test | needs physical King Fahad / Aldar WiFi | external pasted-link conferencing works meanwhile |
| Per-school WhatsApp QR scan | each school admin | in-app + email messaging works meanwhile |
Deferred (post-launch)
Explicit non-goals this sprint, listed so no speculative work starts.
| Item | Reason |
|---|---|
| Hostel / Cafeteria / Clinic / Facility modules | not built; no near-term demand |
| Bankak gateway | pending Bank of Khartoum API spec |
| Weather-aware routing, voice messages, recurring exams | post-MVP backlog |
| Native iOS / Android | Epic 10/11 stalled; separate track |
| Catalog content depth (Arab-nationals chapters/lessons, real mp4/PDF uploads) | AWS-creds-gated content, not code |
On-prem (Epic 05) merge to main | Aldar Wave-2, post-pilot |