fix(nextjs-template): flow-aware degradation + api-<sub> endpoint + scoped tsconfig#25
Draft
yyyyaaa wants to merge 3 commits into
Draft
fix(nextjs-template): flow-aware degradation + api-<sub> endpoint + scoped tsconfig#25yyyyaaa wants to merge 3 commits into
yyyyaaa wants to merge 3 commits into
Conversation
… + scoped tsconfig
Make a freshly-scaffolded constructive-app green-build for a minimal auth:email
flow with NO manual stubbing, while keeping the b2b org surface fully functional
when the admin SDK has it.
F1 — degrade org/invite/members/settings when the admin SDK lacks Org*/Invite*:
- Add src/lib/gql/admin-compat.ts: re-exports @sdk/admin and, for each symbol that
exists only in the b2b admin SDK, exports a value that resolves to the REAL
export when present (sdk[name] ?? stub). Lives outside src/graphql/sdk so codegen
(which wipes the generated SDK dirs) never clobbers it.
- auth:email build → org/invite symbols absent → typed stubs keep the dead
template code type-checking; they are never on the runtime path and throw
loudly if invoked.
- b2b build → symbols present → genuine hooks/fns are used at runtime.
- Repoint the 13 org/invite/app hook + members-route imports of the 23 at-risk
symbols from @sdk/admin to @/lib/gql/admin-compat.
- Annotate 5 derived id arrays as string[] so the where:{id:{in:…}} sites stay
typed when the upstream fetch degrades to any (no-op cast on the b2b path).
- Verified by overlaying the full template src against BOTH a real auth:email SDK
(org symbols absent) and a real b2b/org-roles SDK (org symbols present):
tsc --noEmit = 0 errors in both.
F2 (template half) — app DATA endpoint is api-<sub>, not app-public-<sub>:
- graphql-codegen.config.ts: the app target Host now honors CODEGEN_APP_HOST and
defaults to api-{db}.localhost:3000; endpoint + Host header stay in sync (Host
drives routing, so a URL-only override still 404s). admin/auth gain matching
CODEGEN_*_HOST overrides.
- config-core.ts getAppEndpoint(): default resolves to http://api-{db}.localhost,
still overridable via NEXT_PUBLIC_APP_ENDPOINT.
F11 — scope tsconfig:
- include limited to src/** (+ Next types); add "packages" to exclude so the
provision sub-package isn't greedily compiled by the app's tsc --noEmit.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ecipes
BASE tier: strip all org/b2b code so a base app builds clean on the
auth:email module set with zero dangling org imports.
#3b — tier the template (base = auth:email only):
- delete org/invite/app-admin surfaces: app/{organizations,orgs,invite,
invites,users,settings}, components/{organizations,members,invites,
settings}, lib/gql/hooks/admin/{organizations,policies},
admin/app/{use-app-invites,use-app-settings,use-app-users},
invites-shared-utils, auth/use-submit-{invite,org-invite}-code
- delete the 111-line lib/gql/admin-compat.ts shim (no consumer left)
- delete orphan org demo scaffolding (components/header.tsx,
layouts/{navigation-data,sidebar-config}.ts) + auth invite-screen
- simplify shared layer to a single app-root level: app-routes (drop
org/app routes + buildOrgRoute), navigation (sidebar-config,
use-entity-params, use-sidebar-navigation), authenticated-shell (drop
org switcher), route-guards (drop invite-token branch), admin/auth
barrels, app-permissions; home page drops the orgs/members advert
- relocate query-string helpers to lib/navigation/query-string.ts
- make TopBarConfig.entityLevels optional (b2b populates it)
- base seed only seeds users (no orgs)
- B2B OPT-IN: docs/B2B.md documents re-adding org via the registry org
blocks (org-create-card/org-members-list/org-roles-editor/
org-settings-form) + provisioning ORG_MODULES
#3a — provision recipe fixes:
- create-db.ts: default to the auth:email preset via new modules.ts
(AUTH_EMAIL_MODULES, mirrors flows.json email-password); scoped modules
use TUPLE form (colon-string is rejected: PROVISION-001)
- provision.ts: bake in the users self-update control-plane step
(AuthzDirectOwner self_update policy on users_public.users) and a
provisionAppTable() blueprint helper with object-form grants + the
AuthzDirectOwner owner-scoped default
- graphql/provision/provision.config.ts: replace modules:['all'] with the
auth:email tuple set
Verified: tsc --noEmit clean on the provision package (real
@constructive-io/node) and on the base src (SDK call sites stubbed loose;
all local/@-alias imports resolve; zero refs to deleted paths/symbols/
routes). Full next build needs a provisioned DB (later stress-test).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ision recipes
Fix the baked provision.ts bug cluster the v5 stress-test caught (all 5 agents
hit these), verified end-to-end against the live hub.
B1 (split-endpoint): provision used one client (api.localhost) for everything,
so createDatabaseProvisionModule / createBlueprint / constructBlueprint /
createSecureTableProvision failed with 'Unknown type ...Input' — those live on
modules.localhost. Add config.modulesEndpoint (env PROVISION_MODULES_ENDPOINT /
PG_PROVISION_MODULES_ENDPOINT) + helpers.createModulesClient, and route each
call to the right host: blueprint / construct / secure-table / provision-module
mutations -> modules; apis/schemas/tables/databases reads + createApiSchema ->
api. Verified by introspecting both hosts.
B2 (api-name): schema-attach looked up the app-data API by name 'app', but the
hub names it 'api' (services_public.apis ... name='api'), so the step silently
no-op'd ('App API not found'). Look up 'api' and make the step non-fatal /
idempotent (constructBlueprint already auto-attaches the table's schema).
B3 (field-shape + PK + policy): provisionAppTable emitted bare-string field
type/default -> constructBlueprint BAD_FIELD_INPUT (table never created). Emit
FieldType/FieldDefault OBJECTS (type {name:'text'}, default {value:false});
PREPEND DataId to the default nodes so the table gets a uuid PK (without it no
update/delete); and use AuthzDirectOwner data.entity_field:'owner_id' (the key
the policy actually reads) instead of owner_field. Ship the base `todos` table.
B4 (cross-tenant SQL): membership-defaults + SEED_SCHEMA detection used a
floating `LIKE '%memberships_public' DESC LIMIT 1` with no db filter, which on
the shared hub resolves to a SIBLING tenant (data-corruption risk). Resolve THIS
tenant's physical schema via the metaschema (scoped by database_id) through a new
helpers.resolvePhysicalSchemaName; same fix applied to the create-db admin grant.
Quick wins: fix stale 'app-public-{db}' comments + point appEndpoint at the
api-{db} data host (matches codegen); make the dev/start port env-overridable
(${PORT:-3011}); document in B2B.md the org-create RLS prerequisite (createUser
type=2 needs the create_entity app-permission bit 0x10000 or it hits 'new row
violates RLS for table users'), how create-db grants it, and the
@constructive-io/node *.localhost 'fetch failed' workaround (NodeHttpAdapter /
@constructive-io/fetch createFetch).
Live smoke (hub, constructive-db 3e2000b644): provisioned throwaway tenant
fixsmoke_79faay (auth:email) with the fixed create-db (modules endpoint) +
provision. todos table created in <tenant>_app_public with id PK + owner_id (NO
BAD_FIELD_INPUT), owner-scoped RLS on owner_id, users self_update policy landed
(id = current_user_id), is_done default false from {value:false}; B4 resolved
this tenant's exact schemas (the old query would have hit sibling
rlsb4-f3891e-7073ae68); api-fixsmoke_79faay.localhost serves the todos type.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
What
Makes the
nextjs/constructive-apptemplate scaffold cleanly when consuming Constructive Blocks under a minimal auth preset — the template half of the cross-repo Blocks effort (library/docsconstructive-io/dashboard#227, skillconstructive-skills, harnessconstructive-sdk-agentic-flow).Contents (single commit
0c064ff)auth:emailpreset, hard-failingtsc+next buildout of the box. A compat shim lets the scaffold compile under bothauth:emailand b2b.api-<sub>— point codegen + runtime atapi-<sub>(with aCODEGEN_APP_HOSTseam) instead of the deadapp-public-<sub>Host.tsconfig— sonext buildtype-checks the app, not unrelated sibling workspace packages.Status
Draft / WIP. Unblocks the Blocks on-ramp scaffold; in repeated harness runs 8–10 of every fleet's agents hand-wrote these same fixes, so landing them in the template removes that per-build friction. Follow-up: harden the b2b-import degradation (the compat shim currently lives inside the codegen-regenerated dir and must be re-applied after
pnpm codegen).🤖 Generated with Claude Code