# AGS Vocab — Claude Code entry pointer

> **READ FIRST (in this order):**
> 1. **[docs/HANDOFF.md](docs/HANDOFF.md)** — the steady-state design of the
>    whole AGS app family (vocab + account + math). Architecture, every
>    subsystem, deployment runbooks, common pitfalls, outstanding work.
> 2. **[docs/SESSION-LOG.md](docs/SESSION-LOG.md)** — newest-first chronological
>    journal. Skim the top 1-2 entries to see what changed since the HANDOFF
>    was last refreshed.
>
> Reading these two before grepping the code saves thousands of tokens.

## Stack (one-liner)

Laravel 11 + Sanctum + Cashier + Filament v6 (backend at `vocabapi.allgifted.com`),
Flutter web PWA in `mobile/` (frontend at `vocab.allgifted.com`), MySQL `vocab`
schema, 3PL IRT engine, OTP auth + SSO via `account.allgifted.com`, Stripe
(test mode) for premium subscriptions + lives packs, Anthropic Claude for
the AI vocab tutor on wrong answers. All on one DigitalOcean droplet
(152.42.223.228) co-tenanted with AGS Math.

## Production URLs

- https://vocab.allgifted.com — learner Flutter PWA
- https://vocabapi.allgifted.com — API + Filament admin
- https://account.allgifted.com — SSO sign-in + app launcher

## Test types (gate matrix)
| Test type | Free | Premium | Subject to 5 hearts/day |
|---|---|---|---|
| Skill Practice (`skill_practice`) | ✓ | ✓ | Free: ✓ / Premium: ✗ (unlimited) |
| Vocab Diagnostic (`vocab_diagnostic`) | premium_required (402) | ✓ | Premium: ✗ (unlimited, no deduct anyway) |
| Vocab Path (`vocab_path`) | premium_required (402) | ✓ | Premium: ✗ (unlimited) |

Both `is_unlimited_lives` (staff bypass) and `is_premium` (paying
subscribers) bypass the daily-5 limit. The snapshot reports both
separately so UI copy can differentiate.

## Lives system (daily-reset model — NOT Math's 5h regen; Math-style deduct)
- 5 hearts/day, lazy reset at midnight Singapore on any `LivesService` call
- **First wrong attempt is FREE** — learner gets a retry chance at no cost
- **Final wrong (retry-wrong OR skip-after-first-wrong) charges 1 heart**
  via `POST /api/lives/consume` — client-driven, server never deducts in
  the test flow
- Diagnostic NEVER deducts (IRT integrity), but IS gated by lives at start
- **Premium = unlimited hearts** (Math parity). `is_unlimited_lives` (staff
  bypass) and `is_premium` both flip `is_unlimited: true` in the snapshot
- 0 hearts (free user only) → `422` with `code: 205` + payment-ready snapshot

## Dev servers (local)
- Vocab Laravel API: `http://127.0.0.1:8002`
- Vocab Flutter web: `http://127.0.0.1:8001`
- AGS Math (reference only): `http://127.0.0.1:8000`

## Key accounts
- `pamelaliusm@gmail.com` — admin, `is_premium=true`, `is_unlimited_lives=true`
- `learner@vocabile.test` — test learner, free tier

## Habits to keep
- **Update `docs/SESSION-LOG.md` at every commit.** Newest entry at the top.
  This is the user's explicit ask — keeps token usage down across CC sessions.
- **Update `docs/HANDOFF.md`** when you change a subsystem's design (not on every
  commit — only when the steady-state shape changes).
- Run `php artisan test` after backend changes; should be 53+/53+ green.
- Run `flutter analyze` on touched Dart files before committing.
- Use `Bash`/`Edit`/`Grep`/`Glob` directly — they're scoped tighter than the agent fallback.
- For SSH-to-droplet work: PowerShell mangles bash heredocs. Write scripts
  to local `deploy/*.sh`, scp them up, run via `ssh ... 'bash /tmp/...'`.

## Reference paths (cross-app patterns)
- AGS Math backend (reference) — `c:\allgifted\mathapi11v2`
- AGS Math Flutter (reference) — `c:\allgifted\flutter_demo`
- AGS palette + brand — `c:\allgifted\flutter_demo\AGS_MATH_PALETTE.md`
- AGS Account repo (sibling, ours) — https://github.com/2ppaamm/account
- Parent portal (planned consumer) — `c:\projects\ags_parent`
