create-lego-one 2.0.12 โ†’ 2.0.14

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 (78) hide show
  1. package/dist/index.cjs +150 -15
  2. package/dist/index.cjs.map +1 -1
  3. package/package.json +1 -1
  4. package/template/.cursor/rules/rules.mdc +639 -0
  5. package/template/.dockerignore +58 -0
  6. package/template/.env.example +18 -0
  7. package/template/.eslintignore +5 -0
  8. package/template/.eslintrc.js +28 -0
  9. package/template/.prettierignore +6 -0
  10. package/template/.prettierrc +11 -0
  11. package/template/CLAUDE.md +634 -0
  12. package/template/Dockerfile +67 -0
  13. package/template/PROMPT.md +457 -0
  14. package/template/README.md +325 -0
  15. package/template/docker-compose.yml +48 -0
  16. package/template/docker-entrypoint.sh +23 -0
  17. package/template/docs/checkpoints/.template.md +64 -0
  18. package/template/docs/checkpoints/framework/01-infrastructure-setup.md +132 -0
  19. package/template/docs/checkpoints/framework/02-pocketbase-setup.md +155 -0
  20. package/template/docs/checkpoints/framework/03-host-kernel.md +170 -0
  21. package/template/docs/checkpoints/framework/04-auth-system.md +163 -0
  22. package/template/docs/checkpoints/framework/phase-05-multitenancy-rbac.md +223 -0
  23. package/template/docs/checkpoints/framework/phase-06-ui-components.md +260 -0
  24. package/template/docs/checkpoints/framework/phase-07-communication-system.md +276 -0
  25. package/template/docs/checkpoints/framework/phase-08-plugin-system.md +91 -0
  26. package/template/docs/checkpoints/framework/phase-09-dashboard-plugin.md +111 -0
  27. package/template/docs/checkpoints/framework/phase-10-todo-plugin.md +169 -0
  28. package/template/docs/checkpoints/framework/phase-11-testing.md +264 -0
  29. package/template/docs/checkpoints/framework/phase-12-deployment.md +294 -0
  30. package/template/docs/checkpoints/framework/phase-13-documentation.md +312 -0
  31. package/template/docs/framework/plans/00-index.md +164 -0
  32. package/template/docs/framework/plans/01-infrastructure-setup.md +855 -0
  33. package/template/docs/framework/plans/02-pocketbase-setup.md +1374 -0
  34. package/template/docs/framework/plans/03-host-kernel.md +1518 -0
  35. package/template/docs/framework/plans/04-auth-system.md +1466 -0
  36. package/template/docs/framework/plans/05-multitenancy-rbac.md +1527 -0
  37. package/template/docs/framework/plans/06-ui-components.md +1478 -0
  38. package/template/docs/framework/plans/07-communication-system.md +1106 -0
  39. package/template/docs/framework/plans/08-plugin-system.md +1179 -0
  40. package/template/docs/framework/plans/09-dashboard-plugin.md +1137 -0
  41. package/template/docs/framework/plans/10-todo-plugin.md +1343 -0
  42. package/template/docs/framework/plans/11-testing.md +935 -0
  43. package/template/docs/framework/plans/12-deployment.md +896 -0
  44. package/template/docs/framework/prompts/0-boilerplate-modernjs.md +151 -0
  45. package/template/docs/framework/research/00-modernjs-audit.md +488 -0
  46. package/template/docs/framework/research/01-system-blueprint.md +721 -0
  47. package/template/docs/framework/research/02-data-migration-protocol.md +699 -0
  48. package/template/docs/framework/research/03-host-setup.md +714 -0
  49. package/template/docs/framework/research/04-plugin-architecture.md +645 -0
  50. package/template/docs/framework/research/05-slot-injection-pattern.md +671 -0
  51. package/template/docs/framework/research/06-cli-strategy.md +615 -0
  52. package/template/docs/framework/research/07-deployment.md +629 -0
  53. package/template/docs/framework/research/README.md +282 -0
  54. package/template/docs/framework/setup/00-index.md +210 -0
  55. package/template/docs/framework/setup/01-framework-structure.md +308 -0
  56. package/template/docs/framework/setup/02-development-workflow.md +405 -0
  57. package/template/docs/framework/setup/03-environment-setup.md +215 -0
  58. package/template/docs/framework/setup/04-kernel-architecture.md +499 -0
  59. package/template/docs/framework/setup/05-plugin-system.md +620 -0
  60. package/template/docs/framework/setup/06-communication-patterns.md +451 -0
  61. package/template/docs/framework/setup/07-plugin-development.md +582 -0
  62. package/template/docs/framework/setup/08-component-library.md +658 -0
  63. package/template/docs/framework/setup/09-data-integration.md +609 -0
  64. package/template/docs/framework/setup/10-auth-rbac.md +497 -0
  65. package/template/docs/framework/setup/11-hooks-api.md +393 -0
  66. package/template/docs/framework/setup/12-components-api.md +665 -0
  67. package/template/docs/framework/setup/13-deployment-guide.md +566 -0
  68. package/template/docs/framework/setup/README.md +548 -0
  69. package/template/host/package.json +1 -1
  70. package/template/nginx.conf +72 -0
  71. package/template/package.json +1 -1
  72. package/template/packages/plugins/@lego/plugin-dashboard/package.json +1 -1
  73. package/template/packages/plugins/@lego/plugin-todo/package.json +1 -1
  74. package/template/pocketbase/CHANGELOG.md +911 -0
  75. package/template/pocketbase/LICENSE.md +17 -0
  76. package/template/scripts/create-plugin.js +221 -0
  77. package/template/scripts/deploy.sh +56 -0
  78. package/template/tsconfig.base.json +26 -0
@@ -0,0 +1,855 @@
1
+ # Infrastructure Setup
2
+
3
+ > **For AI:** This is the first implementation document. Complete all tasks in order before proceeding to `02-pocketbase-setup.md`.
4
+
5
+ **Goal:** Set up the monorepo structure, configure tooling (pnpm, TypeScript, ESLint, Prettier), and create base package configurations.
6
+
7
+ **Architecture:** Monorepo with pnpm workspaces. Root manages shared dev dependencies. Host app and plugins are separate workspaces.
8
+
9
+ **Tech Stack:** pnpm, TypeScript, ESLint, Prettier, Turbo (optional), Husky not needed (keeping it simple per decision)
10
+
11
+ ---
12
+
13
+ ## Task 1: Initialize Root Package
14
+
15
+ **Files:**
16
+ - Create: `package.json`
17
+ - Create: `pnpm-workspace.yaml`
18
+ - Create: `pnpm-lock.yaml` (auto-generated)
19
+ - Create: `.gitignore`
20
+ - Create: `.npmrc`
21
+
22
+ **Step 1: Create package.json**
23
+
24
+ Create `package.json`:
25
+
26
+ ```json
27
+ {
28
+ "name": "lego-one",
29
+ "version": "1.0.0",
30
+ "private": true,
31
+ "description": "Microkernel SaaS OS with Modern.js + Garfish + PocketBase",
32
+ "type": "module",
33
+ "scripts": {
34
+ "dev": "pnpm --filter './host' dev",
35
+ "dev:host": "pnpm --filter './host' dev",
36
+ "dev:plugins": "pnpm -r --filter './packages/plugins/@lego/*' dev",
37
+ "dev:all": "pnpm --filter './host' dev & pnpm -r --filter './packages/plugins/@lego/*' dev",
38
+ "build": "pnpm --filter './host' build && pnpm -r --filter './packages/plugins/@lego/*' build",
39
+ "lint": "pnpm -r lint",
40
+ "lint:fix": "pnpm -r lint:fix",
41
+ "format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
42
+ "format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,md}\"",
43
+ "typecheck": "pnpm -r typecheck",
44
+ "test": "pnpm -r test",
45
+ "test:e2e": "pnpm --filter './host' test:e2e",
46
+ "clean": "pnpm -r exec rm -rf dist node_modules",
47
+ "create-plugin": "node scripts/create-plugin.js"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^20.11.0",
51
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
52
+ "@typescript-eslint/parser": "^7.0.0",
53
+ "eslint": "^8.57.0",
54
+ "eslint-config-prettier": "^9.1.0",
55
+ "prettier": "^3.2.0",
56
+ "prettier-plugin-tailwindcss": "^0.5.0",
57
+ "typescript": "^5.3.0"
58
+ },
59
+ "engines": {
60
+ "node": ">=18.0.0",
61
+ "pnpm": ">=8.0.0"
62
+ }
63
+ }
64
+ ```
65
+
66
+ **Step 2: Create pnpm-workspace.yaml**
67
+
68
+ Create `pnpm-workspace.yaml`:
69
+
70
+ ```yaml
71
+ packages:
72
+ - 'host'
73
+ - 'packages/plugins/@lego/*'
74
+ ```
75
+
76
+ **Step 3: Create .npmrc**
77
+
78
+ Create `.npmrc`:
79
+
80
+ ```
81
+ shamefully-hoist=false
82
+ strict-peer-dependencies=false
83
+ ```
84
+
85
+ **Step 4: Create .gitignore**
86
+
87
+ Create `.gitignore`:
88
+
89
+ ```
90
+ # Dependencies
91
+ node_modules/
92
+ .pnp*
93
+
94
+ # Build outputs
95
+ dist/
96
+ build/
97
+ *.tsbuildinfo
98
+
99
+ # Environment
100
+ .env
101
+ .env.local
102
+ .env.production
103
+ .env.development
104
+ *.log
105
+
106
+ # IDE
107
+ .vscode/
108
+ .idea/
109
+ *.swp
110
+ *.swo
111
+ *~
112
+ .DS_Store
113
+
114
+ # Testing
115
+ coverage/
116
+ .nyc_output/
117
+ playwright-report/
118
+ test-results/
119
+
120
+ # PocketBase
121
+ pocketbase/pb_data/
122
+ pocketbase/pb_public/
123
+ pocketbase/pb_hooks/
124
+ *.pb
125
+
126
+ # Temporary
127
+ *.tmp
128
+ .cache/
129
+ ```
130
+
131
+ **Step 5: Verify setup**
132
+
133
+ Run:
134
+ ```bash
135
+ pnpm install
136
+ ```
137
+
138
+ Expected: No errors, `node_modules` created, `pnpm-lock.yaml` generated.
139
+
140
+ **Step 6: Commit**
141
+
142
+ ```bash
143
+ git add .
144
+ git commit -m "chore: initialize monorepo with pnpm workspaces"
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Task 2: Configure TypeScript
150
+
151
+ **Files:**
152
+ - Create: `tsconfig.json`
153
+ - Create: `tsconfig.base.json`
154
+
155
+ **Step 1: Create base TypeScript config**
156
+
157
+ Create `tsconfig.base.json`:
158
+
159
+ ```json
160
+ {
161
+ "compilerOptions": {
162
+ "target": "ES2020",
163
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
164
+ "module": "ESNext",
165
+ "moduleResolution": "bundler",
166
+ "resolveJsonModule": true,
167
+ "allowJs": true,
168
+ "strict": true,
169
+ "noEmit": true,
170
+ "esModuleInterop": true,
171
+ "skipLibCheck": true,
172
+ "forceConsistentCasingInFileNames": true,
173
+ "isolatedModules": true,
174
+ "jsx": "react-jsx",
175
+ "jsxImportSource": "react",
176
+ "allowImportingTsExtensions": true,
177
+ "noUnusedLocals": true,
178
+ "noUnusedParameters": true,
179
+ "noFallthroughCasesInSwitch": true,
180
+ "baseUrl": ".",
181
+ "paths": {
182
+ "@/*": ["./src/*"]
183
+ }
184
+ }
185
+ }
186
+ ```
187
+
188
+ **Step 2: Create root TypeScript config**
189
+
190
+ Create `tsconfig.json`:
191
+
192
+ ```json
193
+ {
194
+ "files": [],
195
+ "references": [
196
+ { "path": "./host" },
197
+ { "path": "./packages/plugins/@lego/plugin-dashboard" },
198
+ { "path": "./packages/plugins/@lego/plugin-todo" }
199
+ ]
200
+ }
201
+ ```
202
+
203
+ **Step 3: Commit**
204
+
205
+ ```bash
206
+ git add tsconfig.*
207
+ git commit -m "chore: add TypeScript configuration"
208
+ ```
209
+
210
+ ---
211
+
212
+ ## Task 3: Configure ESLint
213
+
214
+ **Files:**
215
+ - Create: `.eslintrc.js`
216
+ - Create: `.eslintignore`
217
+
218
+ **Step 1: Create ESLint config**
219
+
220
+ Create `.eslintrc.js`:
221
+
222
+ ```javascript
223
+ module.exports = {
224
+ root: true,
225
+ env: {
226
+ browser: true,
227
+ es2022: true,
228
+ node: true,
229
+ },
230
+ extends: [
231
+ 'eslint:recommended',
232
+ '@typescript-eslint/recommended',
233
+ 'prettier',
234
+ ],
235
+ parser: '@typescript-eslint/parser',
236
+ parserOptions: {
237
+ ecmaVersion: 'latest',
238
+ sourceType: 'module',
239
+ ecmaFeatures: {
240
+ jsx: true,
241
+ },
242
+ },
243
+ plugins: ['@typescript-eslint'],
244
+ rules: {
245
+ '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
246
+ '@typescript-eslint/no-explicit-any': 'warn',
247
+ 'no-console': ['warn', { allow: ['warn', 'error'] }],
248
+ },
249
+ ignorePatterns: ['dist', 'node_modules', '*.config.js'],
250
+ };
251
+ ```
252
+
253
+ **Step 2: Create .eslintignore**
254
+
255
+ Create `.eslintignore`:
256
+
257
+ ```
258
+ dist
259
+ node_modules
260
+ *.config.js
261
+ coverage
262
+ playwright-report
263
+ ```
264
+
265
+ **Step 3: Add lint script to each workspace** (will be done when creating host/plugins)
266
+
267
+ **Step 4: Commit**
268
+
269
+ ```bash
270
+ git add .eslintrc* .eslintignore
271
+ git commit -m "chore: add ESLint configuration"
272
+ ```
273
+
274
+ ---
275
+
276
+ ## Task 4: Configure Prettier
277
+
278
+ **Files:**
279
+ - Create: `.prettierrc`
280
+ - Create: `.prettierignore`
281
+
282
+ **Step 1: Create Prettier config**
283
+
284
+ Create `.prettierrc`:
285
+
286
+ ```json
287
+ {
288
+ "semi": true,
289
+ "trailingComma": "es5",
290
+ "singleQuote": true,
291
+ "printWidth": 100,
292
+ "tabWidth": 2,
293
+ "useTabs": false,
294
+ "arrowParens": "always",
295
+ "endOfLine": "lf",
296
+ "plugins": ["prettier-plugin-tailwindcss"]
297
+ }
298
+ ```
299
+
300
+ **Step 2: Create .prettierignore**
301
+
302
+ Create `.prettierignore`:
303
+
304
+ ```
305
+ dist
306
+ node_modules
307
+ pnpm-lock.yaml
308
+ package-lock.json
309
+ coverage
310
+ playwright-report
311
+ ```
312
+
313
+ **Step 3: Commit**
314
+
315
+ ```bash
316
+ git add .prettierrc*
317
+ git commit -m "chore: add Prettier configuration"
318
+ ```
319
+
320
+ ---
321
+
322
+ ## Task 5: Create Root Scripts Directory
323
+
324
+ **Files:**
325
+ - Create: `scripts/create-plugin.js`
326
+
327
+ **Step 1: Create plugin scaffolding script**
328
+
329
+ Create `scripts/create-plugin.js`:
330
+
331
+ ```javascript
332
+ #!/usr/bin/env node
333
+
334
+ const fs = require('fs');
335
+ const path = require('path');
336
+
337
+ const args = process.argv.slice(2);
338
+
339
+ if (args.length === 0) {
340
+ console.error('Usage: node scripts/create-plugin.js <plugin-name>');
341
+ process.exit(1);
342
+ }
343
+
344
+ const pluginName = args[0].startsWith('plugin-')
345
+ ? args[0]
346
+ : `plugin-${args[0]}`;
347
+ const pluginPascal = pluginName
348
+ .split('-')
349
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
350
+ .join('');
351
+
352
+ const pluginDir = path.join(process.cwd(), 'packages/plugins/@lego', pluginName);
353
+
354
+ // Create plugin directory
355
+ fs.mkdirSync(pluginDir, { recursive: true });
356
+ fs.mkdirSync(path.join(pluginDir, 'src'));
357
+ fs.mkdirSync(path.join(pluginDir, 'src/pages'));
358
+ fs.mkdirSync(path.join(pluginDir, 'src/components'));
359
+ fs.mkdirSync(path.join(pluginDir, 'src/hooks'));
360
+ fs.mkdirSync(path.join(pluginDir, 'src/lib'));
361
+
362
+ // Create package.json
363
+ const packageJson = {
364
+ name: `@lego/${pluginName}`,
365
+ version: '1.0.0',
366
+ private: true,
367
+ type: 'module',
368
+ exports: {
369
+ '.': './src/main.tsx',
370
+ './plugin.config': './plugin.config.ts',
371
+ },
372
+ scripts: {
373
+ dev: 'modern dev',
374
+ build: 'modern build',
375
+ preview: 'modern preview',
376
+ lint: 'eslint src',
377
+ typecheck: 'tsc --noEmit',
378
+ },
379
+ dependencies: {
380
+ '@modern-js/runtime': '^2.0.0',
381
+ 'react': '^18.3.0',
382
+ 'react-dom': '^18.3.0',
383
+ },
384
+ devDependencies: {
385
+ '@modern-js/app-tools': '^2.0.0',
386
+ '@modern-js/plugin-garfish': '^2.0.0',
387
+ '@types/react': '^18.3.0',
388
+ '@types/react-dom': '^18.3.0',
389
+ typescript: '^5.3.0',
390
+ },
391
+ };
392
+
393
+ fs.writeFileSync(
394
+ path.join(pluginDir, 'package.json'),
395
+ JSON.stringify(packageJson, null, 2)
396
+ );
397
+
398
+ // Create plugin.config.ts
399
+ const pluginConfig = `import { definePluginConfig } from '@lego/kernel/plugin-config';
400
+
401
+ export default definePluginConfig({
402
+ name: '@lego/${pluginName}',
403
+ version: '1.0.0',
404
+ displayName: '${pluginPascal}',
405
+ description: 'A plugin for ${pluginName}',
406
+
407
+ slots: {
408
+ 'sidebar:nav': {
409
+ component: './src/components/SidebarLink',
410
+ order: 100,
411
+ },
412
+ },
413
+ });
414
+ `;
415
+
416
+ fs.writeFileSync(path.join(pluginDir, 'plugin.config.ts'), pluginConfig);
417
+
418
+ // Create modern.config.ts
419
+ const modernConfig = `import { appTools, defineConfig } from '@modern-js/app-tools';
420
+ import { garfishPlugin } from '@modern-js/plugin-garfish';
421
+
422
+ // Get next available port starting from 3001
423
+ const basePort = 3001 + parseInt(process.env.PLUGIN_INDEX || '0');
424
+
425
+ export default defineConfig({
426
+ dev: {
427
+ port: basePort,
428
+ },
429
+ runtime: {
430
+ router: true,
431
+ },
432
+ deploy: {
433
+ microFrontend: true,
434
+ },
435
+ plugins: [appTools(), garfishPlugin()],
436
+ source: {
437
+ alias: {
438
+ '@': './src',
439
+ },
440
+ },
441
+ });
442
+ `;
443
+
444
+ fs.writeFileSync(path.join(pluginDir, 'modern.config.ts'), modernConfig);
445
+
446
+ // Create tsconfig.json
447
+ const tsconfig = {
448
+ extends: '../../tsconfig.base.json',
449
+ compilerOptions: {
450
+ composite: true,
451
+ outDir: './dist',
452
+ rootDir: './src',
453
+ },
454
+ include: ['src'],
455
+ };
456
+
457
+ fs.writeFileSync(path.join(pluginDir, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2));
458
+
459
+ // Create main App.tsx
460
+ const appTsx = `import { BrowserRouter, Routes, Route } from '@modern-js/runtime/router';
461
+
462
+ interface PluginAppProps {
463
+ basename?: string;
464
+ }
465
+
466
+ export default function PluginApp({ basename }: PluginAppProps) {
467
+ const routerBasename = basename || '/';
468
+
469
+ return (
470
+ <BrowserRouter basename={routerBasename}>
471
+ <Routes>
472
+ <Route index element={<div>TODO: Implement ${pluginPascal}</div>} />
473
+ </Routes>
474
+ </BrowserRouter>
475
+ );
476
+ }
477
+ `;
478
+
479
+ fs.writeFileSync(path.join(pluginDir, 'src/App.tsx'), appTsx);
480
+
481
+ // Create main.tsx entry point
482
+ const mainTsx = `import React from 'react';
483
+ import ReactDOM from 'react-dom/client';
484
+ import App from './App';
485
+
486
+ ReactDOM.createRoot(document.getElementById('root')!).render(
487
+ <React.StrictMode>
488
+ <App />
489
+ </React.StrictMode>
490
+ );
491
+ `;
492
+
493
+ fs.writeFileSync(path.join(pluginDir, 'src/main.tsx'), mainTsx);
494
+
495
+ // Create basic SidebarLink component
496
+ const sidebarLink = `import { Link } from '@modern-js/runtime/router';
497
+
498
+ export function SidebarLink() {
499
+ return (
500
+ <Link
501
+ to="/${pluginName.replace('plugin-', '')}"
502
+ className="flex items-center gap-2 px-3 py-2 text-sm rounded-md hover:bg-accent hover:text-accent-foreground"
503
+ >
504
+ <span>${pluginPascal}</span>
505
+ </Link>
506
+ );
507
+ }
508
+ `;
509
+
510
+ fs.writeFileSync(path.join(pluginDir, 'src/components/SidebarLink.tsx'), sidebarLink);
511
+
512
+ // Create HTML template
513
+ const html = `<!DOCTYPE html>
514
+ <html lang="en">
515
+ <head>
516
+ <meta charset="UTF-8" />
517
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
518
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
519
+ <title>${pluginPascal}</title>
520
+ </head>
521
+ <body>
522
+ <div id="root"></div>
523
+ <script type="module" src="/src/main.tsx"></script>
524
+ </body>
525
+ </html>
526
+ `;
527
+
528
+ fs.writeFileSync(path.join(pluginDir, 'src/index.html'), html);
529
+
530
+ console.log(`โœ… Plugin created: packages/plugins/@lego/${pluginName}`);
531
+ console.log(``);
532
+ console.log(`Next steps:`);
533
+ console.log(` 1. cd packages/plugins/@lego/${pluginName}`);
534
+ console.log(` 2. pnpm install`);
535
+ console.log(` 3. pnpm run dev`);
536
+ `;
537
+
538
+ // Update root tsconfig.json to include new plugin
539
+ const rootTsconfig = JSON.parse(fs.readFileSync('tsconfig.json', 'utf8'));
540
+ rootTsconfig.references.push({
541
+ path: `./packages/plugins/@lego/${pluginName}`,
542
+ });
543
+ fs.writeFileSync('tsconfig.json', JSON.stringify(rootTsconfig, null, 2));
544
+
545
+ // Update pnpm-workspace.yaml
546
+ const workspaceContent = fs.readFileSync('pnpm-workspace.yaml', 'utf8');
547
+ if (!workspaceContent.includes(pluginName)) {
548
+ const newWorkspace = workspaceContent.replace(
549
+ /(packages:\/\s*@lego\/\*)/,
550
+ `$1\n - '${pluginName}'`
551
+ );
552
+ fs.writeFileSync('pnpm-workspace.yaml', newWorkspace);
553
+ }
554
+ `;
555
+
556
+ **Step 2: Make script executable**
557
+
558
+ ```bash
559
+ chmod +x scripts/create-plugin.js
560
+ ```
561
+
562
+ **Step 3: Commit**
563
+
564
+ ```bash
565
+ git add scripts/
566
+ git commit -m "chore: add plugin scaffolding CLI script"
567
+ ```
568
+
569
+ ---
570
+
571
+ ## Task 6: Create Environment Configuration Structure
572
+
573
+ **Files:**
574
+ - Create: `.env.development`
575
+ - Create: `.env.production`
576
+ - Create: `.env.example`
577
+ - Create: `src/env/env.schema.ts`
578
+
579
+ **Step 1: Create development environment**
580
+
581
+ Create `.env.development`:
582
+
583
+ ```bash
584
+ # App
585
+ VITE_APP_NAME=Lego-One
586
+ VITE_APP_URL=http://localhost:8080
587
+
588
+ # PocketBase
589
+ VITE_POCKETBASE_URL=http://localhost:8090
590
+ VITE_POCKETBASE_ADMIN_EMAIL=admin@lego-one.dev
591
+ VITE_POCKETBASE_ADMIN_PASSWORD=admin123456
592
+
593
+ # Seed Admin (for development)
594
+ VITE_SEED_ADMIN_EMAIL=admin@lego-one.dev
595
+ VITE_SEED_ADMIN_PASSWORD=admin123456
596
+ VITE_SEED_ADMIN_NAME=Super Admin
597
+ VITE_SEED_ORG_NAME=Demo Organization
598
+
599
+ # Plugin Ports
600
+ VITE_DEV_HOST_PORT=8080
601
+ VITE_DEV_DASHBOARD_PORT=3001
602
+ VITE_DEV_TODO_PORT=3002
603
+ ```
604
+
605
+ **Step 2: Create production environment**
606
+
607
+ Create `.env.production`:
608
+
609
+ ```bash
610
+ # App
611
+ VITE_APP_NAME=Lego-One
612
+ VITE_APP_URL=https://your-domain.com
613
+
614
+ # PocketBase (configure for production)
615
+ VITE_POCKETBASE_URL=https://your-pocketbase-url.com
616
+ VITE_POCKETBASE_ADMIN_EMAIL=
617
+ VITE_POCKETBASE_ADMIN_PASSWORD=
618
+
619
+ # No seed admin in production
620
+ ```
621
+
622
+ **Step 3: Create environment example**
623
+
624
+ Create `.env.example`:
625
+
626
+ ```bash
627
+ # Copy this file to .env.development or .env.production
628
+
629
+ # App Configuration
630
+ VITE_APP_NAME=Lego-One
631
+ VITE_APP_URL=http://localhost:8080
632
+
633
+ # PocketBase Configuration
634
+ VITE_POCKETBASE_URL=http://localhost:8090
635
+ VITE_POCKETBASE_ADMIN_EMAIL=admin@example.com
636
+ VITE_POCKETBASE_ADMIN_PASSWORD=change-me
637
+
638
+ # Seed Admin (development only)
639
+ VITE_SEED_ADMIN_EMAIL=admin@lego-one.dev
640
+ VITE_SEED_ADMIN_PASSWORD=admin123456
641
+ VITE_SEED_ADMIN_NAME=Super Admin
642
+ VITE_SEED_ORG_NAME=Demo Organization
643
+
644
+ # Plugin Development Ports
645
+ VITE_DEV_HOST_PORT=8080
646
+ VITE_DEV_DASHBOARD_PORT=3001
647
+ VITE_DEV_TODO_PORT=3002
648
+ ```
649
+
650
+ **Step 4: Create zod validation schema**
651
+
652
+ Create `src/env/env.schema.ts`:
653
+
654
+ ```typescript
655
+ import { z } from 'zod';
656
+
657
+ const envSchema = z.object({
658
+ // App
659
+ VITE_APP_NAME: z.string().default('Lego-One'),
660
+ VITE_APP_URL: z.string().url(),
661
+
662
+ // PocketBase
663
+ VITE_POCKETBASE_URL: z.string().url(),
664
+ VITE_POCKETBASE_ADMIN_EMAIL: z.string().email(),
665
+ VITE_POCKETBASE_ADMIN_PASSWORD: z.string().min(8),
666
+
667
+ // Seed Admin (development only)
668
+ VITE_SEED_ADMIN_EMAIL: z.string().email().optional(),
669
+ VITE_SEED_ADMIN_PASSWORD: z.string().min(8).optional(),
670
+ VITE_SEED_ADMIN_NAME: z.string().optional(),
671
+ VITE_SEED_ORG_NAME: z.string().optional(),
672
+
673
+ // Plugin Ports
674
+ VITE_DEV_HOST_PORT: z.string().transform(Number).default(8080),
675
+ VITE_DEV_DASHBOARD_PORT: z.string().transform(Number).default(3001),
676
+ VITE_DEV_TODO_PORT: z.string().transform(Number).default(3002),
677
+ });
678
+
679
+ export type Env = z.infer<typeof envSchema>;
680
+
681
+ export function validateEnv(): Env {
682
+ const env = {
683
+ VITE_APP_NAME: import.meta.env.VITE_APP_NAME,
684
+ VITE_APP_URL: import.meta.env.VITE_APP_URL,
685
+ VITE_POCKETBASE_URL: import.meta.env.VITE_POCKETBASE_URL,
686
+ VITE_POCKETBASE_ADMIN_EMAIL: import.meta.env.VITE_POCKETBASE_ADMIN_EMAIL,
687
+ VITE_POCKETBASE_ADMIN_PASSWORD: import.meta.env.VITE_POCKETBASE_ADMIN_PASSWORD,
688
+ VITE_SEED_ADMIN_EMAIL: import.meta.env.VITE_SEED_ADMIN_EMAIL,
689
+ VITE_SEED_ADMIN_PASSWORD: import.meta.env.VITE_SEED_ADMIN_PASSWORD,
690
+ VITE_SEED_ADMIN_NAME: import.meta.env.VITE_SEED_ADMIN_NAME,
691
+ VITE_SEED_ORG_NAME: import.meta.env.VITE_SEED_ORG_NAME,
692
+ VITE_DEV_HOST_PORT: import.meta.env.VITE_DEV_HOST_PORT,
693
+ VITE_DEV_DASHBOARD_PORT: import.meta.env.VITE_DEV_DASHBOARD_PORT,
694
+ VITE_DEV_TODO_PORT: import.meta.env.VITE_DEV_TODO_PORT,
695
+ };
696
+
697
+ const result = envSchema.safeParse(env);
698
+
699
+ if (!result.success) {
700
+ const errors = result.error.flatten().fieldErrors;
701
+ console.error('โŒ Invalid environment variables:');
702
+ for (const [field, error] of Object.entries(errors)) {
703
+ console.error(` ${field}: ${error?.join(', ')}`);
704
+ }
705
+ throw new Error('Environment validation failed');
706
+ }
707
+
708
+ return result.data;
709
+ }
710
+
711
+ export const env = validateEnv();
712
+ ```
713
+
714
+ **Step 5: Commit**
715
+
716
+ ```bash
717
+ git add .env* src/env/
718
+ git commit -m "chore: add environment configuration with zod validation"
719
+ ```
720
+
721
+ ---
722
+
723
+ ## Task 7: Create README
724
+
725
+ **Files:**
726
+ - Create: `README.md`
727
+
728
+ **Step 1: Create README**
729
+
730
+ Create `README.md`:
731
+
732
+ ```markdown
733
+ # Lego-One
734
+
735
+ > **Microkernel SaaS OS** - A modular boilerplate for building SaaS applications with Modern.js, Garfish, and PocketBase.
736
+
737
+ ## Features
738
+
739
+ - ๐Ÿ—๏ธ **Microkernel Architecture** - Host (Kernel) + Plugins (Features)
740
+ - ๐Ÿ” **Multi-Tenancy** - Multiple organizations with RBAC
741
+ - ๐Ÿ”Œ **Plugin System** - Enable/disable plugins via config or UI
742
+ - ๐ŸŽจ **Modern UI** - Tailwind CSS + Shadcn components
743
+ - โšก **Performance** - Rspack bundler, code-splitting, lazy loading
744
+ - ๐Ÿงช **Tested** - Vitest + Playwright
745
+ - ๐Ÿ”’ **Type-Safe** - TypeScript strict mode
746
+
747
+ ## Quick Start
748
+
749
+ ### Prerequisites
750
+
751
+ - Node.js >= 18.0.0
752
+ - pnpm >= 8.0.0
753
+
754
+ ### Installation
755
+
756
+ ```bash
757
+ # Install dependencies
758
+ pnpm install
759
+
760
+ # Start development (host + all plugins)
761
+ pnpm run dev:all
762
+
763
+ # Or start individually
764
+ pnpm run dev:host # :8080
765
+ pnpm run dev:plugins # All plugins
766
+ ```
767
+
768
+ ### First Run
769
+
770
+ 1. PocketBase will auto-initialize with seed admin
771
+ 2. Login with: `admin@lego-one.dev` / `admin123456`
772
+ 3. Explore the Dashboard and Todo plugins
773
+
774
+ ## Project Structure
775
+
776
+ ```
777
+ lego-one/
778
+ โ”œโ”€โ”€ host/ # Kernel application
779
+ โ”œโ”€โ”€ packages/
780
+ โ”‚ โ””โ”€โ”€ plugins/
781
+ โ”‚ โ””โ”€โ”€ @lego/
782
+ โ”‚ โ”œโ”€โ”€ plugin-dashboard
783
+ โ”‚ โ””โ”€โ”€ plugin-todo
784
+ โ”œโ”€โ”€ docs/
785
+ โ”‚ โ”œโ”€โ”€ research/ # Architecture research
786
+ โ”‚ โ”œโ”€โ”€ plans/ # Implementation plans
787
+ โ”‚ โ””โ”€โ”€ setup/ # User guides
788
+ โ””โ”€โ”€ pocketbase/ # Backend data
789
+ ```
790
+
791
+ ## Documentation
792
+
793
+ - [Implementation Plans](./docs/plans/00-index.md) - Complete implementation guide
794
+ - [Setup Guides](./docs/setup/) - How to create plugins, configure, etc.
795
+ - [Research](./docs/research/) - Architecture research documents
796
+
797
+ ## License
798
+
799
+ MIT
800
+ ```
801
+
802
+ **Step 2: Commit**
803
+
804
+ ```bash
805
+ git add README.md
806
+ git commit -m "docs: add project README"
807
+ ```
808
+
809
+ ---
810
+
811
+ ## Verification
812
+
813
+ After completing all tasks:
814
+
815
+ **Step 1: Verify file structure**
816
+
817
+ Run:
818
+ ```bash
819
+ ls -la
820
+ ```
821
+
822
+ Expected: `package.json`, `pnpm-workspace.yaml`, `.npmrc`, `.gitignore`, `tsconfig*`, `.eslintrc*`, `.prettierrc*`, `.env*`, `scripts/`, `src/env/`, `README.md`
823
+
824
+ **Step 2: Verify dependencies install**
825
+
826
+ Run:
827
+ ```bash
828
+ pnpm install
829
+ ```
830
+
831
+ Expected: No errors, `node_modules` created.
832
+
833
+ **Step 3: Verify TypeScript**
834
+
835
+ Run:
836
+ ```bash
837
+ pnpm typecheck
838
+ ```
839
+
840
+ Expected: No errors (some "cannot find module" is OK since we haven't created workspaces yet).
841
+
842
+ ---
843
+
844
+ ## Summary
845
+
846
+ After completing this document, you have:
847
+
848
+ โœ… Monorepo structure with pnpm workspaces
849
+ โœ… TypeScript configuration (root + base)
850
+ โœ… ESLint + Prettier configured
851
+ โœ… Environment variables with zod validation
852
+ โœ… Plugin scaffolding CLI script
853
+ โœ… README documentation
854
+
855
+ **Next:** โ†’ [`02-pocketbase-setup.md`](./02-pocketbase-setup.md)