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.
- package/EXTERNAL_ALPHA.md +17 -1
- package/README.md +21 -1
- package/assets/claude-local/skills/README.md +5 -0
- package/assets/claude-local/skills/app-pack-authoring/SKILL.md +15 -0
- package/assets/claude-local/skills/generated-workspace-architecture/SKILL.md +25 -9
- package/assets/claude-local/skills/shell-architecture/SKILL.md +15 -0
- package/assets/claude-local/skills/vuilder-public-site-authoring/SKILL.md +10 -4
- package/assets/claude-local/skills/vuilder-workspace-architecture/SKILL.md +78 -0
- package/assets/templates/vuilder-public-site/.env.example +11 -0
- package/assets/templates/vuilder-public-site/README.md +15 -0
- package/assets/templates/vuilder-public-site/eslint.config.mjs +6 -0
- package/assets/templates/vuilder-public-site/next-env.d.ts +4 -0
- package/assets/templates/vuilder-public-site/next.config.mjs +28 -0
- package/assets/templates/vuilder-public-site/package.json +39 -0
- package/assets/templates/vuilder-public-site/postcss.config.mjs +5 -0
- package/assets/templates/vuilder-public-site/src/app/api/onboarding/start/route.ts +19 -0
- package/assets/templates/vuilder-public-site/src/app/blog/[slug]/page.tsx +25 -0
- package/assets/templates/vuilder-public-site/src/app/blog/page.tsx +26 -0
- package/assets/templates/vuilder-public-site/src/app/globals.css +103 -0
- package/assets/templates/vuilder-public-site/src/app/layout.tsx +18 -0
- package/assets/templates/vuilder-public-site/src/app/onboarding/[[...step]]/page.tsx +39 -0
- package/assets/templates/vuilder-public-site/src/app/page.tsx +43 -0
- package/assets/templates/vuilder-public-site/src/lib/env.server.ts +31 -0
- package/assets/templates/vuilder-public-site/src/lib/platform.server.ts +47 -0
- package/assets/templates/vuilder-public-site/src/lib/public-dj.server.ts +86 -0
- package/assets/templates/vuilder-public-site/src/lib/public-dj.test.ts +8 -0
- package/assets/templates/vuilder-public-site/src/lib/routes.test.ts +13 -0
- package/assets/templates/vuilder-public-site/src/lib/routes.ts +12 -0
- package/assets/templates/vuilder-public-site/template.json +21 -0
- package/assets/templates/vuilder-public-site/tools/template/validate-template.mjs +44 -0
- package/assets/templates/vuilder-public-site/tsconfig.json +23 -0
- package/assets/templates/vuilder-public-site/vitest.config.ts +13 -0
- package/assets/templates/vuilder-shell/.env.example +8 -0
- package/assets/templates/vuilder-shell/.storybook/main.ts +19 -0
- package/assets/templates/vuilder-shell/.storybook/preview.tsx +38 -0
- package/assets/templates/vuilder-shell/README.md +49 -0
- package/assets/templates/vuilder-shell/components.json +21 -0
- package/assets/templates/vuilder-shell/eslint.config.mjs +41 -0
- package/assets/templates/vuilder-shell/next-env.d.ts +6 -0
- package/assets/templates/vuilder-shell/next.config.mjs +33 -0
- package/assets/templates/vuilder-shell/package.json +61 -0
- package/assets/templates/vuilder-shell/postcss.config.mjs +8 -0
- package/assets/templates/vuilder-shell/public/.gitkeep +1 -0
- package/assets/templates/vuilder-shell/src/app/api/auth/accept-shell-session/route.test.ts +105 -0
- package/assets/templates/vuilder-shell/src/app/api/auth/accept-shell-session/route.ts +63 -0
- package/assets/templates/vuilder-shell/src/app/api/auth/logout/route.test.ts +63 -0
- package/assets/templates/vuilder-shell/src/app/api/auth/logout/route.ts +24 -0
- package/assets/templates/vuilder-shell/src/app/api/auth/session/route.test.ts +70 -0
- package/assets/templates/vuilder-shell/src/app/api/auth/session/route.ts +27 -0
- package/assets/templates/vuilder-shell/src/app/app/layout.tsx +17 -0
- package/assets/templates/vuilder-shell/src/app/app/page.tsx +30 -0
- package/assets/templates/vuilder-shell/src/app/blog/[slug]/page.tsx +15 -0
- package/assets/templates/vuilder-shell/src/app/blog/page.tsx +15 -0
- package/assets/templates/vuilder-shell/src/app/docs/[...slug]/page.tsx +15 -0
- package/assets/templates/vuilder-shell/src/app/docs/page.tsx +15 -0
- package/assets/templates/vuilder-shell/src/app/globals.css +70 -0
- package/assets/templates/vuilder-shell/src/app/layout.tsx +69 -0
- package/assets/templates/vuilder-shell/src/app/login/route.test.ts +33 -0
- package/assets/templates/vuilder-shell/src/app/login/route.ts +21 -0
- package/assets/templates/vuilder-shell/src/app/page.tsx +16 -0
- package/assets/templates/vuilder-shell/src/app/pricing/page.tsx +15 -0
- package/assets/templates/vuilder-shell/src/app/providers.tsx +25 -0
- package/assets/templates/vuilder-shell/src/app/robots.ts +21 -0
- package/assets/templates/vuilder-shell/src/app/sitemap.ts +33 -0
- package/assets/templates/vuilder-shell/src/app/w/[workspace_slug]/connect/page.tsx +31 -0
- package/assets/templates/vuilder-shell/src/app/w/[workspace_slug]/page.tsx +54 -0
- package/assets/templates/vuilder-shell/src/components/ui/button.tsx +59 -0
- package/assets/templates/vuilder-shell/src/components/ui/input.tsx +21 -0
- package/assets/templates/vuilder-shell/src/design-system/docs/governance.mdx +26 -0
- package/assets/templates/vuilder-shell/src/design-system/patterns/panel-frame.stories.tsx +48 -0
- package/assets/templates/vuilder-shell/src/design-system/patterns/panel-frame.tsx +26 -0
- package/assets/templates/vuilder-shell/src/design-system/patterns/status-badge.stories.tsx +26 -0
- package/assets/templates/vuilder-shell/src/design-system/patterns/status-badge.tsx +35 -0
- package/assets/templates/vuilder-shell/src/design-system/patterns/theme-mode-toggle.stories.tsx +21 -0
- package/assets/templates/vuilder-shell/src/design-system/patterns/theme-mode-toggle.tsx +75 -0
- package/assets/templates/vuilder-shell/src/design-system/primitives/button.stories.tsx +37 -0
- package/assets/templates/vuilder-shell/src/design-system/primitives/button.ts +1 -0
- package/assets/templates/vuilder-shell/src/design-system/primitives/input.stories.tsx +26 -0
- package/assets/templates/vuilder-shell/src/design-system/primitives/input.ts +1 -0
- package/assets/templates/vuilder-shell/src/design-system/recipes/chrome.ts +28 -0
- package/assets/templates/vuilder-shell/src/design-system/tokens/foundation.css +31 -0
- package/assets/templates/vuilder-shell/src/design-system/tokens/index.css +3 -0
- package/assets/templates/vuilder-shell/src/design-system/tokens/manifest.json +85 -0
- package/assets/templates/vuilder-shell/src/design-system/tokens/manifest.ts +87 -0
- package/assets/templates/vuilder-shell/src/design-system/tokens/semantic.css +105 -0
- package/assets/templates/vuilder-shell/src/design-system/tokens/theme.css +59 -0
- package/assets/templates/vuilder-shell/src/design-system/tokens/tokens.stories.tsx +71 -0
- package/assets/templates/vuilder-shell/src/features/dashboard/components/tenant-dashboard.tsx +134 -0
- package/assets/templates/vuilder-shell/src/features/public-shell/components/static-public-page.tsx +58 -0
- package/assets/templates/vuilder-shell/src/features/shell/components/authenticated-app-layout-shell.tsx +84 -0
- package/assets/templates/vuilder-shell/src/features/shell/components/private-app-shell.tsx +22 -0
- package/assets/templates/vuilder-shell/src/features/vuilder-shell/components/vuilder-connect-screen.tsx +89 -0
- package/assets/templates/vuilder-shell/src/features/vuilder-shell/components/vuilder-workspace-screen.tsx +49 -0
- package/assets/templates/vuilder-shell/src/lib/app-routes.test.ts +37 -0
- package/assets/templates/vuilder-shell/src/lib/app-routes.ts +86 -0
- package/assets/templates/vuilder-shell/src/lib/auth-routes.server.test.ts +26 -0
- package/assets/templates/vuilder-shell/src/lib/auth-routes.server.ts +53 -0
- package/assets/templates/vuilder-shell/src/lib/http/same-origin.test.ts +23 -0
- package/assets/templates/vuilder-shell/src/lib/http/same-origin.ts +18 -0
- package/assets/templates/vuilder-shell/src/lib/platform/client.server.test.ts +201 -0
- package/assets/templates/vuilder-shell/src/lib/platform/client.server.ts +540 -0
- package/assets/templates/vuilder-shell/src/lib/platform/contracts.ts +190 -0
- package/assets/templates/vuilder-shell/src/lib/platform/endpoints.server.ts +29 -0
- package/assets/templates/vuilder-shell/src/lib/platform/env.server.ts +82 -0
- package/assets/templates/vuilder-shell/src/lib/platform/route-response.ts +33 -0
- package/assets/templates/vuilder-shell/src/lib/platform/session.server.ts +145 -0
- package/assets/templates/vuilder-shell/src/lib/public-site.test.ts +20 -0
- package/assets/templates/vuilder-shell/src/lib/public-site.ts +48 -0
- package/assets/templates/vuilder-shell/src/lib/theme-config.ts +10 -0
- package/assets/templates/vuilder-shell/src/lib/theme.tsx +159 -0
- package/assets/templates/vuilder-shell/src/lib/utils.ts +6 -0
- package/assets/templates/vuilder-shell/template.json +28 -0
- package/assets/templates/vuilder-shell/template.schema.json +171 -0
- package/assets/templates/vuilder-shell/test/server-only-stub.ts +1 -0
- package/assets/templates/vuilder-shell/tools/design-system/build-token-manifest.mjs +3 -0
- package/assets/templates/vuilder-shell/tools/design-system/check-imports.mjs +9 -0
- package/assets/templates/vuilder-shell/tools/design-system/check-stories.mjs +9 -0
- package/assets/templates/vuilder-shell/tools/design-system/check-values.mjs +9 -0
- package/assets/templates/vuilder-shell/tools/design-system/checks.mjs +238 -0
- package/assets/templates/vuilder-shell/tools/design-system/eslint-plugin-design-system.mjs +184 -0
- package/assets/templates/vuilder-shell/tools/design-system/playwright.config.mjs +34 -0
- package/assets/templates/vuilder-shell/tools/design-system/run-checks.mjs +22 -0
- package/assets/templates/vuilder-shell/tools/design-system/shared.mjs +166 -0
- package/assets/templates/vuilder-shell/tools/design-system/visual.spec.ts +41 -0
- package/assets/templates/vuilder-shell/tools/template/validate-route-contract.mjs +373 -0
- package/assets/templates/vuilder-shell/tools/template/validate-template.mjs +45 -0
- package/assets/templates/vuilder-shell/tools/template/with-public-site-fixture.mjs +45 -0
- package/assets/templates/vuilder-shell/tsconfig.json +42 -0
- package/assets/templates/vuilder-shell/vitest.config.ts +23 -0
- package/dist/auth.js +66 -14
- package/dist/auth.js.map +1 -1
- package/dist/deploy-state.d.ts +1 -0
- package/dist/deploy-state.js.map +1 -1
- package/dist/deploy.js +18 -4
- package/dist/deploy.js.map +1 -1
- package/dist/developer-client.d.ts +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/init-prompt.js +21 -13
- package/dist/init-prompt.js.map +1 -1
- package/dist/init.d.ts +3 -1
- package/dist/init.js +103 -12
- package/dist/init.js.map +1 -1
- package/dist/orchestrator-context.js +17 -5
- package/dist/orchestrator-context.js.map +1 -1
- package/dist/orchestrator-state.d.ts +2 -2
- package/dist/orchestrator-state.js.map +1 -1
- package/dist/publish.js +12 -2
- package/dist/publish.js.map +1 -1
- package/dist/state.d.ts +2 -0
- package/dist/state.js +9 -0
- package/dist/state.js.map +1 -1
- package/package.json +3 -3
- package/vendor/workspace-mcp/context.d.ts +3 -1
- package/vendor/workspace-mcp/context.js +134 -21
- package/vendor/workspace-mcp/context.js.map +1 -1
- package/vendor/workspace-mcp/types.d.ts +72 -7
- package/vendor/workspace-mcp/types.js +8 -4
- package/vendor/workspace-mcp/types.js.map +1 -1
- package/assets/templates/fastapi-sidecar/poetry.lock +0 -757
- package/assets/templates/next-tenant-app/package-lock.json +0 -9682
- 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` (
|
|
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
|
|
23
|
-
|
|
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
|
-
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
`
|
|
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`, `
|
|
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
|
|
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 `
|
|
29
|
-
|
|
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,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,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
|
+
}
|