create-bw-app 0.8.0 → 0.9.0
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/README.md +1 -1
- package/package.json +1 -1
- package/src/constants.mjs +0 -3
- package/src/generator.mjs +98 -27
- package/template/base/AGENTS.md +26 -0
- package/template/base/app/page.tsx +1 -1
- package/template/base/config/bootstrap.ts +1 -1
- package/template/base/config/brand.ts +7 -9
- package/template/base/config/modules.ts +3 -11
- package/template/base/docs/ai/README.md +44 -0
- package/template/modules/crm/app/api/crm/contacts/route.ts +6 -0
- package/template/modules/crm/app/api/crm/organizations/route.ts +6 -0
- package/template/modules/crm/app/api/crm/owners/route.ts +6 -0
- package/template/modules/crm/app/api/crm/stats/route.ts +6 -0
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ npm create bw-app@latest
|
|
|
34
34
|
- platform apps include BrightWeb auth, shell wiring, and optional module starter surfaces
|
|
35
35
|
- site apps include Next.js, Tailwind CSS v4, and local component primitives
|
|
36
36
|
- writes `package.json`, `next.config.ts`, `.gitignore`, and `README.md` for both templates
|
|
37
|
-
- platform apps also write `.env.
|
|
37
|
+
- platform apps also write `.env.local`, `AGENTS.md`, `docs/ai/README.md`, and generated config files for brand and module state
|
|
38
38
|
- supports repo-local `workspace:*` wiring and future published dependency wiring
|
|
39
39
|
|
|
40
40
|
## Workspace mode extras
|
package/package.json
CHANGED
package/src/constants.mjs
CHANGED
|
@@ -20,21 +20,18 @@ export const SELECTABLE_MODULES = [
|
|
|
20
20
|
label: "CRM",
|
|
21
21
|
packageName: "@brightweblabs/module-crm",
|
|
22
22
|
templateFolder: "crm",
|
|
23
|
-
envKey: "NEXT_PUBLIC_ENABLE_CRM",
|
|
24
23
|
},
|
|
25
24
|
{
|
|
26
25
|
key: "projects",
|
|
27
26
|
label: "Projects",
|
|
28
27
|
packageName: "@brightweblabs/module-projects",
|
|
29
28
|
templateFolder: "projects",
|
|
30
|
-
envKey: "NEXT_PUBLIC_ENABLE_PROJECTS",
|
|
31
29
|
},
|
|
32
30
|
{
|
|
33
31
|
key: "admin",
|
|
34
32
|
label: "Admin",
|
|
35
33
|
packageName: "@brightweblabs/module-admin",
|
|
36
34
|
templateFolder: "admin",
|
|
37
|
-
envKey: "NEXT_PUBLIC_ENABLE_ADMIN",
|
|
38
35
|
},
|
|
39
36
|
];
|
|
40
37
|
|
package/src/generator.mjs
CHANGED
|
@@ -256,13 +256,6 @@ async function getVersionMap(workspaceRoot) {
|
|
|
256
256
|
return versionMap;
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
function createModuleFlags(selectedModules) {
|
|
260
|
-
const selected = new Set(selectedModules);
|
|
261
|
-
return Object.fromEntries(
|
|
262
|
-
SELECTABLE_MODULES.map((moduleDefinition) => [moduleDefinition.key, selected.has(moduleDefinition.key)]),
|
|
263
|
-
);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
259
|
function createDerivedBrandValues(slug) {
|
|
267
260
|
const projectName = titleizeSlug(slug);
|
|
268
261
|
|
|
@@ -276,7 +269,94 @@ function createDerivedBrandValues(slug) {
|
|
|
276
269
|
};
|
|
277
270
|
}
|
|
278
271
|
|
|
279
|
-
function
|
|
272
|
+
function createPlatformBrandConfigFile({ slug, brandValues }) {
|
|
273
|
+
return [
|
|
274
|
+
"export type StarterBrandConfig = {",
|
|
275
|
+
" companyName: string;",
|
|
276
|
+
" productName: string;",
|
|
277
|
+
" slug: string;",
|
|
278
|
+
" tagline: string;",
|
|
279
|
+
" contactEmail: string;",
|
|
280
|
+
" supportEmail: string;",
|
|
281
|
+
" primaryHex: string;",
|
|
282
|
+
"};",
|
|
283
|
+
"",
|
|
284
|
+
"export const starterBrandConfig: StarterBrandConfig = {",
|
|
285
|
+
` companyName: ${JSON.stringify(brandValues.companyName)},`,
|
|
286
|
+
` productName: ${JSON.stringify(brandValues.productName)},`,
|
|
287
|
+
` slug: ${JSON.stringify(slug)},`,
|
|
288
|
+
` tagline: ${JSON.stringify(brandValues.tagline)},`,
|
|
289
|
+
` contactEmail: ${JSON.stringify(brandValues.contactEmail)},`,
|
|
290
|
+
` supportEmail: ${JSON.stringify(brandValues.supportEmail)},`,
|
|
291
|
+
` primaryHex: ${JSON.stringify(brandValues.primaryHex)},`,
|
|
292
|
+
"};",
|
|
293
|
+
"",
|
|
294
|
+
].join("\n");
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function createPlatformModulesConfigFile(selectedModules) {
|
|
298
|
+
const selected = new Set(selectedModules);
|
|
299
|
+
|
|
300
|
+
return [
|
|
301
|
+
'export type StarterModuleKey = "core-auth" | "crm" | "projects" | "admin";',
|
|
302
|
+
"",
|
|
303
|
+
"export type StarterModuleConfig = {",
|
|
304
|
+
" key: StarterModuleKey;",
|
|
305
|
+
" label: string;",
|
|
306
|
+
" description: string;",
|
|
307
|
+
" enabled: boolean;",
|
|
308
|
+
" packageName: string;",
|
|
309
|
+
" playgroundHref?: string;",
|
|
310
|
+
' placement: "core" | "primary" | "admin";',
|
|
311
|
+
"};",
|
|
312
|
+
"",
|
|
313
|
+
"export const starterModuleConfig: StarterModuleConfig[] = [",
|
|
314
|
+
" {",
|
|
315
|
+
' key: "core-auth",',
|
|
316
|
+
' label: "Core Auth",',
|
|
317
|
+
' description: "Login, reset-password, callback URLs, and shared auth validation utilities.",',
|
|
318
|
+
" enabled: true,",
|
|
319
|
+
' packageName: "@brightweblabs/core-auth",',
|
|
320
|
+
' playgroundHref: "/playground/auth",',
|
|
321
|
+
' placement: "core",',
|
|
322
|
+
" },",
|
|
323
|
+
" {",
|
|
324
|
+
' key: "crm",',
|
|
325
|
+
' label: "CRM",',
|
|
326
|
+
' description: "Contacts, marketing audience, and CRM server/data layer.",',
|
|
327
|
+
` enabled: ${String(selected.has("crm"))},`,
|
|
328
|
+
' packageName: "@brightweblabs/module-crm",',
|
|
329
|
+
' playgroundHref: "/playground/crm",',
|
|
330
|
+
' placement: "primary",',
|
|
331
|
+
" },",
|
|
332
|
+
" {",
|
|
333
|
+
' key: "projects",',
|
|
334
|
+
' label: "Projects",',
|
|
335
|
+
' description: "Project portfolio, detail routes, and work-management server logic.",',
|
|
336
|
+
` enabled: ${String(selected.has("projects"))},`,
|
|
337
|
+
' packageName: "@brightweblabs/module-projects",',
|
|
338
|
+
' playgroundHref: "/playground/projects",',
|
|
339
|
+
' placement: "primary",',
|
|
340
|
+
" },",
|
|
341
|
+
" {",
|
|
342
|
+
' key: "admin",',
|
|
343
|
+
' label: "Admin",',
|
|
344
|
+
' description: "User role governance, admin tools, and access-control surfaces.",',
|
|
345
|
+
` enabled: ${String(selected.has("admin"))},`,
|
|
346
|
+
' packageName: "@brightweblabs/module-admin",',
|
|
347
|
+
' playgroundHref: "/playground/admin",',
|
|
348
|
+
' placement: "admin",',
|
|
349
|
+
" },",
|
|
350
|
+
"];",
|
|
351
|
+
"",
|
|
352
|
+
"export function getEnabledStarterModules() {",
|
|
353
|
+
" return starterModuleConfig.filter((moduleConfig) => moduleConfig.enabled);",
|
|
354
|
+
"}",
|
|
355
|
+
"",
|
|
356
|
+
].join("\n");
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function createEnvFileContent() {
|
|
280
360
|
return [
|
|
281
361
|
"NEXT_PUBLIC_APP_URL=http://localhost:3000",
|
|
282
362
|
"NEXT_PUBLIC_SUPABASE_URL=",
|
|
@@ -284,18 +364,6 @@ function createEnvFileContent({ slug, brandValues, moduleFlags }) {
|
|
|
284
364
|
"SUPABASE_SERVICE_ROLE_KEY=",
|
|
285
365
|
"RESEND_API_KEY=",
|
|
286
366
|
"",
|
|
287
|
-
`NEXT_PUBLIC_CLIENT_COMPANY_NAME=${brandValues.companyName}`,
|
|
288
|
-
`NEXT_PUBLIC_CLIENT_PRODUCT_NAME=${brandValues.productName}`,
|
|
289
|
-
`NEXT_PUBLIC_CLIENT_SLUG=${slug}`,
|
|
290
|
-
`NEXT_PUBLIC_CLIENT_TAGLINE=${brandValues.tagline}`,
|
|
291
|
-
`NEXT_PUBLIC_CLIENT_CONTACT_EMAIL=${brandValues.contactEmail}`,
|
|
292
|
-
`NEXT_PUBLIC_CLIENT_SUPPORT_EMAIL=${brandValues.supportEmail}`,
|
|
293
|
-
`NEXT_PUBLIC_CLIENT_PRIMARY_HEX=${brandValues.primaryHex}`,
|
|
294
|
-
"",
|
|
295
|
-
`NEXT_PUBLIC_ENABLE_CRM=${String(moduleFlags.crm)}`,
|
|
296
|
-
`NEXT_PUBLIC_ENABLE_PROJECTS=${String(moduleFlags.projects)}`,
|
|
297
|
-
`NEXT_PUBLIC_ENABLE_ADMIN=${String(moduleFlags.admin)}`,
|
|
298
|
-
"",
|
|
299
367
|
].join("\n");
|
|
300
368
|
}
|
|
301
369
|
|
|
@@ -333,9 +401,8 @@ function createGitignore() {
|
|
|
333
401
|
"yarn-error.log*",
|
|
334
402
|
".pnpm-debug.log*",
|
|
335
403
|
"",
|
|
336
|
-
"# env files
|
|
404
|
+
"# env files",
|
|
337
405
|
".env*",
|
|
338
|
-
"!.env.example",
|
|
339
406
|
"",
|
|
340
407
|
"# vercel",
|
|
341
408
|
".vercel",
|
|
@@ -363,12 +430,12 @@ function createPlatformReadme({
|
|
|
363
430
|
|
|
364
431
|
const localSteps = workspaceMode
|
|
365
432
|
? [
|
|
366
|
-
"1. Review `.env.
|
|
433
|
+
"1. Review `.env.local` and fill in real service credentials.",
|
|
367
434
|
"2. Run `pnpm install` from the BrightWeb workspace root.",
|
|
368
435
|
`3. Run \`pnpm --filter ${slug} dev\`.`,
|
|
369
436
|
]
|
|
370
437
|
: [
|
|
371
|
-
"1. Review `.env.
|
|
438
|
+
"1. Review `.env.local` and fill in real service credentials.",
|
|
372
439
|
`2. Run \`${packageManager} install\`.`,
|
|
373
440
|
`3. Run \`${packageManager} dev\`.`,
|
|
374
441
|
];
|
|
@@ -871,7 +938,6 @@ async function scaffoldPlatformProject({
|
|
|
871
938
|
answers,
|
|
872
939
|
dbInstallPlan,
|
|
873
940
|
}) {
|
|
874
|
-
const moduleFlags = createModuleFlags(selectedModules);
|
|
875
941
|
const brandValues = createDerivedBrandValues(answers.slug);
|
|
876
942
|
const baseTemplateDir = path.join(TEMPLATE_ROOT, "base");
|
|
877
943
|
|
|
@@ -899,11 +965,16 @@ async function scaffoldPlatformProject({
|
|
|
899
965
|
)}\n`,
|
|
900
966
|
);
|
|
901
967
|
await fs.writeFile(path.join(targetDir, "next.config.ts"), createNextConfig({ template: "platform", selectedModules }));
|
|
968
|
+
await fs.writeFile(
|
|
969
|
+
path.join(targetDir, "config", "brand.ts"),
|
|
970
|
+
createPlatformBrandConfigFile({ slug: answers.slug, brandValues }),
|
|
971
|
+
);
|
|
972
|
+
await fs.writeFile(path.join(targetDir, "config", "modules.ts"), createPlatformModulesConfigFile(selectedModules));
|
|
902
973
|
await fs.writeFile(path.join(targetDir, "config", "shell.ts"), createShellConfig(selectedModules));
|
|
903
974
|
|
|
904
|
-
const envFileContent = createEnvFileContent(
|
|
975
|
+
const envFileContent = createEnvFileContent();
|
|
905
976
|
|
|
906
|
-
await fs.writeFile(path.join(targetDir, ".env.
|
|
977
|
+
await fs.writeFile(path.join(targetDir, ".env.local"), envFileContent);
|
|
907
978
|
await fs.writeFile(path.join(targetDir, ".gitignore"), createGitignore());
|
|
908
979
|
await fs.writeFile(
|
|
909
980
|
path.join(targetDir, "README.md"),
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This generated project is a BrightWeb platform starter. Use this file as the local entrypoint for AI agents working inside the app.
|
|
4
|
+
|
|
5
|
+
## Start here
|
|
6
|
+
|
|
7
|
+
- `README.md`: local setup commands and starter routes.
|
|
8
|
+
- `docs/ai/README.md`: app-specific routing guide for agents.
|
|
9
|
+
- `config/brand.ts`: client identity, naming, and contact defaults.
|
|
10
|
+
- `config/modules.ts`: selected module set and runtime enablement.
|
|
11
|
+
- `config/client.ts`: starter-facing derived state used by the home page and setup surfaces.
|
|
12
|
+
- `.env.local`: runtime service values for local development.
|
|
13
|
+
|
|
14
|
+
## Working rules
|
|
15
|
+
|
|
16
|
+
- Treat `/bootstrap`, `/preview/app-shell`, and `/playground/*` as starter validation surfaces. They are app-owned and can be removed after setup if links and references are cleaned up too.
|
|
17
|
+
- Check `config/modules.ts` before assuming CRM, Projects, or Admin routes exist.
|
|
18
|
+
- Prefer composing app-level routes and config before forking logic from `@brightweblabs/*` packages.
|
|
19
|
+
- Keep edits local to this app unless the change is intentionally shared across multiple BrightWeb projects.
|
|
20
|
+
|
|
21
|
+
## First validation pass
|
|
22
|
+
|
|
23
|
+
1. Run the local dev server from this project or workspace.
|
|
24
|
+
2. Open `/`, `/bootstrap`, `/preview/app-shell`, and `/playground/auth`.
|
|
25
|
+
3. If optional modules are enabled, open the matching `/playground/*` route for each one.
|
|
26
|
+
4. Confirm `.env.local` contains real service values before debugging runtime behavior.
|
|
@@ -115,7 +115,7 @@ export default function HomePage() {
|
|
|
115
115
|
<li>`config/brand.ts` for client identity and contact details.</li>
|
|
116
116
|
<li>`config/modules.ts` for enabled platform modules.</li>
|
|
117
117
|
<li>`config/env.ts` for infra requirements and readiness checks.</li>
|
|
118
|
-
<li>`.env.
|
|
118
|
+
<li>`.env.local` for per-client service credentials and local runtime overrides.</li>
|
|
119
119
|
</ul>
|
|
120
120
|
</div>
|
|
121
121
|
</article>
|
|
@@ -69,7 +69,7 @@ export function getStarterBootstrapChecklist() {
|
|
|
69
69
|
{
|
|
70
70
|
label: "Create per-client environment variables",
|
|
71
71
|
done: config.envReadiness.allReady,
|
|
72
|
-
detail: "
|
|
72
|
+
detail: "Fill `.env.local` with the real service values for this client.",
|
|
73
73
|
},
|
|
74
74
|
],
|
|
75
75
|
};
|
|
@@ -9,13 +9,11 @@ export type StarterBrandConfig = {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
export const starterBrandConfig: StarterBrandConfig = {
|
|
12
|
-
companyName:
|
|
13
|
-
productName:
|
|
14
|
-
slug:
|
|
15
|
-
tagline:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
supportEmail: process.env.NEXT_PUBLIC_CLIENT_SUPPORT_EMAIL?.trim() || "support@example.com",
|
|
20
|
-
primaryHex: process.env.NEXT_PUBLIC_CLIENT_PRIMARY_HEX?.trim() || "#1f7a45",
|
|
12
|
+
companyName: "Starter Client",
|
|
13
|
+
productName: "Operations Platform",
|
|
14
|
+
slug: "starter-client",
|
|
15
|
+
tagline: "A configurable Brightweb starter app for shipping new client instances without rebuilding the platform.",
|
|
16
|
+
contactEmail: "hello@example.com",
|
|
17
|
+
supportEmail: "support@example.com",
|
|
18
|
+
primaryHex: "#1f7a45",
|
|
21
19
|
};
|
|
@@ -10,14 +10,6 @@ export type StarterModuleConfig = {
|
|
|
10
10
|
placement: "core" | "primary" | "admin";
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
function envFlag(value: string | undefined, defaultValue: boolean) {
|
|
14
|
-
if (typeof value !== "string") return defaultValue;
|
|
15
|
-
const normalized = value.trim().toLowerCase();
|
|
16
|
-
if (["1", "true", "yes", "on"].includes(normalized)) return true;
|
|
17
|
-
if (["0", "false", "no", "off"].includes(normalized)) return false;
|
|
18
|
-
return defaultValue;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
13
|
export const starterModuleConfig: StarterModuleConfig[] = [
|
|
22
14
|
{
|
|
23
15
|
key: "core-auth",
|
|
@@ -32,7 +24,7 @@ export const starterModuleConfig: StarterModuleConfig[] = [
|
|
|
32
24
|
key: "crm",
|
|
33
25
|
label: "CRM",
|
|
34
26
|
description: "Contacts, marketing audience, and CRM server/data layer.",
|
|
35
|
-
enabled:
|
|
27
|
+
enabled: true,
|
|
36
28
|
packageName: "@brightweblabs/module-crm",
|
|
37
29
|
playgroundHref: "/playground/crm",
|
|
38
30
|
placement: "primary",
|
|
@@ -41,7 +33,7 @@ export const starterModuleConfig: StarterModuleConfig[] = [
|
|
|
41
33
|
key: "projects",
|
|
42
34
|
label: "Projects",
|
|
43
35
|
description: "Project portfolio, detail routes, and work-management server logic.",
|
|
44
|
-
enabled:
|
|
36
|
+
enabled: true,
|
|
45
37
|
packageName: "@brightweblabs/module-projects",
|
|
46
38
|
playgroundHref: "/playground/projects",
|
|
47
39
|
placement: "primary",
|
|
@@ -50,7 +42,7 @@ export const starterModuleConfig: StarterModuleConfig[] = [
|
|
|
50
42
|
key: "admin",
|
|
51
43
|
label: "Admin",
|
|
52
44
|
description: "User role governance, admin tools, and access-control surfaces.",
|
|
53
|
-
enabled:
|
|
45
|
+
enabled: true,
|
|
54
46
|
packageName: "@brightweblabs/module-admin",
|
|
55
47
|
playgroundHref: "/playground/admin",
|
|
56
48
|
placement: "admin",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Agent Guide
|
|
2
|
+
|
|
3
|
+
This file is the local routing guide for AI agents working inside a generated BrightWeb platform app.
|
|
4
|
+
|
|
5
|
+
It is intentionally app-scoped. It explains the generated project you are in, not the maintainer-only BrightWeb monorepo internals.
|
|
6
|
+
|
|
7
|
+
## Project shape
|
|
8
|
+
|
|
9
|
+
This app is a normal Next.js App Router project with BrightWeb runtime wiring layered on top.
|
|
10
|
+
|
|
11
|
+
- `app/`: route tree, layouts, pages, starter previews, and playground routes.
|
|
12
|
+
- `config/`: generated app configuration for brand, env readiness, enabled modules, bootstrap content, and shell registration.
|
|
13
|
+
- `public/brand/`: starter logos used by the shell lockups.
|
|
14
|
+
- `.env.local`: local service configuration for Supabase, Resend, and runtime URLs.
|
|
15
|
+
|
|
16
|
+
## Fast routing map
|
|
17
|
+
|
|
18
|
+
- `README.md`: first-run setup steps.
|
|
19
|
+
- `config/brand.ts`: client name, product name, support inboxes, and brand color.
|
|
20
|
+
- `config/modules.ts`: module metadata and enablement flags for CRM, Projects, and Admin.
|
|
21
|
+
- `config/client.ts`: aggregated state consumed by starter pages.
|
|
22
|
+
- `config/bootstrap.ts`: bootstrap checklist content for `/bootstrap`.
|
|
23
|
+
- `config/shell.ts`: app-shell registration and navigation wiring.
|
|
24
|
+
- `app/page.tsx`: starter landing page for the generated app.
|
|
25
|
+
- `app/bootstrap/page.tsx`: setup checklist surface.
|
|
26
|
+
- `app/preview/app-shell/page.tsx`: shell preview validation route.
|
|
27
|
+
- `app/playground/auth/page.tsx`: auth validation route.
|
|
28
|
+
- `app/playground/*`: optional module playgrounds when those modules were selected at scaffold time.
|
|
29
|
+
|
|
30
|
+
## Editing strategy
|
|
31
|
+
|
|
32
|
+
- Change client identity first in `config/brand.ts`.
|
|
33
|
+
- Check module presence in `config/modules.ts` before editing or creating module-specific routes.
|
|
34
|
+
- Use `config/shell.ts` when navigation or toolbar behavior needs to change.
|
|
35
|
+
- Use `config/bootstrap.ts` and `config/client.ts` when the setup checklist or readiness messaging is wrong.
|
|
36
|
+
- Keep starter validation routes until the real product routes replace their purpose.
|
|
37
|
+
|
|
38
|
+
## Validation checklist
|
|
39
|
+
|
|
40
|
+
1. Confirm `.env.local` is populated with real values.
|
|
41
|
+
2. Run the app locally.
|
|
42
|
+
3. Validate `/`, `/bootstrap`, `/preview/app-shell`, and `/playground/auth`.
|
|
43
|
+
4. Validate the playground route for each enabled optional module.
|
|
44
|
+
5. If a starter route is removed, also remove any links or config references that still point to it.
|