# Admin guide

This is what an administrator (Pamela today; tomorrow: other schools running the same product) actually does in the system.

## Signing in

1. Go to `http://127.0.0.1:8000/admin/login` (or your deployed URL + `/admin/login`)
2. Type your **email** in the contact field (the same email seeded into `users` with `role=admin`)
3. Click **Send code**
4. The 6-digit code arrives in your email inbox (via the configured SMTP — currently Namecheap Private Email). In dev mode it's also shown on screen + written to `storage/logs/laravel.log`.
5. Type the code → **Verify & sign in**

Non-admin accounts are rejected at the verify step. There is **no password** — the AGS family is OTP-only.

To add another admin: open `/admin/users`, create the user, set `role = admin`.

## Navigation

The sidebar groups everything into six sections:

| Group | What's in it | Why you'd open it |
|---|---|---|
| **Content** | Words, Questions | Edit a word's definition, change a question's correct answer, mark something Draft |
| **Taxonomy** | Parts of Speech, Grade Levels, Bloom's Taxonomy, Skills, Word Difficulty, **Genres**, **Reader Voices** | Tune classifications, add a genre, enable/disable a reader voice |
| **Sessions** | Test Sessions | See who's taking what, when, with what score |
| **Gamification** | Kudos Events, Lives Events | Audit awards and life losses; spot suspicious patterns |
| **User Management** | Users | Add/remove admins, grant unlimited lives, see user details |
| **System** | Site Configuration, Publishing Statuses | Change the school's branding, mail credentials, accent, feature flags |

## The most common admin tasks

### Change the school's accent (read-aloud voices)
1. **System → Site Configuration**
2. Find the row `default_accent_code`
3. Edit value to one of: `en-US`, `en-GB`, `en-AU`, `en-SG`, `en-IN`, or leave blank to rotate across all accents
4. Save

The Flutter app re-loads the voice roster at next launch (or after force-refresh). The rotation pool will be only personas matching that accent.

### Add or disable a reader persona
1. **Taxonomy → Reader Voices**
2. Edit any row's `is_active` to toggle it in/out of the rotation
3. To add a new persona, click **New Voice** and fill: code, name, accent_code, accent_label, gender, character, voice_hints (JSON array of substrings), pitch, rate, letter, placard_color, mood, intro
4. Save — the Flutter app picks it up on next reload

### Change branding colors / fonts / logo
1. **System → Site Configuration**, category `theme` or `branding`
2. Edit `primary_color` / `secondary_color` / `cta_color` / etc. (hex like `#960000`)
3. `primary_font` is a Google Fonts family name (default `Raleway`)
4. `logo_path` points at a file under `public/` (default `brand/logo.png`)
5. Save — the Filament theme picks up changes within 60s (the SiteConfig cache TTL). Flutter app picks them up on next launch via `/api/config`.

### Reconfigure SMTP / change mail provider
1. **System → Site Configuration**, category `mail`
2. Edit `mail_host`, `mail_port`, `mail_encryption`, `mail_username`, `mail_password`, `mail_from_address`, `mail_from_name`
3. The password is encrypted at rest — paste it plain and Laravel encrypts via `Crypt::encryptString`
4. Save — `AppServiceProvider::boot()` re-reads and overrides Laravel's mail config at the next request (no restart needed)

Currently set to Namecheap Private Email: `mail.privateemail.com:465` SSL with `pam@allgifted.com`.

### Hide Singlish from tests
1. **System → Site Configuration**
2. Set `show_singlish` to `false`
3. Save → next test sessions skip all words with `is_singlish=true`

### Mark a question Draft / Archived
1. **Content → Questions** or **Content → Words**
2. Open the row
3. Set `status_id` to **Draft** (4) or **Archived** (5)
4. Save → the IRT engine excludes anything that isn't **Public** (3)

### Grant a user unlimited lives (proxy for "premium")
1. **User Management → Users**
2. Open the user
3. Toggle `is_unlimited_lives` to true
4. Save

This bypasses life deduction and unlocks **Vocab Path** for that user.

### See who's taking tests right now
**Dashboard** (default landing page) shows the 5 stat cards (Words, Questions, Learners, Sessions today, Kudos today) + a **Recent test sessions** table listing the last 10 sessions with status badges.

For deeper drill-down: **Sessions → Test Sessions** has filters and search.

### Audit kudos
1. **Gamification → Kudos Events** — every award has user_id, source_app, source_kind, amount, meta JSON (bloom level, skill, word_id, etc.), awarded_at
2. The `kudo_events` table is **append-only** — admin can't edit individual rows, only filter and inspect

## How the configs system works

The `configs` table is the single source of truth for everything tunable:

- **branding** — site name, slogan, logo, favicon
- **theme** — every color used in admin + Flutter UI
- **typography** — primary font (Google Fonts name), body font size, border radius
- **layout** — sidebar width, etc.
- **content** — default min/max questions per session, SE threshold
- **feature** — feature flags (lives_enabled, kudos_enabled, otp_only, show_singlish, default_accent_code)
- **mail** — SMTP host/port/encryption/username/password/from-address/from-name

Each row has:
- `key` — a slug like `mail_password`
- `value` — the current value (encrypted if type is `password`)
- `default_value` — fallback if value is null
- `type` — string | int | bool | color | url | json | font | password
- `category` — drives grouping in the admin UI
- `label` — human-readable name shown in the form
- `description` — explanation shown beneath the field (this is the **best in-product documentation**)
- `is_public` — when true the row is exposed via `/api/config` to the Flutter app

When in doubt: open `/admin/configs`, find the relevant row, read the description.
