Files

71 lines
3.4 KiB
Markdown
Raw Permalink Normal View History

# 09 — Admin billing plans UI (agent 9/20)
**Owns:** Admin → Billing → **Plans** tab (table, filters, badges), create/edit plan dialogs, assign-plan UX, companies-tab assign shortcuts.
**Does not own:** Permissions tab / `PlanPermissionsPanel` (agent 8).
**Entry:** `/admin/billing` (gate: `requirePlatformAdmin`).
---
## Delivered
1. **Plans table** — search + visibility filters (All / Public / Legacy / Custom) with counts.
2. **Badges** — Public (ladder FreeEnterprise), Legacy (A1, Basic, Professional, Mini, Merkur…), Custom (other client deals). Public + `is_custom` also shows “Custom package flag” (Enterprise).
3. **Create / edit** — polished dialog: name, description, monthly/yearly credits, max products, term, custom flag; preview of visibility kind. Wired to `POST /api/admin/plans` (upsert with `id` for edit).
4. **Assign plan** — dialog with company + plan selects, optional trial + trial credits; row actions from Plans and Companies. `POST /api/admin/plans/assign`.
5. **Link to permissions** — Plans row → Permissions tab with that plan selected (`PlanPermissionsPanel`).
6. **Companies polish** — search, has/no active plan filter, Assign plan + Add credits actions; summary card for companies without a plan.
---
## Source files
| File | Intent |
|------|--------|
| `apps/web/src/routes/admin/billing/+page.svelte` | Host page: stats, tabs, dialogs, companies table |
| `apps/web/src/lib/components/admin/AdminPlansPanel.svelte` | Plans table + filters + row actions |
| `apps/web/src/lib/admin-billing-plans.ts` | Visibility classify/filter, upsert/assign API helpers |
---
## API contract (existing)
| Method | Path | Use |
|--------|------|-----|
| `GET` | `/api/admin/plans` | List all plans (ladder + deals) |
| `POST` | `/api/admin/plans` | Upsert plan (`id` optional); body: name, description, monthly_credits, yearly_credits, max_products, is_custom, term |
| `POST` | `/api/admin/plans/assign` | `{ company_id, plan_id, is_trial?, trial_credits? }` |
| `GET` | `/api/admin/companies` | Companies + `has_active_plan` |
| `POST` | `/api/admin/credits` | Adjust balance |
| `POST` | `/api/admin/billing/run-cycles` | Due renewals |
---
## Visibility rules (UI)
| Kind | Rule |
|------|------|
| **Public** | Name ∈ Free, Starter, Growth, Business, Enterprise (`isDefaultPublicPlanName`) |
| **Legacy** | Known migrated names: A1 (+ `a1 …` prefix), Basic, Professional, Mini, Merkur*, Meur, or name contains `legacy` |
| **Custom** | Everything else (client deals / `is_custom` non-ladder) |
ASSUMPTION: Backend may later expose an explicit `is_legacy` / profile field; until then UI classifies by name (aligned with `IsPublicProductPlan` + migrated deal set).
---
## Manual verify
1. Platform admin → `/admin/billing` → Plans.
2. Filter Public / Legacy / Custom; search by name.
3. Create a custom plan; edit credits/description; confirm row badges.
4. Assign plan to a company (from Plans row or Companies → Assign plan); optional trial.
5. Click Permissions on a plan → Permissions tab opens with that plan selected.
6. Companies filter “No active plan”; Add credits still works.
---
## Coordination
- Agent 8 owns Permissions panel styling/profiles — do not rewrite `PlanPermissionsPanel`.
- Agent 5/19 may add explicit legacy profile on plans; when present, prefer API flag over name heuristics (additive).
- Agent 10 may deepen org/company management; this page only adds assign/credits filters needed for billing ops.