feat(app-showcase): ADR-0056 Option A public form + D7 default-profile CLI wiring#2076
Merged
Merged
Conversation
…tion A Adds a `showcase_inquiry` object + a public FormView (`allowAnonymous` + `publicLink: /forms/contact-us`) so `pnpm dev` ships a working anonymous web-to-lead form. The submit route authorizes via the declaration-derived `publicFormGrant` (create + read-back on `showcase_inquiry` only) — no `guest_portal` profile, even under secure-by-default auth. A beforeInsert hook stamps server-controlled defaults (status=new, source=web). Dogfood proof (`showcase-public-form.dogfood.test.ts`) drives the real HTTP routes end-to-end under `requireAuth: true`: GET resolves the form + whitelisted schema, POST creates the inquiry anonymously with stamped defaults, and a general anonymous read is still denied (the grant is create + read-back only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XVdnfUAx85amkerym26vdx
…R-0056 D7) D7 added `isDefault` to PermissionSet and resolves it in the SecurityPlugin constructor — but only over the plugin's built-in `defaultPermissionSets`. The CLI boots `new SecurityPlugin()` with no options, so an `isDefault` profile declared purely in APP METADATA was silently ignored under `pnpm dev`. This closes that gap: - `appDefaultProfileName(permissions)` — exported helper that extracts the first `isProfile && isDefault` profile name from a stack's permissions. - CLI `serve.ts` calls it and passes the name as `fallbackPermissionSet` (undefined → built-in default preserved, so non-declaring apps are unaffected). At request time the name resolves through the metadata service / `sys_permission_set` like any user-defined permission set. - Showcase declares `showcase_member_default` (isDefault) — a read-mostly baseline for fresh sign-ups, so `pnpm dev` demonstrates an app-declared default posture instead of the built-in wildcard. Proofs: unit test for `appDefaultProfileName`, and a showcase dogfood test that wires the extracted name as the fallback and shows a fresh member is governed by the declared default (reads announcements, denied private notes the built-in wildcard would have allowed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XVdnfUAx85amkerym26vdx
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 3 package(s): 19 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
…ry view defineView infers the object from list.data; FormView has no label field. These tripped the example-apps typecheck (TS2353).
…lity) The guest-defaults hook unconditionally set source='web', so the verify round-trip wrote source='verify-sample' and read back 'web' — a fidelity gap that failed the Dogfood Regression Gate. Make it a default (only when absent), matching status. Public submissions never include source (the form whitelist excludes it), so they still get 'web'; explicit values now round-trip cleanly.
os-zhuang
marked this pull request as ready for review
June 20, 2026 12:38
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Goal
Make the
pnpm devshowcase visibly demonstrate the remaining ADR-0056 capabilities — and do the platform fixes so they genuinely take effect, not just sit in metadata.What's in this PR (both proven end-to-end)
✅ Option A — web-to-lead public form
showcase_inquiryobject + a publicFormView(allowAnonymous+publicLink: /forms/contact-us) + a guest-defaults hook (status=new,source=web).publicFormGrant(create + read-back onshowcase_inquiryonly) — noguest_portalprofile, even under secure-by-default auth.showcase-public-form.dogfood.test.ts, 3/3): drives the real HTTP routes underrequireAuth: true— GET resolves the form + whitelisted schema, POST creates the inquiry anonymously with stamped defaults, and a general anonymous read is still denied.✅ D7 — app-declared default profile, wired through the CLI
isDefaultbut resolved it only over the SecurityPlugin's built-in sets. The CLI bootsnew SecurityPlugin()with no options, so anisDefaultprofile declared in app metadata was silently ignored underpnpm dev.appDefaultProfileName(permissions);serve.tspasses the extracted name asfallbackPermissionSet(undefined → built-in default preserved, so non-declaring apps are unaffected). It resolves at request time via the metadata service /sys_permission_set.showcase_member_default(read-mostly baseline) sopnpm devshows an app-declared default posture.appDefaultProfileNameunit test (4/4) +showcase-d7-default-profile.dogfood.test.ts(3/3) — a fresh member is governed by the declared default (reads announcements, denied private notes the built-in wildcard would allow).Full showcase dogfood suite re-run green (25/25) — no regressions.
role_and_subordinates) — deferred, needs a dedicated ADRInvestigating D6 surfaced a broader architectural gap: stack-declared
rolesandsharingRulesare never seeded intosys_role/sys_sharing_ruleat runtime — by the harness orpnpm dev. The showcase's existing 3 roles + 2 sharing rules are authoring/Studio metadata that never fire; the sharing-rule evaluator reads the table, which nothing populates from app metadata.So making D6 "truly take effect" is not a showcase tweak — it's an enforce-or-remove (ADR-0049-style) platform feature: runtime activation of declared roles + sharing rules, which would change enforcement behavior for every app (showcase and CRM). That deserves its own focused ADR + PR rather than riding in here. D6's
role_and_subordinatesmechanism itself is already covered byplugin-sharing's own tests.Recommendation: land Option A + D7 here; open a dedicated ADR/PR for "activate declarative roles + sharing rules at runtime" (which D6 then rides on, with a real showcase rule + hierarchy + end-to-end proof).
🤖 Generated with Claude Code
Generated by Claude Code