QuranFlow Rebuild — Implementation Plan
Build plan for taking the Sakīna design (mockups in ../mockup/) to a
production iOS/Android app and coach tool. Companion to FEEDBACK-SYNTHESIS.md
(what stakeholders asked for) and ../mockup/REVIEW.md (the adjudicated
design decisions). This is the "IT revamp" — a full replacement of the current
app and its backend, not an incremental patch.
Revised 2026-07-17: hard deadline. The app must be live for the fall semester — students onboarding in the first week of September 2026. The original open-ended sizing ("6–9 months for one developer") no longer applies as a schedule; it survives below only as the effort arithmetic behind the dated delivery plan in Section 5, which now defines what ships at launch, what lands during the semester, and what a September date costs.
Revised 2026-07-26 (product review with Lejla, Jul 24): the Year-2 model changed. Year 2 has no weekly submissions — per-week, multi-coach appointment booking (soft cap 3/week, included in tuition) replaces the recurring-slot model, and coaches get an appointment-notes tool (record → transcribe → auto-summary → edit → send). A new entry/placement flow (web checkout → email sign-in → first assessment → placement) now gates first-run and therefore moves into the launch scope (Phase 1) — unlike Year-2 booking, which stays deferred to November. Whether to offer an optional recurring "same slot weekly" booking is an open product question (Q13, pending Lejla). Changes are marked in Phases 1 and 4 and Section 5 below; the source is the flow map in
../../explorations/flow-map/.
Revised 2026-07-27 (Lejla review): the Jul 27 screen review (decision record:
../../reviews/App-Review-Jul27-Lejla.md) reshaped the launch-scope entry flow. The first act is now a recorded recitation (four graded reading stages), not a booked 1:1 — and it reuses the submission/recording pipeline, so the launch entry lane costs little beyond the supportive screens and the Level-0 states (full app minus lessons; pending recitation shown as a submission awaiting feedback; never-submitters auto-placed to Level 2). The recording routes to a pooled placement queue (role-gated, replacing today's shared-login account). Two launch-scope cuts: the Qur'an font/script picker (onboarding step 3 and the settings screen) is dropped entirely. One launch-scope add: an availability step for every placed student (Year 1 levels 1–4 and Year 2), collecting general availability that drives all live-session scheduling. Sign-in is email + password (welcome-email credentials), not a magic link. Deferred to November (Phase 4) unchanged: the Year-2 hype sequence for Level-4 graduates and the plan-based appointment copy (allowance stated per the student's purchased plan, never a universal cap). Changes marked in Phases 1 and 4 and Section 5.
Context this plan assumes: a small org (1 program lead, 1 platform lead, ~11 part-time coaches), a student base on iOS today with Android demand likely next, and a coach population that is overwhelmingly mobile (9/11 mobile-only or mobile+desktop, 1 desktop-only per the questionnaire). No committed engineering headcount is named here — sizing in Section 5 is in engineer-weeks so it can be mapped to whoever ends up on it, whether that's one contractor or a small agency.
1. Technology recommendation
Client: React Native (Expo), not SwiftUI, not Flutter
Recommendation: React Native with Expo (EAS Build/Submit, Expo Router).
Rationale:
- Two platforms are in scope, one is not optional-later. The synthesis explicitly flags Android as "likely later" for students and a desktop-leaning coach app. SwiftUI ships iOS only — a second native codebase for Android would double the maintenance surface for a team with no dedicated iOS+Android pair. React Native gets both from one codebase on day one, which matters more for a coach app that a 1-in-11 user wants on desktop than it might for a bigger team that could afford two native apps.
- Single small team, likely one primary developer. RN's larger hiring pool and shared JS/TS skillset across student app, coach app, and (if needed) an admin web panel reduces bus-factor risk versus Swift-only expertise. See Risk R2 below — this is a real constraint, not a nicety.
- Audio is the hard requirement, and RN handles it adequately, not
effortlessly. Recording, resumable upload, scrubbing playback, and
waveform rendering are all solvable in RN (
expo-av/expo-audio, background upload viaexpo-file-system+ a resumable protocol, waveform via pre-computed peaks rendered in-app). It is not as clean as AVFoundation directly, budget explicit spike time for it (see Section 3). - Push notifications and Zoom deep links are both well-trodden RN territory
(Expo push service or FCM/APNs directly,
Linking/expo-linkingforzoommtg://URI schemes with a web-link fallback). Nothing here pushes toward native. - Coach desktop want is a minority-but-real need, not a v1 requirement. Expo Router + React Native Web gets a workable coach web view later without a second UI codebase, if and when it's prioritized. This is the tie-breaker against Flutter, which has no realistic path to reusing the same UI code as a React-based admin/coach web panel.
- Flutter is a reasonable second choice, not the pick. Its performance and single-codebase story are comparable to RN's, but it puts the team on Dart, a language with a smaller local hiring pool than JS/TS, and the org already has web/JS-literate people (the process-site and mockups in this repo are built with bun/JS tooling) — momentum favors staying in that ecosystem.
What would change this recommendation:
- If the org hires a dedicated iOS engineer and Android is genuinely deferred indefinitely (not "later" but "no"), native SwiftUI becomes competitive — better platform-idiomatic audio/notifications, no bridge overhead. Revisit if that hire happens before Phase 1 starts.
- If Arabic text rendering (Section 3) turns out to need custom text layout beyond what a WebView or RN's text primitives can do performantly, a native module (Swift/Kotlin) wrapping a font-shaping library may be needed regardless of the outer framework — this is additive to RN, not a reason to abandon it.
Backend: Managed BaaS over custom API
Recommendation: a managed backend-as-a-service (Firebase or Supabase), with the third-party integrations (Zoom, email, Stripe) as Cloud Functions/Edge Functions rather than a bespoke server.
Rationale:
- Team size is the deciding factor. A program lead and a platform lead are not going to operate a custom API's infra (deploys, scaling, patching, on-call) alongside everything else they run. A managed BaaS removes an entire operational category: auth, database, file storage (audio files), and realtime sync come out of the box.
- The data model (submissions, feedback, annotations, appointments, messages) is relational/document-shaped but not exotic — no need for a custom data engine. Supabase (Postgres + Row Level Security) is a good fit if the team wants SQL and stronger relational guarantees for the submission/feedback/attendance joins described in the wishlist; Firebase (Firestore) is a good fit if the team wants less schema ceremony and tighter native push/RN integration. Lean Supabase if the team is comfortable with SQL — the wishlist's business rules (2 submissions/week, 5–10 min revoke window, cross-teacher shared notes, semester calendar states) are naturally expressed as relational constraints and views, and Postgres RLS maps cleanly onto "coach sees own students, sees shared notes across coaches" access patterns.
- Integrations (Zoom, email, Stripe) don't need a general-purpose API server — they need scheduled/triggered functions: a webhook receiver for Stripe, a scheduled function for reminder emails/push, a Zoom API call to fetch attendance duration. Supabase Edge Functions or Firebase Cloud Functions cover this without standing up and hosting a separate service.
- Custom API becomes justified only if the org later needs bespoke business logic too complex for BaaS functions (e.g., the backlogged student-centric scheduling algorithm) at a scale where BaaS query limitations bite, or if they hire a backend-focused engineer who'd rather own infra than rent it. Not true today.
- Note: the current backend "of unknown quality" is being fully replaced, so there's no migration-path constraint pulling toward a like-for-like replacement — pick for the next five years, not for parity with what exists.
2. Build phases
Each phase ships something a student or coach can actually use, not just
scaffolding. Screen labels reference ../mockup/src/main.jsx artboard
labels.
Phase 1 — Core loop: auth, four tabs, lesson → recording → submission
The minimum viable app: a student can log in, see their week, watch a lesson, record and submit an attempt.
Screens (by artboard label):
- Section E (new, Revised 2026-07-26): Sign in, Book your first assessment,
Waiting for placement, Placement result — the entry/placement flow. It gates
first-run: a new (web-registered) student cannot reach onboarding or the core loop
without being placed, so it must ship at launch. See PRODUCT-SPEC Section E and the
account/enrollment lifecycle in DATA-MODEL §2. Revised 2026-07-27: this lane is
Sign in → 2–3 supportive screens → your first recitation (recorded, reuses the
Section-01 recording pipeline) → Level 0 (full app minus lessons) → placement result.
"Book your first assessment" is retired — there is no booking. The recitation is a
Submissionsubtype routing to a pooled placement queue; because it reuses the recording flow below, its incremental cost is the supportive screens, the Level-0 states, and the placement queue, not a whole new capture surface. - Section 00: Today, Learn — syllabus, Sessions — Tuesday timeline (static/no booking yet), Profile
- Section 01: Lesson — Idghām with ghunnah, Video player — chapter complete, Recording — Ready / In progress / Review / Submitted / No attempts
- Section 05: Onboarding steps 1–6 (Revised 2026-07-27: step 3 "Choose script" is cut; the sequence is five steps. Add an availability step for placed students, and restore a "watch as a video" option on the explainer steps.)
- Section 02 (partial): Personal details
, Qur'an font picker(Revised 2026-07-27: the Qur'an font picker is cut — one usable Madani-compatible web font is used everywhere; there is no picker to build.)
Backend surface:
- Auth (magic sign-in link emailed after web checkout, set-password fallback —
sales are off-app; the account already exists at first sign-in). Revised
2026-07-26: auth must route by account status (new / Year 1 / Year 2 / coach) and
hold a
new/awaiting_placementaccount out of the Year-1 loop. - Enrollment/placement (new, Revised 2026-07-26): account-status state machine
(
registered → assessment_booked → awaiting_placement → placed | year2), first- assessment booking (reuses the slot-grid), and a coach-set placement result — see DATA-MODEL §2. This is small but launch-blocking: without it, a brand-new student has no way in. Revised 2026-07-27: corrected state machine isregistered → level_0 → placed | auto_placed(DATA-MODEL §2). No booking; the first recitation is aSubmissionsubtype routed to a pooled placement queue (rotating coaches claim from it — replaces the shared-login account). Level 0 is the full app minus lessons; a never-submitter is auto-placed into Level 2 after reminder emails (email-automation workstream). Add an availability capture at onboarding for every placed student (general availability, feeds all scheduling). Retire any font/script-preference storage. - Student, Course, Level, Lesson, Video-progress, Submission (audio file + status: not-started/in-progress/submitted/revoked) tables/collections
- Audio upload pipeline (record → resumable upload → storage) — see Section 3
- Weekly rhythm state machine: current week number, submission deadline, attempts-remaining counter, 2/week limit + revoke window enforcement
- Push notification registration (even if no notifications are sent yet — wire the token collection now)
Exit criteria: a real student can complete onboarding, watch this week's lesson, record an attempt, submit it, and see it move through Ready → In Progress → Submitted → (revoke window closes) with no coach-side app yet (feedback can be seeded manually/by hand for pilot testing). This phase is usable standalone if coaches temporarily keep using their current review process for one more cycle while Phase 2 builds.
Phase 2 — Feedback loop closure + coach review app
This is the single most-requested fix across all four feedback sources ("teachers can't see the assignment text while reviewing audio" is called the most damning fact in the current app) and makes coaches, the bottleneck users, actually adopt the new system.
Screens:
- Section F1: Submission — feedback ready, Submission — in review/revoke window, Practice the corrections, Practice — review take
- Section 02: Submissions archive, Notifications sheet, Notification settings
- Section 06: Submissions — empty archive, Notifications — all caught up, Recording — mic permission
- Section C (coach app, full): Coach — review queue, Coach — review a submission, Coach — student record, Coach — my schedule
Backend surface:
- Coach role + coach-student assignment table
- Feedback object: text-span-anchored annotations on assignment text, coach audio reply, pass/fail, timestamp, linked to the submission
- Full multi-semester submission/feedback history per student (queryable by both student and any coach who has taught them — cross-coach shared notes per the wishlist)
- Practice-take handling: takes attached to feedback, don't burn attempt count (per REVIEW.md C3)
- Coach queue view (submissions awaiting review, sorted/filtered)
- Notification triggers: feedback-ready push to student, new-submission push to coach
Exit criteria: a coach can open the queue, see assignment text and audio side by side, leave annotated + voice feedback, and the student sees it arrive, practices, and resubmits — all in-app, replacing notebooks/Excel/ second devices. Pilot with 2–3 coaches here (see Risk R3) before wider rollout.
Phase 3 — Schedule, notifications, announcements/messaging
Solves the second-most damaging problem class: timezone bugs, no attendance signal, and the community-board replacement decided on the coaches' call.
Screens:
- Section 00a: Sessions — Recordings
- Section F2: Week at a glance
- Section F3: Announcements, Messages — Ustadha Amina
- Section 03: Live class — Sisters' QRC
- Section 04 (billing can slide to Phase 4 if tight, see note below)
SakSessionDetail/SakSessionDetailQRC(not on canvas, but required here — they're the notification-tap deep-link destinations per REVIEW.md C4)
Backend surface:
- Session/class schedule data model with UTC storage (see Section 3) — recurring sessions (weekly class, QRC) and one-off (drop-in Q&A)
- Zoom integration: deep link generation (
zoommtg://), attendance duration fetch (feeds Phase 4's auto-attendance) - Reminder scheduling: 15-min student / 30-min teacher pushes, calendar add (.ics or platform calendar intent)
- Announcement board: one-way, audience-filtered by year/level
- 1:1 messaging: guarded (length warning ~800 chars, weekly cap), coach ↔ student only, routes from both SakCoach and Profile per REVIEW.md B5
- Notification inbox aggregating session reminders + announcements + feedback-ready, with announcement rows deep-linking to the board (REVIEW.md C1/B4)
Exit criteria: every displayed time is correct in the viewer's local zone (this is the phase to run the DST/timezone test matrix from Section 3 against, not defer); a student gets a real Zoom link at the real local time; a coach and student can message inside guardrails; the community-board replacement is live for both years.
Phase 4 — Year-2 appointments, attendance automation, issue reporting, subscriptions
The long tail: features that matter but don't block Year-1 students' daily loop, plus the business-operations surface.
Revised 2026-07-26 (product review with Lejla, Jul 24): the Year-2 appointment work here changed shape. Booking is now per week across the coach team with a weekly cap (soft cap 3, included in tuition), not a recurring 15-week slot lock — the recurring option is dropped pending Q13. Year 2 has no submissions, so this phase also delivers the appointment-notes pipeline (coach records a debrief → transcribe → auto-summary → coach edits → send) and its two new screens. Note the entry/placement flow moved to Phase 1 (it gates first-run); only the Year-2 loop stays deferred here to November.
Revised 2026-07-27 (Lejla review): three Year-2 corrections land in this phase. (a) the weekly appointment count is plan-based, bought at checkout (default 1/week for every elective; only Tajweed Practice sells 2–3), not a universal soft cap of 3 — all allowance copy derives from the student's own
appointment_plan("Your plan includes N appointments a week"). (b) Year-2 lessons are per-elective (only Tajweed Practice has none; its Today is appointments-led) — the shared-lessons assumption is wrong; the sole universal Y1→Y2 difference is feedback format. (c) two Year-2 arrival scenarios: Level-4 graduates auto-enrolled into the mandatory first semester get a celebratory hype sequence (placeholder copy this pass; Yasmeen owns the sensibility, Lejla provides the graduation-email copy source), while returning elective students arrive via checkout with no hype plus a change-elective housekeeping line (first week, email admin). NewElectiveentity andappointment_planfield — DATA-MODEL.
Screens:
- Section F4: Report an issue, Today — pre-semester countdown
- Section F5: Book your one-to-one (revised: per-week, multi-coach, weekly cap), Appointment — recurring weekly (now a single-week appointment detail pending Q13), Availability (Year-2 booking)
- Section Y2 (new, Revised 2026-07-26): Year 2 orientation, Today — Year 2 (no record CTA), Appointment — teacher's notes
- Coach — appointment notes (new, Revised 2026-07-26) — the coach-side notes pipeline
- Section 04: Subscription & billing, Manage subscription
- Section 06: Today — rest day, Profile — first week (remaining states)
Backend surface:
- Appointment lifecycle. Revised 2026-07-26: per-week booking across the coach
team with a weekly cap (soft cap 3/week, included in tuition) — the recurring
15-week slot lock is dropped pending Q13; each
Appointmentcarries its owncoach_id(a Year-2 student is not bound to one coach). 15-min reminder, attendance capture, notes visible to any teacher who's met the student, and auto-email escalation after 2 consecutive absences all carry unchanged to multi-coach weeks (confirm Q7). - Appointment-notes pipeline (new, Revised 2026-07-26): record a post-appointment
debrief → transcribe → auto-summary → coach edits (the edit is the approval, Q12) →
send to the student. New
AppointmentNoteentity + state machine (DATA-MODEL §2), a coach-side edit UI (Coach — appointment notes), and the student-facing Appointment — teacher's notes screen. This is Year 2's feedback object, replacing the Year-1 submission/Feedbackpair. - Auto-attendance from Zoom duration ≥75% (absorbs the Time Clock Wizard workflow, feeds coach hour-logging)
- Report Issue: auto-attached screen/app-version/account context, routed wherever the team currently triages support (email, ticketing tool). Global reachability without persistent UI: hook the iOS screenshot and shake gestures to open the report sheet with the screen attached (the TestFlight pattern). Decided 2026-07-16 in place of the floating button the teachers' call proposed — a permanent visible button invites misuse as a support/messaging channel.
- Live-session RSVP: a one-tap "Going / Can't make it" response on the session detail (now in the mockup), feeding a per-session headcount for staff. Attendance itself stays automatic (Zoom join data) and is shown to the student as a quiet summary line ("You've joined 6 of 8 circles"), never asked for — requested on the teachers' call and in the coaches' questionnaire (Rania: a way for students "to mark if they will attend")
- Stripe integration: subscription state, cancellation flow (framed as choice, not failure, per the mockup's enrollment section), webhook-driven status sync back to the student's access level
- Student availability capture during Year-2 booking/enrollment — not first-run onboarding (REVIEW.md C5) — feeds Year-2 scheduling
Exit criteria: Year-2 students can book and manage a 1:1 without an email chain; attendance is a real number instead of an assumption; billing state changes (upgrade/cancel/lapse) reflect correctly in what content a student can access.
Note: if Phase 3 runs long, subscription/billing (Section 04) can move earlier or later relative to appointments — it has no dependency on the scheduling work and can be sequenced independently based on business urgency (e.g., if Stripe migration has a deadline, pull it into Phase 3).
3. Cross-cutting workstreams
These don't belong to one phase — get them right early because retrofitting is expensive.
Timezone / DST correctness
Strategy: store every timestamp in UTC, render in the viewer's IANA timezone (not a fixed offset like "EST" — REVIEW.md's B3 finding, bare EST/EDT strings that had to be swept out of an earlier mockup iteration, is exactly the bug class to avoid), derive the timezone from device settings at render time, never trust a stored offset for the future.
This needs a dedicated test matrix, not ad hoc QA, because the reported production bug (calendar shows 7 PM for an 8 PM class) is a class of error that silently reintroduces itself:
- A US Eastern viewer and a Toronto viewer during the US/Canada DST gap (US switches ~1–3 weeks apart from EU some years — actually same week currently, but the code must not assume that)
- A Europe/EU viewer during the EU-vs-US DST transition week (the actual gap period where US and EU clocks are offset by a different amount than usual)
- Turkey (no DST since 2016, fixed UTC+3) and Egypt (DST history has flip-flopped by government decree in recent years) as no-DST or irregular-DST cases that break any hardcoded "add 7 hours" logic
- A recurring weekly booking that spans a DST transition — does the local wall-clock time stay fixed (correct) or does the UTC instant stay fixed (wrong, shows up as a 1-hour drift for half the recurrence)
Recommend this become an explicit automated test suite (fixed set of UTC instants × viewer timezones × expected rendered string), not manual spot-checks, given it's already bitten production once.
Audio pipeline
- Record: platform recording API via RN wrapper, capture at a consistent bitrate/format for consistent playback across devices
- Upload: resumable (chunked or tus-protocol-style) — coaches and students are plausibly on inconsistent connections; a dropped upload should resume, not restart or silently fail
- Playback + scrubbing: needs frame-accurate seek for coaches reviewing specific passages, and for students re-listening to feedback at a specific timestamp (feedback is timestamped per the wishlist)
- Waveforms: compute once server-side or client-side at upload time and store the peak data alongside the audio file — don't recompute on every playback
- Budget an early spike (before Phase 1 commits to final APIs) to confirm RN audio libraries meet the scrubbing/waveform bar; this is the piece most likely to need a native module fallback.
- Interruption survival (from the coaches' questionnaire): recordings in the current app are lost to incoming phone calls and to force-logout when a second device signs in. Recording must survive audio-session interruptions (pause + resume with the partial take intact) and an auth change must never discard an in-progress recording. Also from the questionnaire: feedback comment text is truncated in the current app — any text field that stores more than it displays is a bug class to test for explicitly.
Arabic text rendering — flag early, spike first
This is the hardest UI problem in the whole rebuild and should get a spike in Phase 1 before the recording/annotation screens are built on top of it, not discovered mid-Phase-2. The requirement (from the coach feedback: "mark up submission text... text-span anchored annotations") means annotations must anchor to specific words within Quranic Arabic text, which involves:
- Correct right-to-left, contextual letter-shaping rendering (standard in modern text stacks, but verify RN's text engine + chosen Quranic font handle it without breaking on diacritics)
- Word-level (not just character-offset) anchoring for annotations, robust to font/size changes and the font-picker feature (Section 02) — an annotation anchored to a pixel position breaks the moment the user changes font or text size; anchor to a semantic word/ayah index instead computed from the Uthmani/Quranic text data source, not from rendered glyph positions.
- Correct rendering of tajweed marks / makharij diagram overlays mentioned in the coach questionnaire, without fighting the RTL layout
Recommend: build a throwaway prototype of "render a verse, place a marker on word 4, change font size, marker stays on word 4" before committing the annotation feature's data model. If this doesn't work cleanly in RN's text primitives, a native text-rendering module is the fallback — decide before Phase 2, not during it.
Push / email infrastructure
- Push: Expo push service (wraps APNs/FCM) is sufficient given the BaaS choice; if Firebase is the BaaS, use FCM directly for both push and potentially in-app messaging.
- Email: transactional email provider (existing tool if the org already has one for enrollment, otherwise a standard provider) for the escalation emails (2 consecutive absences), receipts (Stripe), and any digest/ reminder emails that duplicate the push channel for reliability.
- Both need a single "notification dispatch" service layer (a BaaS Cloud Function) so timing, dedup, and localization logic live in one place rather than being reimplemented per trigger (session reminder, feedback ready, announcement, escalation).
Analytics for the attendance/engagement gap
The team's own words: "100% of the time currently, we are going off of assumptions" about attendance. Since Phase 4 introduces real attendance and Zoom-duration data, instrument from day one so historical data exists when leadership eventually asks for trends:
- Event logging for: session join/leave, lesson video watch completion, submission timing (on-time vs. late in week), revoke usage, message volume, coach response latency
- This can be as simple as a BaaS analytics table + scheduled export, it does not need a dedicated analytics platform at this org's scale — but it needs to start recording from Phase 1, not be bolted on retroactively when someone asks for a report in year two.
- The backlogged "AI-aggregated post-session survey trends" item depends on this data existing; build the capture now even though the AI analysis is explicitly out of scope for v1.
4. Risks and mitigations
R1 — Rocky launch is the default expectation, not a worst case. A full rebuild replacing an unknown-quality backend will have launch bugs. Mitigate with: the Report Issue button (Phase 4, but consider pulling its backend — auto-attached context capture — earlier if feasible, since it's cheap and valuable from day one of any beta), feature flags on newer/riskier surfaces (messaging guardrails, auto-attendance, appointment booking) so a bad rollout can be toggled off without a full app release, and a staged rollout (pilot cohort → one year group → everyone) rather than a big-bang release to the full student body.
R2 — Team size and bus factor. The September deadline (Section 5) requires 2–3 developers in parallel — a single developer cannot hit the date, and with a small parallel team the bus-factor risk shifts from "one person knows everything" to "no slack to absorb losing anyone mid-build." Mitigate with: RN/TS (larger substitute-hire pool than a native+BaaS mixed stack would require), a managed BaaS specifically because it reduces the amount of bespoke infrastructure only one person understands, and written architecture notes / a handoff doc as a deliverable at the end of each phase, not just at project end — so a mid-project developer change doesn't require reverse-engineering everything from scratch.
R3 — Coach adoption depends on the review workspace actually being better than a spreadsheet, not on it existing. 8/11 coaches maintain a patchwork workaround today; if Phase 2's review queue is clunkier or slower than what they've built for themselves, they will route around it, and the single most-requested fix in this whole project will fail to land. Mitigate with: pilot Phase 2 with 2–3 coaches (ideally including the desktop-preferring coach and a high-volume mobile coach) before rolling to all 11, treat their first two weeks of real usage as a gate before wider release, and make sure the pilot includes actual review of live students, not a demo dataset — workflow friction only surfaces under real load.
R4 — Timezone bugs recur. Already burned production once (7 PM vs 8 PM bug) and is exactly the kind of defect that regresses silently when a new screen is added by someone who didn't know the rule. Mitigate with the explicit test matrix in Section 3, and a lint-level rule/code-review checklist item: no screen may render a hardcoded offset string ("EST"/"EDT") — always derive from device timezone at render time.
R5 — Arabic annotation anchoring is underspecified until the spike runs. If word-anchored annotation turns out to be harder than expected in RN, it could blow out Phase 2's timeline specifically (the feature most tied to coach adoption, per R3). Mitigate by running the spike in Phase 1 (Section 3), not discovering the problem mid-Phase-2 when the review queue UI is already built on a broken assumption.
R6 — BaaS lock-in / limits. Managed BaaS trades control for speed; if the org later needs the backlogged student-centric scheduling algorithm or heavier custom logic, BaaS query/function limitations could force a partial migration. Mitigate by choosing Supabase (Postgres underneath) over Firestore if this is a concern — Postgres data is far more portable to a custom API later than a Firestore export would be.
5. Delivery plan — live for the fall semester (September 2026)
The deadline is fixed; scope and team size are the variables. Two facts frame everything below:
- Engineer-weeks are not calendar weeks. The 26–38 engineer-week total still holds — but from a ~July 21 start to a first-week-of-September launch there are ~6½ calendar weeks. Three developers working in parallel give ~19 engineer-weeks of capacity in that window; two give ~13. The full scope does not fit. A subset launches in September; the rest lands during the semester — which the semester structure actually supports, because students don't need Year-2 booking or billing screens in week 1.
- One developer cannot hit this date. The original single-developer framing is dead for this deadline. Minimum viable team: 2 full-stack RN/BaaS developers; 3 is the realistic number (one on the student app, one on backend + coach app, one on the schedule/notification surface and the test matrices). Phases 1 and 2 are sequentially dependent, but backend models, the coach app UI, and the Phase-3 schedule slice parallelize well.
Launch scope — in students' hands for week 1 of the semester
| # | What ships | From | Effort (ew) |
|---|---|---|---|
| 0 | Spikes: Arabic word-anchored annotation + audio record/upload/scrub | pre-Phase 1 | 2–3 |
| 1 | Auth + entry/placement flow (new, Revised 2026-07-26 — gates first-run; Revised 2026-07-27 — recorded recitation reusing the submission pipeline, supportive screens, Level-0 states; font/script picker cut; availability step for placed students), four tabs, onboarding, lesson → recording → submission loop | Phase 1 (full) | 6–8 |
| 2 | Coach essentials: queue, review workspace (text + audio side by side, annotations, voice reply), feedback-ready loop back to the student | Phase 2 (core) | 5–7 |
| 3 | Schedule slice: session list in correct local time, Zoom join links, 15-min reminders | Phase 3 (slice) | 2–3 |
| Launch total | 15–21 ew — fits 3 devs × 6½ weeks if the spikes go well |
Launch = the weekly loop works end to end: a student onboards, sees Week 1, watches, records, submits; the coach reviews in-app; the student hears feedback; nobody misses a session because of a wrong clock. That is the whole audit answered on day one — everything else is enhancement.
In-semester scope — shipped as updates while the semester runs
- Weeks 2–5 (by early October): rest of Phase 2 (practice takes, submissions archive, notification settings), announcements board, session recordings, guarded messaging.
- By mid-semester (November): Year-2 loop — per-week multi-coach appointment booking with plan-based counts (Revised 2026-07-27: allowance derives from the student's purchased plan, not a universal cap; recurring lock deferred pending Q13), the appointment-notes pipeline (record → transcribe → auto-summary → coach edit → send) and its screens (Year 2 orientation with the Level-4 hype sequence, Today — Year 2, Appointment — teacher's notes, Coach — appointment notes), per-elective lessons, auto-attendance from Zoom duration, Report an Issue, Stripe/subscription surface, remaining empty/edge states.
- Android: launch is iOS-first. RN builds Android from the same code, but a second platform's testing surface does not fit the window — Android follows in-semester once the iOS launch stabilizes.
Calendar (assumes start Monday, July 21)
| Dates | Milestone |
|---|---|
| Jul 21 – Jul 25 | Team signed, BaaS chosen (Supabase per Section 1), repos/CI/EAS set up, both spikes run — spike results gate the annotation data model |
| Jul 28 – Aug 15 | Phase 1 complete; backend models + coach app build in parallel; TestFlight internal build from ~Aug 4 |
| Aug 18 – Aug 22 | Phase 2 core complete; schedule slice lands; DST/timezone test matrix runs |
| Aug 25 – Aug 29 | Coach pilot (2–3 coaches, real recitations) and student dry-run; fix window |
| ~Aug 28 | App Store submission (review turnaround is calendar risk — submit before the fix window closes, use expedited review if needed) |
| Sep 1 – Sep 5 | Staged rollout to the cohort; onboarding emails; semester starts with the app live |
What the September date costs (say it out loud now, not in October)
- The coach pilot compresses to one week. R3 says adoption depends on the workspace beating the coaches' spreadsheets under real load; one week of pilot is the minimum honest version of that gate. If the pilot fails, the fallback is launching Phase 1 student-side while coaches keep their current process for the first cycle — the plan's own Phase-1 exit criterion allows this.
- Feature flags are mandatory, not optional (R1): reminders, annotations, and anything shaky ships behind a flag so launch week never needs an emergency App Store release.
- The spikes move to week one and become go/no-go gates. If Arabic word-anchoring fails in RN primitives (R5), the launch scope keeps coach review with timestamped audio + free-text feedback and word-anchored annotations follow in-semester — decided in week 1, not discovered in August.
- No slack for a mid-project developer change (R2) — the phase-end handoff-notes discipline matters more, not less, at this pace.
Decisions needed from the org this week
- Confirm the actual semester start date — this calendar assumes first week of September; every milestone moves with it.
- Commit the team by July 24. 3 developers (2 minimum with the reduced scope noted above). Later than that, subtract the days from the pilot and fix window — the deadline doesn't move, the safety margin does.
- Is Year-2 1:1 booking needed at launch? This plan defers the Year-2 loop (per-week multi-coach booking, appointment notes) to November with an email-chain fallback for the first weeks. If it must exist on day one, something of equal size leaves the launch scope (candidate: the reminders slice). Revised 2026-07-26: the entry/placement flow is not deferrable — it gates first-run for every new student, so it is in the launch scope (Phase 1) regardless of the Year-2 decision.
- Content readiness: week-by-week lesson videos and curriculum text must be uploaded by mid-August — engineering can't absorb a content delay.
- Confirm the Year-2 product defaults (Revised 2026-07-26). The design encodes
working defaults pending Lejla — see
../../explorations/flow-map/QUESTIONS-FOR-LEJLA.md. The one that changes engineering shape most is Q13: offer an optional recurring "same slot weekly" booking, or per-week only? The current build assumes per-week only; confirming Q13 (and the placement SLA Q2, magic-link auth Q4, soft cap Q5, one shared coach pool Q11, single-approver notes Q12) unblocks the Phase-4 Year-2 work. Revised 2026-07-27 (Lejla review): Q1, Q2, Q4, Q5, Q8 are now answered — the first assessment is a recorded recitation to a pooled coach queue (Q1); Level-0 waiting is student-paced with auto-placement (Q2); sign-in is email + password, no magic link (Q4); appointment counts are plan-based, bought at checkout, not a universal cap (Q5); lessons are per-elective (Q8). Q3 confirmed (new students → Year-1 only), Q9 refined (auto-enroll for level graduates; electives/repeats via checkout). Still open and engineering-shaping: Q13 (per-week vs optional recurring), Q11 (one shared coach pool), Q12 (single-approver notes), plus two new items — Q15 (exact name of the mandatory first Year-2 semester, tentatively "Advanced Tajweed Rules") and Q16 (the student-facing rename of the first assessment).
Notes on the effort arithmetic (unchanged from the original sizing):
- Coach pilot cycles (R3) and the DST test matrix (R4) are inside the estimates, not additional.
- Store review turnaround is calendar time, not engineering time — it is why submission is Aug 28, not Sep 1.
- The original full-scope table (26–38 ew across Spike + Phases 1–4) remains the basis for the in-semester waves; nothing was re-estimated downward to fit the deadline — scope moved instead.