minutework 0.1.40 → 0.1.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/EXTERNAL_ALPHA.md +17 -1
  2. package/README.md +21 -1
  3. package/assets/claude-local/skills/README.md +5 -0
  4. package/assets/claude-local/skills/app-pack-authoring/SKILL.md +15 -0
  5. package/assets/claude-local/skills/generated-workspace-architecture/SKILL.md +25 -9
  6. package/assets/claude-local/skills/shell-architecture/SKILL.md +15 -0
  7. package/assets/claude-local/skills/vuilder-public-site-authoring/SKILL.md +10 -4
  8. package/assets/claude-local/skills/vuilder-workspace-architecture/SKILL.md +78 -0
  9. package/assets/templates/vuilder-public-site/.env.example +11 -0
  10. package/assets/templates/vuilder-public-site/README.md +15 -0
  11. package/assets/templates/vuilder-public-site/eslint.config.mjs +6 -0
  12. package/assets/templates/vuilder-public-site/next-env.d.ts +4 -0
  13. package/assets/templates/vuilder-public-site/next.config.mjs +28 -0
  14. package/assets/templates/vuilder-public-site/package.json +39 -0
  15. package/assets/templates/vuilder-public-site/postcss.config.mjs +5 -0
  16. package/assets/templates/vuilder-public-site/src/app/api/onboarding/start/route.ts +19 -0
  17. package/assets/templates/vuilder-public-site/src/app/blog/[slug]/page.tsx +25 -0
  18. package/assets/templates/vuilder-public-site/src/app/blog/page.tsx +26 -0
  19. package/assets/templates/vuilder-public-site/src/app/globals.css +103 -0
  20. package/assets/templates/vuilder-public-site/src/app/layout.tsx +18 -0
  21. package/assets/templates/vuilder-public-site/src/app/onboarding/[[...step]]/page.tsx +39 -0
  22. package/assets/templates/vuilder-public-site/src/app/page.tsx +43 -0
  23. package/assets/templates/vuilder-public-site/src/lib/env.server.ts +31 -0
  24. package/assets/templates/vuilder-public-site/src/lib/platform.server.ts +47 -0
  25. package/assets/templates/vuilder-public-site/src/lib/public-dj.server.ts +86 -0
  26. package/assets/templates/vuilder-public-site/src/lib/public-dj.test.ts +8 -0
  27. package/assets/templates/vuilder-public-site/src/lib/routes.test.ts +13 -0
  28. package/assets/templates/vuilder-public-site/src/lib/routes.ts +12 -0
  29. package/assets/templates/vuilder-public-site/template.json +21 -0
  30. package/assets/templates/vuilder-public-site/tools/template/validate-template.mjs +44 -0
  31. package/assets/templates/vuilder-public-site/tsconfig.json +23 -0
  32. package/assets/templates/vuilder-public-site/vitest.config.ts +13 -0
  33. package/assets/templates/vuilder-shell/.env.example +8 -0
  34. package/assets/templates/vuilder-shell/.storybook/main.ts +19 -0
  35. package/assets/templates/vuilder-shell/.storybook/preview.tsx +38 -0
  36. package/assets/templates/vuilder-shell/README.md +49 -0
  37. package/assets/templates/vuilder-shell/components.json +21 -0
  38. package/assets/templates/vuilder-shell/eslint.config.mjs +41 -0
  39. package/assets/templates/vuilder-shell/next-env.d.ts +6 -0
  40. package/assets/templates/vuilder-shell/next.config.mjs +33 -0
  41. package/assets/templates/vuilder-shell/package.json +61 -0
  42. package/assets/templates/vuilder-shell/postcss.config.mjs +8 -0
  43. package/assets/templates/vuilder-shell/public/.gitkeep +1 -0
  44. package/assets/templates/vuilder-shell/src/app/api/auth/accept-shell-session/route.test.ts +105 -0
  45. package/assets/templates/vuilder-shell/src/app/api/auth/accept-shell-session/route.ts +63 -0
  46. package/assets/templates/vuilder-shell/src/app/api/auth/logout/route.test.ts +63 -0
  47. package/assets/templates/vuilder-shell/src/app/api/auth/logout/route.ts +24 -0
  48. package/assets/templates/vuilder-shell/src/app/api/auth/session/route.test.ts +70 -0
  49. package/assets/templates/vuilder-shell/src/app/api/auth/session/route.ts +27 -0
  50. package/assets/templates/vuilder-shell/src/app/app/layout.tsx +17 -0
  51. package/assets/templates/vuilder-shell/src/app/app/page.tsx +30 -0
  52. package/assets/templates/vuilder-shell/src/app/blog/[slug]/page.tsx +15 -0
  53. package/assets/templates/vuilder-shell/src/app/blog/page.tsx +15 -0
  54. package/assets/templates/vuilder-shell/src/app/docs/[...slug]/page.tsx +15 -0
  55. package/assets/templates/vuilder-shell/src/app/docs/page.tsx +15 -0
  56. package/assets/templates/vuilder-shell/src/app/globals.css +70 -0
  57. package/assets/templates/vuilder-shell/src/app/layout.tsx +69 -0
  58. package/assets/templates/vuilder-shell/src/app/login/route.test.ts +33 -0
  59. package/assets/templates/vuilder-shell/src/app/login/route.ts +21 -0
  60. package/assets/templates/vuilder-shell/src/app/page.tsx +16 -0
  61. package/assets/templates/vuilder-shell/src/app/pricing/page.tsx +15 -0
  62. package/assets/templates/vuilder-shell/src/app/providers.tsx +25 -0
  63. package/assets/templates/vuilder-shell/src/app/robots.ts +21 -0
  64. package/assets/templates/vuilder-shell/src/app/sitemap.ts +33 -0
  65. package/assets/templates/vuilder-shell/src/app/w/[workspace_slug]/connect/page.tsx +31 -0
  66. package/assets/templates/vuilder-shell/src/app/w/[workspace_slug]/page.tsx +54 -0
  67. package/assets/templates/vuilder-shell/src/components/ui/button.tsx +59 -0
  68. package/assets/templates/vuilder-shell/src/components/ui/input.tsx +21 -0
  69. package/assets/templates/vuilder-shell/src/design-system/docs/governance.mdx +26 -0
  70. package/assets/templates/vuilder-shell/src/design-system/patterns/panel-frame.stories.tsx +48 -0
  71. package/assets/templates/vuilder-shell/src/design-system/patterns/panel-frame.tsx +26 -0
  72. package/assets/templates/vuilder-shell/src/design-system/patterns/status-badge.stories.tsx +26 -0
  73. package/assets/templates/vuilder-shell/src/design-system/patterns/status-badge.tsx +35 -0
  74. package/assets/templates/vuilder-shell/src/design-system/patterns/theme-mode-toggle.stories.tsx +21 -0
  75. package/assets/templates/vuilder-shell/src/design-system/patterns/theme-mode-toggle.tsx +75 -0
  76. package/assets/templates/vuilder-shell/src/design-system/primitives/button.stories.tsx +37 -0
  77. package/assets/templates/vuilder-shell/src/design-system/primitives/button.ts +1 -0
  78. package/assets/templates/vuilder-shell/src/design-system/primitives/input.stories.tsx +26 -0
  79. package/assets/templates/vuilder-shell/src/design-system/primitives/input.ts +1 -0
  80. package/assets/templates/vuilder-shell/src/design-system/recipes/chrome.ts +28 -0
  81. package/assets/templates/vuilder-shell/src/design-system/tokens/foundation.css +31 -0
  82. package/assets/templates/vuilder-shell/src/design-system/tokens/index.css +3 -0
  83. package/assets/templates/vuilder-shell/src/design-system/tokens/manifest.json +85 -0
  84. package/assets/templates/vuilder-shell/src/design-system/tokens/manifest.ts +87 -0
  85. package/assets/templates/vuilder-shell/src/design-system/tokens/semantic.css +105 -0
  86. package/assets/templates/vuilder-shell/src/design-system/tokens/theme.css +59 -0
  87. package/assets/templates/vuilder-shell/src/design-system/tokens/tokens.stories.tsx +71 -0
  88. package/assets/templates/vuilder-shell/src/features/dashboard/components/tenant-dashboard.tsx +134 -0
  89. package/assets/templates/vuilder-shell/src/features/public-shell/components/static-public-page.tsx +58 -0
  90. package/assets/templates/vuilder-shell/src/features/shell/components/authenticated-app-layout-shell.tsx +84 -0
  91. package/assets/templates/vuilder-shell/src/features/shell/components/private-app-shell.tsx +22 -0
  92. package/assets/templates/vuilder-shell/src/features/vuilder-shell/components/vuilder-connect-screen.tsx +89 -0
  93. package/assets/templates/vuilder-shell/src/features/vuilder-shell/components/vuilder-workspace-screen.tsx +49 -0
  94. package/assets/templates/vuilder-shell/src/lib/app-routes.test.ts +37 -0
  95. package/assets/templates/vuilder-shell/src/lib/app-routes.ts +86 -0
  96. package/assets/templates/vuilder-shell/src/lib/auth-routes.server.test.ts +26 -0
  97. package/assets/templates/vuilder-shell/src/lib/auth-routes.server.ts +53 -0
  98. package/assets/templates/vuilder-shell/src/lib/http/same-origin.test.ts +23 -0
  99. package/assets/templates/vuilder-shell/src/lib/http/same-origin.ts +18 -0
  100. package/assets/templates/vuilder-shell/src/lib/platform/client.server.test.ts +201 -0
  101. package/assets/templates/vuilder-shell/src/lib/platform/client.server.ts +540 -0
  102. package/assets/templates/vuilder-shell/src/lib/platform/contracts.ts +190 -0
  103. package/assets/templates/vuilder-shell/src/lib/platform/endpoints.server.ts +29 -0
  104. package/assets/templates/vuilder-shell/src/lib/platform/env.server.ts +82 -0
  105. package/assets/templates/vuilder-shell/src/lib/platform/route-response.ts +33 -0
  106. package/assets/templates/vuilder-shell/src/lib/platform/session.server.ts +145 -0
  107. package/assets/templates/vuilder-shell/src/lib/public-site.test.ts +20 -0
  108. package/assets/templates/vuilder-shell/src/lib/public-site.ts +48 -0
  109. package/assets/templates/vuilder-shell/src/lib/theme-config.ts +10 -0
  110. package/assets/templates/vuilder-shell/src/lib/theme.tsx +159 -0
  111. package/assets/templates/vuilder-shell/src/lib/utils.ts +6 -0
  112. package/assets/templates/vuilder-shell/template.json +28 -0
  113. package/assets/templates/vuilder-shell/template.schema.json +171 -0
  114. package/assets/templates/vuilder-shell/test/server-only-stub.ts +1 -0
  115. package/assets/templates/vuilder-shell/tools/design-system/build-token-manifest.mjs +3 -0
  116. package/assets/templates/vuilder-shell/tools/design-system/check-imports.mjs +9 -0
  117. package/assets/templates/vuilder-shell/tools/design-system/check-stories.mjs +9 -0
  118. package/assets/templates/vuilder-shell/tools/design-system/check-values.mjs +9 -0
  119. package/assets/templates/vuilder-shell/tools/design-system/checks.mjs +238 -0
  120. package/assets/templates/vuilder-shell/tools/design-system/eslint-plugin-design-system.mjs +184 -0
  121. package/assets/templates/vuilder-shell/tools/design-system/playwright.config.mjs +34 -0
  122. package/assets/templates/vuilder-shell/tools/design-system/run-checks.mjs +22 -0
  123. package/assets/templates/vuilder-shell/tools/design-system/shared.mjs +166 -0
  124. package/assets/templates/vuilder-shell/tools/design-system/visual.spec.ts +41 -0
  125. package/assets/templates/vuilder-shell/tools/template/validate-route-contract.mjs +373 -0
  126. package/assets/templates/vuilder-shell/tools/template/validate-template.mjs +45 -0
  127. package/assets/templates/vuilder-shell/tools/template/with-public-site-fixture.mjs +45 -0
  128. package/assets/templates/vuilder-shell/tsconfig.json +42 -0
  129. package/assets/templates/vuilder-shell/vitest.config.ts +23 -0
  130. package/dist/auth.js +66 -14
  131. package/dist/auth.js.map +1 -1
  132. package/dist/deploy-state.d.ts +1 -0
  133. package/dist/deploy-state.js.map +1 -1
  134. package/dist/deploy.js +18 -4
  135. package/dist/deploy.js.map +1 -1
  136. package/dist/developer-client.d.ts +1 -1
  137. package/dist/index.js +12 -2
  138. package/dist/index.js.map +1 -1
  139. package/dist/init-prompt.js +21 -13
  140. package/dist/init-prompt.js.map +1 -1
  141. package/dist/init.d.ts +3 -1
  142. package/dist/init.js +103 -12
  143. package/dist/init.js.map +1 -1
  144. package/dist/orchestrator-context.js +17 -5
  145. package/dist/orchestrator-context.js.map +1 -1
  146. package/dist/orchestrator-state.d.ts +2 -2
  147. package/dist/orchestrator-state.js.map +1 -1
  148. package/dist/publish.js +12 -2
  149. package/dist/publish.js.map +1 -1
  150. package/dist/state.d.ts +2 -0
  151. package/dist/state.js +9 -0
  152. package/dist/state.js.map +1 -1
  153. package/package.json +3 -3
  154. package/vendor/workspace-mcp/context.d.ts +3 -1
  155. package/vendor/workspace-mcp/context.js +134 -21
  156. package/vendor/workspace-mcp/context.js.map +1 -1
  157. package/vendor/workspace-mcp/types.d.ts +72 -7
  158. package/vendor/workspace-mcp/types.js +8 -4
  159. package/vendor/workspace-mcp/types.js.map +1 -1
  160. package/assets/templates/fastapi-sidecar/poetry.lock +0 -757
  161. package/assets/templates/next-tenant-app/package-lock.json +0 -9682
  162. package/assets/templates/next-tenant-app/pnpm-lock.yaml +0 -6062
package/EXTERNAL_ALPHA.md CHANGED
@@ -19,6 +19,12 @@ The shipped `tenant-app` starter is the combined web surface: public routes at
19
19
  the root, a private `/app` workspace, and a MinuteWork-managed public-content
20
20
  path over the runtime-baseline `mw.core.site` contract.
21
21
 
22
+ Vuilder authoring workspaces can scaffold `vuilder-app` plus `vuilder-shell`.
23
+ `vuilder-app` is the public acquisition/onboarding site and `vuilder-shell` is
24
+ the branded customer tenant shell. The customer signup path remains
25
+ server-authoritative: central SSO and the platform `customer_vertical_signup`
26
+ intent decide provisioning and app-pack install metadata.
27
+
22
28
  ### Developer-local broker lane
23
29
 
24
30
  Use `minutework session` when you want MinuteWork to assemble the workspace
@@ -103,10 +109,20 @@ React Native client that authenticates directly against the platform with the
103
109
  native session-token flow; it is distributed through EAS/App Store/Play Store
104
110
  instead of `minutework deploy`.
105
111
 
112
+ For Vuilder verticals, scaffold both Vuilder starters:
113
+
114
+ ```bash
115
+ npx minutework init my-vertical --starter vuilder-app --starter vuilder-shell
116
+ ```
117
+
118
+ The Vuilder shell can customize tenant UX and routes such as
119
+ `/w/[workspace_slug]` and `/w/[workspace_slug]/connect`; it does not own central
120
+ identity, runtime provisioning, app-pack install authority, or billing policy.
121
+
106
122
  Anything outside these lanes remains deferred, including `--live`,
107
123
  runtime-backed deploy targets, and additional local coding engines.
108
124
 
109
- If you run `minutework init` **without** `--starter` in an interactive terminal, the CLI prompts for tenant-app, sidecar, mobile, common combinations, or base-only. In CI or scripts, use `--starter` or set `MW_CLI_NONINTERACTIVE=1` to skip the prompt (base-only scaffold).
125
+ If you run `minutework init` **without** `--starter` in an interactive terminal, the CLI prompts for tenant-app, Vuilder app/shell, sidecar, mobile, common combinations, or base-only. In CI or scripts, use `--starter` or set `MW_CLI_NONINTERACTIVE=1` to skip the prompt (base-only scaffold).
110
126
 
111
127
  ## What `link` does
112
128
 
package/README.md CHANGED
@@ -8,7 +8,10 @@ The npm package and primary command are `minutework`. The `pandawork` command re
8
8
 
9
9
  The current external alpha is intentionally narrow:
10
10
 
11
- - Starters: `tenant-app` (the deployable web surface), `sidecar` (local/internal runtime surface), and `mobile` (init-only native client)
11
+ - Starters: `tenant-app` (combined public/private web surface), `vuilder-app`
12
+ plus `vuilder-shell` (Vuilder public site plus branded customer shell),
13
+ `sidecar` (local/internal runtime surface), and `mobile` (init-only native
14
+ client)
12
15
  - Developer-local broker surface: `minutework session start|resume|status`
13
16
  - Hosted release class: `ssr_container`
14
17
  - Deploy surface: `minutework deploy --preview`
@@ -22,6 +25,12 @@ The shipped `tenant-app` starter is the combined web surface: public routes at
22
25
  the root plus a private `/app` workspace. Public-site content follows the
23
26
  MinuteWork-managed `mw.core.site` baseline and published-snapshot flow.
24
27
 
28
+ For Vuilder verticals, scaffold `vuilder-app` and `vuilder-shell` together.
29
+ `vuilder-app` is the public landing/blog/onboarding site; `vuilder-shell` is the
30
+ branded customer tenant shell opened after central SSO and platform-owned
31
+ `customer_vertical_signup` completion. Browser intake never chooses package
32
+ refs, manifest refs, runtime provider, billing policy, or provisioning kind.
33
+
25
34
  The CLI fails closed when the backend cannot provide typed release metadata, deploy status, receipts, activation state, or rollback state. It does not claim a successful deploy when the provider substrate is unavailable.
26
35
 
27
36
  ## Install
@@ -65,6 +74,17 @@ keychain), not the `tenant-app` BFF cookie path. There is no `link`/`deploy`
65
74
  lane for it — distribution is your own EAS pipeline (`eas build`/`eas submit`,
66
75
  EAS Update), not `minutework deploy`.
67
76
 
77
+ For a first-class Vuilder workspace, scaffold both web starters:
78
+
79
+ ```bash
80
+ npx minutework init fleet-template --starter vuilder-app --starter vuilder-shell
81
+ ```
82
+
83
+ The Vuilder public site redirects onboarding into central SSO. The approved
84
+ app-pack marketplace coordinate is emitted by `minutework publish` and consumed
85
+ by the platform customer-signup intent; the Vuilder shell customizes tenant UX,
86
+ not platform identity/provisioning authority.
87
+
68
88
  ### Developer-local broker lane
69
89
 
70
90
  Use this lane when you want MinuteWork to assemble a bounded workspace context,
@@ -15,6 +15,8 @@ receive:
15
15
 
16
16
  - Builder should compose shared substrate before generating bespoke tenant code
17
17
  - `tenant-app` is the combined public plus private web starter
18
+ - `vuilder-app` plus `vuilder-shell` are the default first-class Vuilder
19
+ workspace web starters around app-pack source
18
20
  - `tenant-app` auth/data uses `@minutework/web-auth` and thin `src/mw/`
19
21
  substrate, not per-app auth/gateway BFF routes
20
22
  - `tenant-app` uses cookie-backed `signUp` / `signInWithPassword` aliases and
@@ -25,6 +27,8 @@ receive:
25
27
  - tenant public authoring is runtime/CMS-backed through `mw.core.site`
26
28
  - Vuilder-owned public sites use `vuilder-public-site` and public-dj CMS
27
29
  manifests
30
+ - Vuilder workspace tasks should load `vuilder-workspace-architecture` before
31
+ the public-site, shell, or app-pack task skill
28
32
  - anonymous live delivery should prefer published snapshots
29
33
  - AI drafting/generation should reuse existing runtime AI capability before new
30
34
  model/provider integrations
@@ -43,6 +47,7 @@ Generated-workspace-first guidance should live here, especially:
43
47
 
44
48
  - `project-overview-and-strategy/SKILL.md`
45
49
  - `generated-workspace-architecture/SKILL.md`
50
+ - `vuilder-workspace-architecture/SKILL.md`
46
51
  - `vuilder-public-site-authoring/SKILL.md`
47
52
  - `workspace-guidance-refresh/SKILL.md`
48
53
  - `shell-architecture/SKILL.md`
@@ -10,6 +10,21 @@ An `app pack` is the shipped product unit.
10
10
  - Compose shared MinuteWork substrate first: baseline capabilities, runtime
11
11
  primitives, reviewed capability skills, app packs, overlays, and hosted
12
12
  publication flows.
13
+ - In a Vuilder workspace, app-pack source is the reusable vertical product that
14
+ customer runtimes receive after `customer_vertical_signup`. The public
15
+ `vuilder-app` and branded `vuilder-shell` are web surfaces around that pack;
16
+ they are not substitutes for the installable app-pack contract.
17
+ - `vuilder-shell` is a platform member shell reached after central SSO and
18
+ app-pack install gating. It uses shell-origin state plus a one-use handoff
19
+ code exchange to obtain a tenant-bound shell token resolved by the platform
20
+ shell-context endpoint. Do not reuse the `tenant-app` `@minutework/web-auth`
21
+ customer-session profile for it, forward raw platform session/CSRF cookies,
22
+ or add a local password-login BFF.
23
+ - Vuilder publish must produce the marketplace coordinate consumed by customer
24
+ signup:
25
+ `core:app_pack_catalog:<publisherTenantId>:<appId>:<appVersion>`. The
26
+ public-site manifest/release context pins that coordinate and digest; browser
27
+ code must not invent or modify it.
13
28
  - Templates are governed starters, not the full limit of what Builder may use.
14
29
  - Builder may adopt open-source libraries, frameworks, and products inside the
15
30
  sandbox when that reduces bespoke code and still preserves the MinuteWork
@@ -19,8 +19,9 @@ the monorepo or a live tenant runtime.
19
19
  - app packs
20
20
  - skills
21
21
  - tenant overlays
22
- - `tenant-app`, optional `sidecar`, and the optional `mobile` starter are
23
- implementation surfaces inside the tenant product, not the whole architecture.
22
+ - `tenant-app`, `vuilder-app`, `vuilder-shell`, optional `sidecar`, and the
23
+ optional `mobile` starter are implementation surfaces inside the generated
24
+ workspace, not the whole architecture.
24
25
  - `tenant-app` is the combined public plus private web starter.
25
26
  - In `tenant-app`, keep MinuteWork web auth/data access inside the thin
26
27
  `src/mw/` substrate and `@minutework/web-auth`. Product UI may call that
@@ -61,12 +62,26 @@ the monorepo or a live tenant runtime.
61
62
  same-named method to return tokens.
62
63
  - If the `mobile` starter is enabled (`starters.mobile.enabled`), read
63
64
  `standalone-mobile-client/SKILL.md` before proposing the mobile surface.
64
- - `vuilder-public-site` is a Vuilder-owned public-site authoring workspace for
65
- landing, blog, and onboarding routes backed by public-dj CMS manifests.
66
- - If `template_kind` is `vuilder-public-site`, or the workspace profile says
67
- `public_dj_cms`, read `vuilder-public-site-authoring/SKILL.md`.
68
- - `vuilder-public-site` does not own tenant `/app`, `/w/*`, or runtime
69
- `mw.core.site`; it renders public-dj content pinned by manifest ref/digest.
65
+ - A first-class Vuilder workspace defaults to `vuilder-app`, `vuilder-shell`,
66
+ app-pack source, and optional `sidecar` / `mobile` starters when selected.
67
+ FleetRun is an example vertical, not a hardcoded product.
68
+ - If the workspace has `starters.vuilderApp.enabled`,
69
+ `starters.vuilderShell.enabled`, `vuilder-app/`, or `vuilder-shell/`, read
70
+ `vuilder-workspace-architecture/SKILL.md` first.
71
+ - `vuilder-app` is a Vuilder-owned public-site authoring workspace for landing,
72
+ blog, and onboarding routes backed by public-dj CMS manifests. It is
73
+ materialized from `vuilder-public-site`.
74
+ - `vuilder-app` does not own tenant `/app`, `/w/*`, or runtime `mw.core.site`;
75
+ it renders public-dj content pinned by manifest ref/digest and redirects
76
+ customer signup into central SSO.
77
+ - `vuilder-shell` is a Vuilder-branded customer tenant shell under
78
+ `/w/[workspace_slug]`; it customizes tenant UX while platform owns identity,
79
+ provisioning, and app-pack install authority. Use central SSO, shell-origin
80
+ state, a short-lived one-use handoff code, and the tenant-bound
81
+ `mw_vuilder_shell_session` context endpoint for `vuilder-shell`; do not use
82
+ `@minutework/web-auth`, raw platform session/CSRF cookies, same-origin `/_mw`
83
+ tenant customer routes, local password forms, or local credential-login BFF
84
+ routes there. Preserve the requested workspace in the SSO return URL.
70
85
  - For member-facing collaboration and operator work, the primary product surface
71
86
  is the gateway shell under `/w/[workspace_slug]`. Do not default to a bespoke
72
87
  standalone tenant frontend when the work belongs in shell threads, cards, or
@@ -96,7 +111,8 @@ the monorepo or a live tenant runtime.
96
111
  itineraries, proposals, pages, and generated assets should usually come from
97
112
  runtime data/content/workflow, not fresh product rebuilds.
98
113
  - Current external alpha constraints matter:
99
- - local authoring supports `tenant-app`, `sidecar`, or both
114
+ - local authoring supports `tenant-app`, `vuilder-app`, `vuilder-shell`,
115
+ `sidecar`, `mobile`, or selected combinations
100
116
  - hosted deploy is preview-first
101
117
  - live public delivery and sidecar/runtime-backed deploys are not implied from
102
118
  the current external lane
@@ -12,6 +12,16 @@ threads, channels, inboxes, guest collaboration, approvals, dashboards, or
12
12
  - Default to the member shell first. For collaboration and operator work, the
13
13
  primary product surface is the gateway shell under `/w/[workspace_slug]`, not
14
14
  a bespoke standalone tenant frontend.
15
+ - `vuilder-shell` is the generated Vuilder-branded customer tenant shell. It
16
+ keeps `/w/[workspace_slug]` and `/w/[workspace_slug]/connect` as branded
17
+ customer workspace routes, but it must still rely on platform identity,
18
+ provisioning, and app-pack install authority. It is a platform member shell
19
+ using central SSO plus a tenant-bound `mw_vuilder_shell_session` token, not a
20
+ `tenant-app` `@minutework/web-auth` customer session surface and not raw
21
+ platform session/CSRF cookies. Its `/login` route sets a shell-origin state
22
+ cookie before redirecting to central SSO; SSO returns a short-lived one-use
23
+ code, and the shell exchanges that code server-side before setting the
24
+ host-only session cookie. Do not add local password-login BFF routes.
15
25
  - Treat these nouns as the default mental model:
16
26
  - **Server**: the product-facing private tenant space
17
27
  - **Channel**: a conversation surface inside the shell
@@ -47,6 +57,11 @@ threads, channels, inboxes, guest collaboration, approvals, dashboards, or
47
57
  - the surface is a mobile app (Expo / React Native / native iOS/Android) ->
48
58
  author in the `mobile` starter, not `tenant-app`; see
49
59
  `standalone-mobile-client/SKILL.md`
60
+ - Do not confuse shell surfaces:
61
+ - central platform shell: first-party MinuteWork member shell substrate
62
+ - `vuilder-shell`: generated branded customer tenant shell for a Vuilder
63
+ vertical, backed by platform member sessions
64
+ - `tenant-app`: combined public/private web starter for ordinary tenant apps
50
65
  - If shell fit is correct but this generated workspace cannot directly author
51
66
  the shell extension, keep the shell-first recommendation and record a
52
67
  capability gap instead of silently converting the request into standalone
@@ -6,8 +6,9 @@ description: "Vuilder-owned public websites, public-dj CMS manifests, vuilder-pu
6
6
  # Vuilder Public Site Authoring
7
7
 
8
8
  Use this skill when the request touches a Vuilder-owned public website,
9
- `vuilder-public-site`, public-dj CMS content, or customer signup through a
10
- Vuilder vertical.
9
+ `vuilder-app`, `vuilder-public-site`, public-dj CMS content, or customer signup
10
+ through a Vuilder vertical. If the workspace also includes `vuilder-shell` or
11
+ app-pack source, read `vuilder-workspace-architecture/SKILL.md` first.
11
12
 
12
13
  ## System Boundary
13
14
 
@@ -25,8 +26,10 @@ Vuilder vertical.
25
26
 
26
27
  ## Template Contract
27
28
 
28
- - Use `runtime/builder/templates/vuilder-public-site` for Vuilder-owned landing,
29
- blog, public onboarding, and other public marketing routes.
29
+ - Use `vuilder-app/` as the generated public starter directory. It is
30
+ materialized from `runtime/builder/templates/vuilder-public-site` for
31
+ Vuilder-owned landing, blog, public onboarding, and other public marketing
32
+ routes.
30
33
  - The template reads public-dj through a server-only CMS adapter.
31
34
  - Expected release env includes `MW_PUBLIC_DJ_BASE_URL`,
32
35
  `MW_PUBLIC_CONTENT_REF`, `MW_PUBLIC_CONTENT_DIGEST`, and
@@ -48,6 +51,9 @@ Vuilder vertical.
48
51
  - The public-site BFF creates customer onboarding intents from server-pinned
49
52
  release context: property/release refs, manifest ref/digest, package
50
53
  ref/digest, onboarding flow ref/digest, and Vuilder workspace context.
54
+ - After creating the intent, redirect the browser to central SSO at an opaque
55
+ route like `/onboarding/vertical/[intent_id]`. The public site does not log
56
+ in users or complete provisioning itself.
51
57
  - Browser intake answers are untrusted input. Browsers must not author package
52
58
  refs, manifest refs, provisioning kind, or workspace identity.
53
59
 
@@ -0,0 +1,78 @@
1
+ ---
2
+ name: vuilder-workspace-architecture
3
+ description: "First skill for generated Vuilder workspaces: vuilder-app public site, vuilder-shell branded customer shell, app-pack source, and customer signup/install flow."
4
+ ---
5
+
6
+ # Vuilder Workspace Architecture
7
+
8
+ Use this skill first when a generated workspace is a Vuilder workspace or when
9
+ the request mentions Vuilder verticals, Vuilder public sites, branded tenant
10
+ shells, customer vertical signup, or app-pack publishing for customer install.
11
+
12
+ ## Default Workspace Shape
13
+
14
+ A first-class Vuilder workspace is vertical-neutral. FleetRun is an example
15
+ vertical name, not a platform hardcode.
16
+
17
+ Expected generated layout:
18
+
19
+ - `vuilder-app/`: public landing, blog, and onboarding site. It uses the
20
+ `vuilder-public-site` template and public-dj CMS manifests.
21
+ - `vuilder-shell/`: Vuilder-branded customer tenant shell. It opens customer
22
+ workspace routes like `/w/[workspace_slug]` and
23
+ `/w/[workspace_slug]/connect`. Its `/login` route sets a host-only shell
24
+ handoff state cookie, redirects to central platform SSO, receives a
25
+ short-lived one-use handoff code, exchanges that code server-side for a
26
+ tenant-bound shell token, and stores that token as a host-only
27
+ `mw_vuilder_shell_session` cookie. It never receives raw platform session
28
+ cookies and is not the `tenant-app` `@minutework/web-auth` customer-session
29
+ profile.
30
+ - App-pack source: schemas, agents, flows, views, seed data, and package
31
+ metadata under the workspace authoring layer.
32
+ - Optional `sidecar/` and `mobile/` starters when selected.
33
+
34
+ ## Flow
35
+
36
+ The acquisition and install path is:
37
+
38
+ 1. Customer lands on the Vuilder public site (`vuilder-app`).
39
+ 2. The public-site BFF creates `customer_vertical_signup` using
40
+ server-pinned release context.
41
+ 3. The browser is redirected to central SSO.
42
+ 4. SSO handles login/signup and completes the opaque onboarding intent
43
+ server-side.
44
+ 5. Platform provisions the customer tenant runtime VM.
45
+ 6. Platform installs the approved app pack from the marketplace coordinate.
46
+ 7. The branded `vuilder-shell` opens the customer workspace.
47
+
48
+ ## Hard Boundary
49
+
50
+ `vuilder-shell` customizes tenant UX, navigation, copy, branding, and customer
51
+ workspace presentation. It does not own identity, tenant creation, runtime
52
+ provider selection, billing policy, provisioning, package refs, manifest refs,
53
+ attestation, digest checks, or app-pack install authority.
54
+
55
+ Do not wire `vuilder-shell` to same-origin `/_mw` tenant customer auth routes.
56
+ Do not render a local password form or expose a local credential-login BFF in
57
+ `vuilder-shell`. `/login` is only a redirect handoff to central SSO with a
58
+ trusted return URL and shell-origin state for the requested workspace. SSO
59
+ completion creates a platform `Membership` and returns a one-use handoff code;
60
+ the shell validates the echoed state, exchanges the code server-side, stores the
61
+ returned `mw_vuilder_shell_session`, and resolves server-authored shell context
62
+ from that token. It must fail closed for missing or mismatched state, missing
63
+ tokens, mismatched workspace slugs, missing member capabilities, or blocked
64
+ workspace-open affordance.
65
+
66
+ Browser intake is untrusted. Do not let browser code choose package refs,
67
+ manifest refs, Vuilder workspace ids, provisioning kind, runtime provider,
68
+ billing policy, or install coordinates.
69
+
70
+ ## Related Skills
71
+
72
+ - Use `vuilder-public-site-authoring` for `vuilder-app`, public-dj manifests,
73
+ and onboarding-intent creation.
74
+ - Use `shell-architecture` for `vuilder-shell` customer workspace routes.
75
+ - Use `app-pack-authoring` for schemas, agents, flows, package metadata, and
76
+ marketplace publish output.
77
+ - Use `generated-workspace-architecture` for general local workspace trust
78
+ boundaries.
@@ -0,0 +1,11 @@
1
+ MW_PUBLIC_DJ_BASE_URL=http://127.0.0.1:8003
2
+ MW_AUTH_BASE_URL=http://127.0.0.1:3400
3
+ MW_PLATFORM_BASE_URL=http://127.0.0.1:8000
4
+ MW_PUBLIC_BASE_URL=http://127.0.0.1:3300
5
+ MW_PUBLIC_SITE_PROPERTY_KEY=main-site
6
+ MW_PUBLIC_SITE_ENV=preview
7
+ MW_PUBLIC_RELEASE_CLASS=ssr_container
8
+ MW_PUBLIC_CONTENT_REF=
9
+ MW_PUBLIC_CONTENT_DIGEST=
10
+ MW_PUBLIC_DJ_READ_TOKEN=
11
+ MW_VUILDER_ONBOARDING_INTENT_TOKEN=
@@ -0,0 +1,15 @@
1
+ # Vuilder Public Site Template
2
+
3
+ `vuilder-public-site` is the public website template for Vuilder-owned websites.
4
+ Builder edits normal Next.js code in this workspace. Public content comes from
5
+ public-dj through an immutable site manifest ref and digest.
6
+
7
+ The template supports two release classes:
8
+
9
+ - `static_export`: content is resolved during build and emitted as static output.
10
+ - `ssr_container`: server code resolves the pinned public-dj manifest at runtime.
11
+
12
+ The browser never receives public-dj credentials or platform intent credentials.
13
+ Onboarding starts through the server route at `/api/onboarding/start`, which asks
14
+ platform to create a `customer_vertical_signup` intent from release-pinned
15
+ server context.
@@ -0,0 +1,6 @@
1
+ import nextVitals from "eslint-config-next/core-web-vitals";
2
+ import nextTs from "eslint-config-next/typescript";
3
+
4
+ const eslintConfig = [...nextVitals, ...nextTs];
5
+
6
+ export default eslintConfig;
@@ -0,0 +1,4 @@
1
+ /// <reference types="next" />
2
+ /// <reference types="next/image-types/global" />
3
+
4
+ // This file is automatically generated by Next.js.
@@ -0,0 +1,28 @@
1
+ import path from "node:path";
2
+ import { existsSync } from "node:fs";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+
7
+ function resolveTurbopackRoot(startDirectory) {
8
+ let directory = startDirectory;
9
+ while (true) {
10
+ if (existsSync(path.join(directory, "pnpm-workspace.yaml"))) {
11
+ return directory;
12
+ }
13
+ const parent = path.dirname(directory);
14
+ if (parent === directory) return startDirectory;
15
+ directory = parent;
16
+ }
17
+ }
18
+
19
+ const nextConfig = {
20
+ reactStrictMode: true,
21
+ typedRoutes: true,
22
+ ...(process.env.MW_PUBLIC_RELEASE_CLASS === "static_export" ? { output: "export" } : {}),
23
+ turbopack: {
24
+ root: resolveTurbopackRoot(__dirname),
25
+ },
26
+ };
27
+
28
+ export default nextConfig;
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "vuilder-public-site",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "packageManager": "pnpm@9.0.0",
6
+ "engines": {
7
+ "node": ">=20.9.0"
8
+ },
9
+ "scripts": {
10
+ "dev": "next dev --hostname 127.0.0.1 --port 3300",
11
+ "build": "next build",
12
+ "start": "next start -p 3300",
13
+ "lint": "eslint .",
14
+ "test": "vitest run",
15
+ "typegen": "next typegen",
16
+ "template:validate": "node tools/template/validate-template.mjs",
17
+ "typecheck": "tsc --noEmit",
18
+ "validate": "pnpm template:validate && pnpm typegen && pnpm typecheck && pnpm lint && pnpm test && pnpm build"
19
+ },
20
+ "dependencies": {
21
+ "next": "^16.2.0",
22
+ "react": "^19.2.0",
23
+ "react-dom": "^19.2.0",
24
+ "server-only": "^0.0.1",
25
+ "zod": "^3.24.1"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^22.0.0",
29
+ "@types/react": "^19.0.0",
30
+ "@types/react-dom": "^19.0.0",
31
+ "ajv": "^8.17.1",
32
+ "eslint": "^9.39.1",
33
+ "eslint-config-next": "^16.2.0",
34
+ "postcss": "^8.5.6",
35
+ "tailwindcss": "^4.2.0",
36
+ "typescript": "^5.6.0",
37
+ "vitest": "^3.2.4"
38
+ }
39
+ }
@@ -0,0 +1,5 @@
1
+ const config = {
2
+ plugins: {},
3
+ };
4
+
5
+ export default config;
@@ -0,0 +1,19 @@
1
+ import { NextResponse } from "next/server";
2
+
3
+ import { env } from "@/lib/env.server";
4
+ import { createCustomerVerticalSignupIntent } from "@/lib/platform.server";
5
+
6
+ export async function POST(request: Request) {
7
+ const formData = await request.formData();
8
+ const payload = await createCustomerVerticalSignupIntent({
9
+ email: String(formData.get("email") ?? ""),
10
+ name: String(formData.get("name") ?? ""),
11
+ });
12
+
13
+ const nextUrl = new URL(
14
+ `/onboarding/vertical/${encodeURIComponent(String(payload.intent.id))}`,
15
+ env.MW_AUTH_BASE_URL,
16
+ );
17
+
18
+ return NextResponse.redirect(nextUrl, { status: 303 });
19
+ }
@@ -0,0 +1,25 @@
1
+ import { notFound } from "next/navigation";
2
+
3
+ import { getSiteManifest } from "@/lib/public-dj.server";
4
+
5
+ export default async function BlogPostPage({
6
+ params,
7
+ }: {
8
+ params: Promise<{ slug: string }>;
9
+ }) {
10
+ const { slug } = await params;
11
+ const manifest = await getSiteManifest();
12
+ const index = Number(slug.replace(/^post-/, "")) - 1;
13
+ const post = manifest.payload.blog_posts[index];
14
+ if (!post) notFound();
15
+
16
+ return (
17
+ <main className="site-main">
18
+ <p className="eyebrow">Blog</p>
19
+ <h1>{post.content_ref}</h1>
20
+ <div className="panel">
21
+ <p>Digest: {post.digest}</p>
22
+ </div>
23
+ </main>
24
+ );
25
+ }
@@ -0,0 +1,26 @@
1
+ import Link from "next/link";
2
+
3
+ import { getSiteManifest } from "@/lib/public-dj.server";
4
+ import { appRoutes } from "@/lib/routes";
5
+
6
+ export default async function BlogIndexPage() {
7
+ const manifest = await getSiteManifest();
8
+
9
+ return (
10
+ <main className="site-main">
11
+ <p className="eyebrow">Blog</p>
12
+ <h1>Updates</h1>
13
+ <div className="panel">
14
+ {manifest.payload.blog_posts.length === 0 ? (
15
+ <p>No published posts are pinned to this release yet.</p>
16
+ ) : (
17
+ manifest.payload.blog_posts.map((post, index) => (
18
+ <p key={`${post.content_ref}:${post.digest}`}>
19
+ <Link href={appRoutes.blogPost(`post-${index + 1}`)}>{post.content_ref}</Link>
20
+ </p>
21
+ ))
22
+ )}
23
+ </div>
24
+ </main>
25
+ );
26
+ }
@@ -0,0 +1,103 @@
1
+ :root {
2
+ color-scheme: light;
3
+ --background: #f8f5ef;
4
+ --foreground: #25231f;
5
+ --muted: #6d675f;
6
+ --line: #ded6ca;
7
+ --accent: #335c67;
8
+ --accent-strong: #1f3f46;
9
+ --surface: #fffdf8;
10
+ }
11
+
12
+ * {
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ body {
17
+ margin: 0;
18
+ background: var(--background);
19
+ color: var(--foreground);
20
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
21
+ }
22
+
23
+ a {
24
+ color: inherit;
25
+ }
26
+
27
+ .site-shell {
28
+ min-height: 100vh;
29
+ }
30
+
31
+ .site-header,
32
+ .site-main,
33
+ .site-footer {
34
+ width: min(1120px, calc(100vw - 40px));
35
+ margin: 0 auto;
36
+ }
37
+
38
+ .site-header {
39
+ display: flex;
40
+ align-items: center;
41
+ justify-content: space-between;
42
+ padding: 24px 0;
43
+ border-bottom: 1px solid var(--line);
44
+ }
45
+
46
+ .site-main {
47
+ padding: 72px 0;
48
+ }
49
+
50
+ .hero {
51
+ display: grid;
52
+ gap: 24px;
53
+ max-width: 760px;
54
+ }
55
+
56
+ .eyebrow {
57
+ margin: 0;
58
+ color: var(--accent);
59
+ font-size: 0.82rem;
60
+ font-weight: 700;
61
+ letter-spacing: 0.08em;
62
+ text-transform: uppercase;
63
+ }
64
+
65
+ h1 {
66
+ margin: 0;
67
+ font-family: Georgia, "Times New Roman", serif;
68
+ font-size: clamp(3rem, 8vw, 6.75rem);
69
+ font-weight: 500;
70
+ line-height: 0.95;
71
+ }
72
+
73
+ p {
74
+ color: var(--muted);
75
+ font-size: 1.08rem;
76
+ line-height: 1.7;
77
+ }
78
+
79
+ .button {
80
+ display: inline-flex;
81
+ min-height: 44px;
82
+ width: fit-content;
83
+ align-items: center;
84
+ justify-content: center;
85
+ border: 1px solid var(--accent-strong);
86
+ background: var(--accent-strong);
87
+ color: white;
88
+ padding: 0 18px;
89
+ text-decoration: none;
90
+ }
91
+
92
+ .panel {
93
+ margin-top: 40px;
94
+ border: 1px solid var(--line);
95
+ background: var(--surface);
96
+ padding: 24px;
97
+ }
98
+
99
+ .site-footer {
100
+ padding: 32px 0;
101
+ border-top: 1px solid var(--line);
102
+ color: var(--muted);
103
+ }
@@ -0,0 +1,18 @@
1
+ import type { Metadata } from "next";
2
+
3
+ import "@/app/globals.css";
4
+ import { env } from "@/lib/env.server";
5
+
6
+ export const metadata: Metadata = {
7
+ metadataBase: new URL(env.MW_PUBLIC_BASE_URL),
8
+ title: "Vuilder Public Site",
9
+ description: "A Vuilder public website backed by public-dj content revisions.",
10
+ };
11
+
12
+ export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
13
+ return (
14
+ <html lang="en">
15
+ <body>{children}</body>
16
+ </html>
17
+ );
18
+ }