Files
kevin-asprec b435847a39 feat(phase-2): school registry + license management UI
Plan 2-01: School create/edit modal + license editor
- SchoolsPage: full create/edit modal (name, city, address, tier, contact,
  billing email, SMS sender name, student limit, status, notes); debounced
  search + status filter; Edit button per row opens pre-filled modal
- SchoolDetailPage: Activate / Suspend / Edit quick-action buttons in header;
  license panel with key copy, expiry, last seen (time-ago); license editor
  (expiry date, max students, tier) calls PUT /api/licenses/{id}; Revoke
  button calls POST /api/licenses/{id}/revoke
- Backend: GET /api/licenses/school/{school_id} — fetch license by school
- api.ts: getSchoolLicense added

Plan 2-02: Subscription setup + SMS credit top-up + ledger
- SchoolDetailPage: subscription panel (monthly fee, SMS cost per msg,
  billing cycle, next billing date) upserts via billing API
- SMS Credits panel: color-coded credit meter (green/amber/red based on
  balance), preset +100/+500/+1000 buttons, custom amount + note field,
  recent 5 ledger entries, link to full SMS page
- All operations toast on success/error

PAUL: Phase 2 marked complete, STATE + ROADMAP updated
2026-03-16 08:09:59 +08:00
..

Phase 2: School Registry + License Management

Status: Complete Completed: 2026-03-15

Goal

Super admin can register schools, issue license keys, set billing plans, add SMS credits, and manage the school lifecycle (pending → active → suspended/expired).

Plans Completed

2-01: School create/edit modal + license editor

SchoolsPage.vue:

  • "Add School" button opens full create modal (name, city, address, tier, contact info, billing email, SMS sender name, student limit, notes)
  • "Edit" button in each row opens pre-filled edit modal (same fields + status selector)
  • Modal validates required fields, shows inline errors, toasts on success
  • Auto-issues license key on school creation (handled by backend)

SchoolDetailPage.vue:

  • Header: Activate / Suspend / Edit quick-action buttons
  • School info panel: all fields displayed
  • License panel: key display + copy button, status badge, expiry, last seen (time ago)
  • License editor: set expiry date, max students, tier → calls PUT /api/licenses/{id}
  • Revoke button: calls POST /api/licenses/{id}/revoke → suspends school

Backend:

  • GET /api/licenses/school/{school_id} — new endpoint to fetch a school's license by school ID

2-02: Subscription setup + SMS credit top-up + ledger

SchoolDetailPage.vue:

  • Subscription panel: monthly fee (PHP), SMS cost per message, billing cycle, next billing date → calls PUT /api/billing/subscriptions/{school_id} (upsert)
  • SMS Credits panel: current balance with color-coded credit meter (green/amber/red) → preset buttons (+100, +500, +1000) + custom amount + note field → calls POST /api/schools/{id}/credits
  • Recent ledger: shows last 5 transactions (description + signed amount) → link to full SMS ledger page

Key Endpoints Used

  • POST /api/schools — create school (auto-issues license)
  • PUT /api/schools/{id} — update school details + status
  • GET /api/licenses/school/{school_id} — get license by school
  • PUT /api/licenses/{id} — update expiry, tier, max_students
  • POST /api/licenses/{id}/revoke — revoke and suspend
  • POST /api/schools/{id}/credits — add SMS credits
  • GET /api/sms/credits/{school_id} — credit ledger
  • PUT /api/billing/subscriptions/{school_id} — set billing plan
  • GET /api/billing/subscriptions/{school_id} — get current plan