# Portal — Parents, Teachers & Schools

Customer surface for **portal.thewordquest.com**. Distinct from platform **admin** (`admin.thewordquest.com`). Until Firebase lands, portal reads/writes the same Firestore-shaped stand-in under [`../admin/database/`](../admin/database/) via [`DatabaseClient`](../admin/js/database-client.js) (symlinked into `portal/`).

---

## Audiences

| Role | Goal |
|---|---|
| **Parent** | Link or create child accounts; limit games, time, and devices; lock/unlock on demand; see progress. |
| **Private tutor** | Run live lessons + homework for 1:1 students (Preply, Superprof, etc.). |
| **School teacher** | Teach a class roster; assign packs/homework; share coverage with colleagues. |
| **School admin** | Manage teachers, classes, seats, and shared lesson library for an organisation. |

Learners stay on **app.thewordquest.com**. Portal never edits the global word CMS or game physics.

---

## Design characterisation — teachers & schools

### A. Private tutors (marketplace / freelance)

**Who:** Independent tutors selling slots on Preply, Superprof, italki-style platforms, or privately.

**Org shape:** Optional `tutorPractices/{id}` (solo “practice”), not a school. Students link via `relationships` type `teacher_of` with `context: "private"`.

**Primary jobs**
1. See **all students** in one list with last activity + struggle words.
2. **Quick links** for the next live lesson (open game, word focus pack, island jump deep-link).
3. **Reusable lessons** — templates they rinse-and-repeat across students.
4. **Per-learner customisation** — pin focus words, preferred games, homework cadence.

**Not primary:** multi-teacher rotation, year-group rosters, seat licensing (unless they later upgrade to a practice with assistants).

### B. Day-school teachers

**Who:** Employed teachers in primary / prep / grammar-feeder day schools.

**Org shape:** `schools.type = "day_school"`. Classes (`Year 5A`) own `teacherUids[]` + `learnerUids[]`. Teachers may co-own a class for cover.

**Primary jobs**
1. Class roster progress at a glance.
2. Curriculum packs aligned to school year.
3. Homework assigned to whole class or groups.
4. Hand-off: another teacher on the same class can open the same lesson run.

### C. Afternoon / weekend supplementary schools

**Who:** After-school 11+ centres, Saturday schools, intensive holiday clubs.

**Org shape:** `schools.type = "afternoon_school"`. Often multiple short cohorts, teachers rotate between rooms/cohorts more than day schools.

**Primary jobs**
1. Shared **lesson library** at org level (not only personal templates).
2. **Teacher rotation** — assign cover / co-teachers without re-inviting every child.
3. Cohort attendance-style lesson runs (who was in the 16:00 group).
4. Tighter timeboxes — lessons are 45–90 minutes; quick-launch matters more than long homework arcs.

### D. School organisation (shared)

Whether day or afternoon:

| Capability | Notes |
|---|---|
| Seats & roster import | School admin only |
| Classes / cohorts | Named groups; multiple teachers |
| Teacher invite & revoke | Email invite → accept |
| Shared curriculum packs | `ownerUid` + optional `schoolId` |
| Cover / rotation | `classes.teacherUids` + optional `coverSchedule` stubs |
| Analytics | School-scoped aggregates (later) |

Private tutors may **upgrade** a practice into a mini-org (assistants) without changing the student experience.

---

## Parent controls

### Account linking

1. **Create child** from parent account (generated learner uid + display name + join code).
2. **Link existing child** via join code / invite the child already uses.
3. Multiple parents may link the same child (permissions per relationship).

Permissions on `parent_of`: `viewProgress`, `setGameBans`, `setTimeLimits`, `setDevicePolicy`, `lockUnlock`.

### Session (portal meaning — not arcade levels)

A **Play Session** is one continuous period of **authenticated learner play** in the Word Quest app.

| Starts | Ends |
|---|---|
| Learner signs in / resumes while **unlocked** and within policy | Parent lock; daily/session budget exhausted; idle timeout; explicit sign-out; or midnight rollover of daily counters (configurable) |

Not the same as an in-game arcade “3 levels” block (`game-levels.js`). Portal sessions meter **clock time and visit count**.

### Limits parents can set

| Control | Meaning |
|---|---|
| Daily duration | Max minutes of Play Sessions per calendar day (learner timezone or parent-chosen TZ) |
| Session duration | Max minutes per single Play Session |
| Visits / day | Max Play Session starts per day |
| Allowed windows | Time-of-day ranges (e.g. 16:00–19:30 on weekdays) |
| Game / category bans | Deny list (allow-list optional later) |
| Instant lock | Block all play until unlock |
| Bonus time | One-shot extra minutes for today (does not change the standing daily cap) |

### Devices & user agents

- Learner must **sign in once** on a browser for it to appear under “Previously used devices”.
- Matching is by **user-agent string** (and coarse hints), **not** a hardware ID. The web cannot tell Chromebook A from Chromebook B with the same UA.
- Admin maintains `userAgentCatalog` (friendly labels: “Chrome on Chromebook”, “Safari iPad”, …). Unknown UAs still appear as raw strings.
- Parent copy must state clearly: blocking “iPad” blocks **any** browser that reports that UA — including a sibling’s identical model — until a native app can do stronger device binding.

### On-demand overrides

- **Lock now** / **Unlock now**
- **Add bonus time** (e.g. +15 minutes today)
- Temporary “allow this window once” (optional v2)

---

## Teacher module — product surface

### Home

- Student / class switcher
- Today’s lesson run (if scheduled)
- Struggle-word strip for selected learner
- Quick actions: Launch focus game, Open homework, Duplicate last lesson

### Lessons

A **Lesson** is a reusable template:

- Title, duration estimate, island/word focus, recommended games, teacher notes, homework recipe
- `visibility`: private | school_shared
- Clone → new lesson; Run → `lessonRuns` instance for a student or class

A **Lesson run** is one delivery (live or assigned): status `planned | live | done`, attendees, notes, linked homework id.

### Homework

Assigned word list + suggested games + due date; completion inferred from learner progress later (Firebase).

### Customisation per learner

Pinned focus words, preferred games, notes (“struggles with antonyms”), pace overrides — stored on `learnerProfiles/{teacherUid}_{childUid}` or relationship `meta`.

---

## Data collections (portal-owned extensions)

Existing: `users`, `relationships`, `invites`, `schools`, `classes`, `curriculumPacks`, `entitlements`.

| Collection | Doc id | Purpose |
|---|---|---|
| `parentalControls` | childUid | Limits, bans, lock, bonus minutes |
| `playSessions` | sessionId | Metered play intervals |
| `deviceSightings` | sightingId | First/last seen UA per child |
| `userAgentCatalog` | catalogId | Admin-maintained UA → label |
| `tutorPractices` | practiceId | Solo tutor org |
| `lessons` | lessonId | Reusable templates |
| `lessonRuns` | runId | Delivered instances |
| `homework` | homeworkId | Assignments |
| `learnerNotes` | noteId | Teacher notes / pins |

`schools` gains: `type` (`day_school` \| `afternoon_school` \| `other`), `timezone`, `adminUids`.

---

## Enforcement (later, on app)

Portal **writes policy**; the learner app **enforces** after Firebase Auth. Until then:

- Portal UI demonstrates controls against the local stand-in + LocalStorage overlay.
- No live lock on `app/` yet.

Admin maintains UA catalog and may audit parental lock abuse / support unlocks.

---

## Screens (v1 build)

**Parent:** Children · Controls · Sessions · Devices  
**Teacher:** Students · Lessons · Lesson runner · Homework  
**School:** Overview · Teachers · Classes  

Demo auth: role switcher (parent / teacher / school admin) — no real login until Firebase.

---

## Phasing

1. Spec + seed fixtures + portal UI against stand-in (**this pass**).
2. Wire learner app to read `parentalControls` / emit `playSessions` + `deviceSightings`.
3. Firebase Auth, Security Rules, real invites/email.
4. Native app for true device binding (post-web).
