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:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user