# Phonics Mentor — project context

Online phonics tuition platform for children aged 3–8. Parents enrol a child into a batch
taught by a phonics teacher. Classes run on Google Meet. The platform handles discovery,
demo booking, enrolment, fees, scheduling, attendance, homework, progress reporting, and a
gamified practice zone for the child.

## Stack

- Laravel 12, PHP 8.3
- Livewire 3 + Alpine.js (full-page Livewire components per panel)
- Tailwind CSS 3 with a custom theme (see `tailwind.config.js`)
- MySQL 8, single database
- Breeze (Livewire stack) for auth; Sanctum for the Phase 4 Flutter API
- Razorpay for payments, FCM for push, cPanel SMTP for mail
- Gemini Flash-Lite for progress report drafting
- DomPDF for certificates and invoices
- Queue: database driver. Scheduler via cron.

## Locked product decisions

1. Teachers are **employed**, not a marketplace. Admin sets all pricing. No teacher-side pricing UI.
2. **Online only.** `batches.mode` exists for future offline/hybrid but only `online` is used.
3. Curriculum is **Jolly Phonics style**: 7 groups, 42 sounds, tricky words. Seeded.
4. Domain: `phonicsmentor.in`
5. Both **group** and **one-on-one** batches. `batches.type` drives fee plan selection.

## Explicitly out of scope

Do not build or suggest: video SDK integration (Zego/Zoom/Jitsi), automatic class recording,
Google Calendar API, WhatsApp Business API, Twilio SMS. Meet links are pasted manually by
the teacher on the batch. `class_sessions.recording_url` exists but stays unused.

## Roles

| Role | Prefix | Middleware |
|---|---|---|
| admin | `/admin` | `role:admin` |
| teacher | `/teacher` | `role:teacher` |
| parent | `/parent` | `role:parent` |
| kid zone | `/play` | `role:parent` + `child.selected` |

A parent may have several children. `session('active_child_id')` selects the current one via
`User::activeChild()`. **Every parent-side and kid-zone query must scope to the active child.**
Children never get their own credentials — an optional 4-digit PIN gates the kid zone only.

## Non-negotiable rules

1. `meet_link` and `recording_url` are `$hidden` on `ClassSession`. Only `ClassJoinController`
   may read them. They must never reach a Blade view, JSON response, or Livewire payload.
2. AI progress reports are **never auto-published**. A human reviews, then publishes.
3. Every `/teacher` and `/parent` component must verify ownership through a policy. Never trust
   a route ID.
4. Money is `decimal(10,2)` everywhere. Never float columns.
5. Datetimes stored UTC, displayed `Asia/Kolkata`.
6. Razorpay: always verify signature server-side. Webhooks must be idempotent (check
   `razorpay_payment_id` before acting) and return 200 fast, queueing heavy work.
7. Session generation only ever touches future sessions with status `scheduled` and no
   attendance rows. Past sessions are immutable.
8. Kid zone: minimum 64px tap targets, no external links, no ads, no free-text chat.

## Key business rules

- **Join window**: opens 10 min before `scheduled_at`, closes 15 min after the session ends.
  Outside it the button renders as a disabled countdown.
- **Fee blocking**: an invoice unpaid past `due_on + 5 days` blocks joining, unless
  `enrollments.grace_until` is in the future (admin override).
- **Attendance**: the join click writes `clicked_join_at`, which pre-fills the teacher's
  toggle. The teacher's `marked_status` is authoritative. If neither exists 24h after a
  session ends, mark absent automatically.
- **Session generation**: activating a batch generates 90 days of sessions; a nightly job
  tops up the rolling window.
- **Cancelled sessions** do not count toward attendance percentage or teacher payout.

## Layout

```
app/
  Http/Controllers/ClassJoinController.php   # the only place meet links are read
  Http/Middleware/EnsureRole.php
  Http/Middleware/EnsureChildSelected.php
  Livewire/{Admin,Teacher,Parent,Kid,Public}/
  Models/                                    # 22 models, all present
  Services/BatchService.php                  # session generation
  Policies/
database/migrations/                         # 26 migrations, all present
database/seeders/                            # Curriculum (42 sounds), FeePlan, Badge
```

## Design tokens

Fonts: `Fredoka` for headings and kid zone, `Nunito` for body and admin.
Colours: `coral` (primary CTA), `sunny` (rewards), `mint` (success), `sky` (info),
`ink` (text), `cream` (page background). Radius `rounded-2xl` default, `rounded-3xl` cards,
`rounded-4xl` kid zone. Shadows `shadow-soft` / `shadow-lift`. Component classes
(`.btn-primary`, `.card`, `.kid-tile`) are in `resources/css/app.css`.

Admin and teacher panels use the same palette but calmer: more whitespace, standard text
sizes, data-dense tables allowed.

## Build order

- **Phase 1** — foundation: migrations, models, policies, roles, admin CRUD (teachers,
  levels, batches, fee plans), session generation, public site + demo booking, parent
  registration + children, enrolment, Razorpay one-time payment, invoices, join redirect.
- **Phase 2** — teaching loop: teacher dashboard, session room (attendance + 3-score
  feedback), homework cycle, parent progress, FCM, email reminders, overdue blocking, payouts.
- **Phase 3** — kid zone (sound board, blending game, tracing canvas, flashcards, progress
  map, badges), Gemini reports with review-and-publish, certificates.
- **Phase 4** — Flutter apps (parent+kid, teacher) on Sanctum.
- **Phase 5** — subscriptions, referrals, waitlist, white-label.

Phase 1 is done when a parent can register, add a child, enrol, pay, see the schedule, and
click join inside the window — and that click lands in `attendances`.
