feat(inbox-ui): Settings → Inbox → Providers from each provider plugin's configSchema (G-P4-2)
Merged
EV
9d ago+3465+3465+0123456789012345678901234567890123456789-65-65-01234567890123456789
What
G-P4-2 (UI): Settings → Inbox → Providers renders each provider plugin's configSchema — plan 06-gauzy-implementation-plan.md G-P4-2, 04-inbox-and-email.md §5.2 (Gauzy ↔ Ever Works integration, ever-co/homelab docs/superpowers/specs/2026-10-15-gauzy-ever-works-integration/). Part 1 of 2; Mailboxes + My mailbox (G-P4-1 UI) follow in the next PR.
@gauzy/plugin-inbox-ui
/pages/settings/inbox-providers(asettings-sectionschild of the settings shell,INBOX_MAILBOX_MANAGE): the provider plugins this server loads (capabilities, "Add account") and the accounts of the selected organization and of the tenant.- Generic JSON-schema → Nebular form (
InboxProviderConfigFormComponent+ pure helpers): text (email / URL / host name), multi-line text, number (min / max / integer), on/off,enum, required marks, the plugin's titles and help texts; the same checks as the API'ssplitProviderConfig. - Secrets are write-only: a stored secret is never put back into the form (the API answers only
secretsSet, the card says "Set"); left empty it is kept, typed it replaces, an optional one can be cleared, ageneratedone (Postmark's webhook credential) is made by the server and shown once, in a dialog that only an acknowledgement closes (closeOnEsc/ backdrop off); one-time values are never kept on the page. - Create / edit (an edit sends
configonly when it changed, so a rename never touches the sealed secrets), Test connection (verifyAccount), enable / disable, make outbound default, delete (the API's 409 "a mailbox receives through it" is shown). The webhook URL shown is the API's answer (webhookUrl, built on the API's own public URL) — no host in the UI. A tenant-wide account is read-only withoutALL_ORG_EDIT. - Gating: the Settings → Inbox nav entries are added only where the API serves the Inbox (the same
InboxAvailabilityServicecheck as the nav entry and badge) and its email features (InboxEmailAvailabilityService:GET /api/inbox/mailboxes/mineonce per user; 404/401/403 final, temporary failures retried) and hidden again after a user switch; the route always exists and says "email is not switched on" on a 404. Plugin-owned i18n (INBOX.SETTINGS.*), OnPush + signals,takeUntilDestroyed.
@gauzy/plugin-inbox (additive, for the UI)
DELETE /api/inbox/provider-accounts/:id— soft (kept, marked deleted, disabled, no longer the outbound default), under the row lock; 409 while a mailbox receives through the account; tenant-wide accounts needALL_ORG_EDITas for every write.GET /api/inbox/mailboxes/:id/verification— a custom domain's TXT record and last status, no DNS lookup.GET/PUT /api/inbox/mailboxes/settingsalso answerplatformDomain(GAUZY_INBOX_DOMAINornull).- Contracts:
IInboxProviderAccountRemoved,IInboxOrganizationEmailSettings.platformDomain?.EMAIL.mdroutes updated.tools/egress-audit/ui-routes.json: the new manual route.
Checks (no local test runs, per the overnight rules — specs written, not run)
tscstrict (packages/plugins/inbox/tsconfig.lib.json+tsconfig.spec.json, workspace path map) 0 errors in plugin-inbox; loose (roottsconfig.json, what the API image compiles) 0 in plugin-inbox (7 pre-existing incore/bootstrap/tracer.ts, shared node_modules).- inbox-ui:
tsc(sources + specs) 0 errors in the plugin;ngcwith strictTemplates over the plugin's sources: 0 template errors in the new components (verified the check runs by planting an error). - prettier, cspell (20 files, 0 issues),
tools/egress-audit/static-hostnames.mjsok; the diff names no Ever host.
🤖 Generated with Claude Code
Summary by cubic
Adds Settings → Inbox → Providers, which renders each provider plugin's configSchema as a generic Nebular form and manages the email provider accounts of the selected organization and tenant.
New Features
- Lists provider plugins with their capabilities; creates, edits, tests, enables/disables, sets outbound default, and deletes accounts (a delete is refused with 409 while a mailbox receives through the account).
- Secrets are write-only: stored values never go into the form, and generated ones are shown once in a dialog only an acknowledgement closes — it ignores Escape and the backdrop so a save in flight reaches its one-time values.
- The Settings → Inbox nav entries appear only where the API serves the Inbox email features; the routes always exist and say email is off when they are not.
- Tenant-wide accounts are read-only without
ALL_ORG_EDIT; edits sendconfigonly when changed so renaming never touches sealed secrets. - Account removal and pointing a mailbox at an account share the account's lock, so removing and attaching at once can never both succeed; refreshes answered for a no-longer-selected organization are dropped.
API additions
DELETE /api/inbox/provider-accounts/:id— soft delete, refused with 409 while a mailbox receives through the account.GET /api/inbox/mailboxes/:id/verification— the custom-domain TXT record and last status, no DNS lookup.- Mailbox settings answer
platformDomain(GAUZY_INBOX_DOMAINornull).