feat: portal redesign, pricing catalog, partner-staff invites

- portal: new admin/ and partner/ surfaces with full component library
  (AppLauncher, Avatar, Badge, Card, Modal, Tabs, etc.), composables,
  layouts, partner-routing middleware, and supporting server APIs
- pricing: Price schema/module with operator CRUD, pricing.vue catalog UI,
  Subscription extended with cycle/currency/perSeatAmount/seats snapshots
  for stable MRR aggregation
- partner staff: User.partnerId, invite-partner-user DTO and flow,
  /partners/:slug/users endpoints, InvitePartnerUserModal, shared
  dezky-partner-staff Authentik group
- /me: partner-aware endpoint returning user + partner context so portal
  can route between end-user and partner-admin surfaces
- tenant: seats field for portfolio displays and future MRR calculations
- operator: pricing page, signed-out page, useMe/useToast composables,
  ToastStack
This commit is contained in:
Ronni Baslund
2026-05-28 20:00:33 +02:00
parent be430179d9
commit 0bd4e5498e
144 changed files with 22110 additions and 209 deletions
+32
View File
@@ -237,6 +237,38 @@ These were excluded from MVP for simplicity. When ready:
- [ ] Configure OIDC integration with Authentik
- [ ] Add to portal launcher
## Billing & subscriptions — partial implementation
**Implemented (Tier 1)** as of 2026-05-26:
- Price catalog (`prices` collection): operator-edited plan/cycle/currency/per-seat
matrix. UI at `operator.dezky.local/pricing`.
- Subscription auto-created on tenant provision with the resolved `priceId` +
`cycle` + `seats` snapshot.
- Partner MRR aggregation: `GET /users/me/partner/mrr` sums active subscriptions,
normalized to monthly DKK. Surfaced on `app.dezky.local/partner` dashboard.
**NOT implemented — deferred to a future billing pipeline:**
- **Stripe integration** (Tier 2): no Stripe Customer/Subscription objects are
created when a tenant is provisioned. No checkout flow. No payment method
capture. The `Subscription.stripe*` placeholder fields stay empty.
- **Invoices** (Tier 2): no invoice generation, no PDF rendering, no
past-due/dunning logic. The customer portal's `/admin/billing` page is
still fixture-driven.
- **Partner payouts** (Tier 3): MRR display uses `Partner.marginPct` for
display purposes only — no actual payout calculation, no payout schedule,
no bank account capture, no Stripe Connect.
- **Multi-currency** (Tier 3): catalog only supports DKK. EUR/USD entries
would need currency-conversion at MRR aggregation time.
- **Plan-change prorating** (Tier 3): changing a tenant's plan mid-cycle
doesn't prorate or generate adjustment invoices.
- **Tax handling** (Tier 3): no VAT calculation, no Stripe Tax wiring, no
reverse-charge handling for cross-border B2B.
When ready for paying customers, the next investment is Tier 2 (Stripe +
invoices). Tier 3 work should wait until there's enough volume to justify it.
## Decisions still open
These need to be made before public launch: