feat(customers): customer portal (#354) on top of feature-flags reorg

Implements the recurring-customer login surface from
the-luap/picpeak#354 plugged into the maintainer's
new feature-flag infrastructure (PR #443) instead of
a parallel toggle.

* New `customerPortal` feature flag (foundation flag for the
  not-yet-built calendar/quotes/bills/messaging customer
  surfaces). Defaults FALSE on fresh installs, TRUE on existing
  installs (events > 0) via migration 095 so live customer
  accounts don't disappear mid-deployment.
* Foundation schema: customer_accounts, customer_invitations,
  event_customer_assignments, customer_password_resets, plus
  RBAC permissions customers.view / .create / .delete granted
  to super_admin + admin system roles.
* Backend: /api/admin/customers (invite, list, search, assign,
  deactivate, reset password) + /api/customer/auth/* +
  /api/customer/* (login, dashboard, accept-invite, reset).
  Customer JWT bypass minted via
  /api/customer/events/:slug/access-token so existing gallery
  middleware stays untouched.
* Frontend: /customer/* route tree gated by RequireFeature flag
  customerPortal, with login / dashboard / accept-invite /
  reset pages and a customer-side sidebar layout.
  /admin/customers and /admin/customers/:id gated identically.
* Settings → Features grows a "Customers" section with a
  Customer portal card. The maintainer's Features tab stays the
  single source of truth — no parallel Advanced features tab.
* CustomerAccountPicker on event create/edit forms hides itself
  when the flag is off; backend ignores customer_account_ids in
  that case instead of erroring the whole event save.

Translations: en + de hand-translated. nl/pt/ru fall through to
en — flagged here as needing native review.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
This commit is contained in:
Luca
2026-05-11 00:05:20 +02:00
co-authored by Claude Opus 4.6
parent f2f48f31b0
commit 087ef45942
54 changed files with 9816 additions and 54 deletions
+40
View File
@@ -416,6 +416,46 @@
@apply text-neutral-500;
}
/*
* Customer-surface scope (#354): the default .input and .card classes
* hard-code bg-white, and the customer surface uses theme variables
* rather than the admin's `.dark` class trigger. Overriding here so
* every <Input> and <Card> rendered inside the customer surface picks
* up var(--color-surface) / var(--color-text) automatically — no
* per-page wrapper needed. Same treatment for native <select>
* elements which share the .input mental model on the profile and
* accept-invite forms.
*
* The .customer-surface marker is set on the root <div> of every
* customer page (CustomerLayout, CustomerLoginPage, CustomerAcceptInvitePage,
* CustomerResetPasswordPage). Pages outside this scope (admin, public
* gallery) keep their original styling.
*/
.customer-surface .card,
.customer-surface .card-hover {
background-color: var(--color-surface);
border-color: var(--color-surface-border);
}
.customer-surface .input,
.customer-surface select.input,
.customer-surface input.input {
background-color: var(--color-surface);
border-color: var(--color-surface-border);
color: var(--color-text);
}
.customer-surface .input::placeholder {
color: var(--color-muted-text);
opacity: 0.7;
}
.customer-surface .input:disabled {
background-color: var(--color-elevated, var(--color-surface));
color: var(--color-muted-text);
opacity: 0.7;
}
.dark .input-themed {
@apply bg-neutral-800 border-neutral-700 text-neutral-100;
}