feat(operator): partner management with attach/detach (O.6)

- Partners list with name/domain/status/customers/margin + Create modal
- Partner detail: contract card, contact card, customers table, attach modal,
  terminate (soft-delete) danger card
- Operator proxies for /partners + /partners/:slug/tenants
- platform-api: add partnerId Prop to Tenant schema. The field was being
  silently dropped by Mongoose because the schema didn't declare it.
- tenants.service: rewrite update() to build $set/$unset explicitly and cast
  partnerId via new Types.ObjectId(). Handles detach via $unset so the field
  vanishes from the doc cleanly.
This commit is contained in:
Ronni Baslund
2026-05-24 08:02:00 +02:00
parent 8e81730372
commit fbbb43e3e2
12 changed files with 807 additions and 7 deletions
+13 -6
View File
@@ -415,13 +415,20 @@ forward as bearer to platform-api.
- Nitro can throw `Could not load /app/server/api/...` if Vite picks
up a new file mid-build. Container restart clears it.
### O.6 · Partner management (real backend)
### O.6 · Partner management (real backend)
- [ ] `pages/partners/index.vue` — list with name/domain/status/customers/MRR
- [ ] `pages/partners/[slug].vue` — detail panel with customers list,
MRR breakdown, margin, contact info
- [ ] "Create partner" modal — POST /partners
- [ ] Attach / detach tenant to partner (PATCH on tenant.partnerId)
- [x] `pages/partners/index.vue` — list with name/domain/status/customers/margin
- [x] `pages/partners/[slug].vue` — detail panel with contract card, contact
card, customers table, attach modal, terminate danger card
- [x] "Create partner" modal — POST /partners, navigates to detail on success
- [x] Attach / detach tenant to partner (PATCH on tenant.partnerId, with $unset
for detach so the field disappears cleanly)
- [x] `services/platform-api/src/schemas/tenant.schema.ts` — added the
`partnerId` Prop. It was missing, which is why early PATCH attempts
returned 200 but Mongoose silently dropped the field. Smoke-tested with
acme ⇄ nordicmsp and a throwaway temp-msp partner (created + terminated).
- MRR aggregation deferred until Subscription gains real pricing (see
follow-ups). For now `customers` is just a count of attached tenants.
### O.7 · Visual-only screens (mock fixtures)