Files
pieced-portal/README.md
admin 6baca1a459
All checks were successful
Build and Push / build (push) Successful in 1m35s
Phase1: Schema + skill event tracking
2026-05-24 00:21:29 +02:00

55 lines
1.7 KiB
Markdown

# PieCed Portal — Billing Phase 1 patch (suspend-via-admin fix)
Single-file fix on top of the Phase 1 v2 drop.
## What it fixes
The admin panel's suspend/resume button hits
`/api/admin/tenants/[name]/suspend` (a different route from the
customer-side `/api/tenants/[name]/suspend`). The v2 drop only
hooked the customer route — admin suspends were going to K8s
without producing a row in `tenant_suspension_events`.
This patch adds the same `recordSuspensionEvent` hook to the
admin route. No other code paths affected; no schema changes.
## Files
```
src/app/api/admin/tenants/[name]/suspend/route.ts MODIFIED
```
## Deploy
Extract over your `pieced-portal/` tree, rebuild, redeploy as
usual. After the new image is running, verify:
1. Suspend any test tenant from the `/admin` panel.
2. Check the events table:
```bash
kubectl -n pieced-system exec -it portal-db-1 -- psql -U postgres -d portal -c \
"SELECT * FROM tenant_suspension_events ORDER BY id DESC LIMIT 5;"
```
Expect a fresh `suspended` row for the tenant you just toggled.
3. Resume → expect a `resumed` row.
## Why I missed this
Both routes share the same shape (PATCH/POST that sets
`spec.suspend`), but they differ on:
- URL path (`/api/admin/tenants/...` vs `/api/tenants/...`)
- Method (POST vs PATCH)
- Authorization (platform-only vs owner+platform)
- Caller (admin panel vs customer cancel button)
When I grepped for the suspend hook target I matched on the
customer endpoint and didn't audit cross-cutting admin
duplicates. I've since checked every site that calls
`patchTenantSpec`, `createTenant`, or `deleteTenant` — this was
the only missed billing-relevant one. Other `patchTenantSpec`
sites are confirmed non-billing (openClawImage, channelUsers).