Wire the mail/identity stack to real Stalwart/Authentik/OCIS provisioning,
replacing the mocked Domains and Users pages.
Domains (customer-admin):
- StalwartClient: real JMAP management (v0.16 dropped REST) — create/list/delete
email domains via x:Domain at the internal http://stalwart:8080 listener;
DKIM auto-generated; the records to publish are read from the domain's
dnsZoneFile. Gated by STALWART_PROVISIONING_ENABLED.
- New Domain collection + DomainsModule: add/list/recheck/set-DMARC/remove,
tenant-membership-gated and audited.
- DnsVerifierService: verifies MX/SPF/DKIM/DMARC/ownership against a public
resolver (1.1.1.1/8.8.8.8) and diffs them against the expected records.
- Remove is guarded: refuses while accounts/aliases/mailing lists still use the
domain (via Stalwart referential integrity).
- Domains page + add wizard on real data; sidebar badge counts domains needing
attention.
Users & groups (customer-admin):
- Create a member provisioned across Authentik SSO, a Stalwart mailbox on the
tenant's primary domain, and OCIS — returning a one-time password.
- Lifecycle: suspend/resume (Authentik is_active + freeze the mailbox via
account permissions, original password preserved), force-logout (terminate
sessions, filtered client-side so it can never end other users' sessions),
reset password (new one-time password on SSO + mailbox), and remove (tear down
mailbox + SSO identity + OCIS + doc; mailbox-in-use aware for multi-tenant
users). Self-suspend / self-force-logout are blocked.
Infra: point platform-api at the internal Stalwart listener; document the new
STALWART_/provisioning vars in .env.example.
Replace the last two holdouts: the dashboard partner-identity fallback now uses the real useMe().partner name, and the decorative MRR sparkline (dashboard + reports) moves to a generated useMrrTrendline() — deterministic, clearly placeholder-only, until a daily MRR-snapshot job exists. Removes the dead sparkLast/sparkTrendPct vars. The data/customers.ts fixture module is now fully deleted; the partner portal carries no mock business data.
Migrate the partner-mode customer switcher, in-customer banner, sidebar tile and the team invite/teammate panels off the data/customers fixture onto the real /api/partner/tenants list (shared key, gated to partner-staff so the global shell doesn't 403 for other users). Active customer resolves by tenant _id (the key the customers page already passes to partnerMode.enter); partner-identity labels now use the real partner name from useMe. Removes the now-unused customers + CustomerOrg-list fixture export and the dead setCustomer helper. Verified in UI: switcher + enter/exit show real Baslund Test / Baslund Research ApS.
Drop partnerTeam, partnerInvoices, partnerActivity and partnerAudit from data/customers.ts — these had no remaining importers now that team, billing, dashboard activity and audit run on real data. The still-used partner / customers / partnerMrrSparkline exports (partner-mode customer switcher + decorative sparkline) stay until those consumers are migrated.
Move partner domain types out of data/customers.ts into types/partner.ts so the fixture data exports can be removed later without breaking type imports. Add usePartnerTenants / usePartnerMrr composables wrapping the shared-key partner fetches.