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,582 @@
1
+ # Plugin Development
2
+
3
+ **Complete Guide to Creating Lego-One Plugins**
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ Lego-One plugins are Modern.js micro-frontends that integrate seamlessly with the host application. This guide provides complete instructions for creating plugins.
10
+
11
+ ---
12
+
13
+ ## Plugin Structure
14
+
15
+ ### Standard Plugin File Structure
16
+
17
+ ```
18
+ packages/plugins/@lego/plugin-<name>/
19
+ ├── package.json # Package configuration
20
+ ├── tsconfig.json # TypeScript configuration
21
+ ├── modern.config.ts # Modern.js configuration
22
+ ├── tailwind.config.ts # Tailwind CSS configuration
23
+ ├── postcss.config.mjs # PostCSS configuration
24
+ └── src/
25
+ ├── global.css # Global styles
26
+ ├── plugin.config.ts # Plugin manifest and configuration
27
+ ├── plugin.ts # Plugin exports for Garfish
28
+ ├── App.tsx # Root component with routing
29
+ ├── types.ts # TypeScript types
30
+ ├── schemas.ts # Zod validation schemas
31
+ ├── pages/ # Route pages
32
+ │ └── <Plugin>Page.tsx
33
+ ├── components/ # React components
34
+ │ └── slots/ # Slot injection components
35
+ │ └── SidebarWidget.tsx
36
+ ├── hooks/ # Custom React hooks
37
+ │ ├── usePocketBase.ts
38
+ │ └── use<Feature>Data.ts
39
+ └── vite-env.d.ts # Vite type declarations
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Step-by-Step Plugin Creation
45
+
46
+ ### Step 1: Create Plugin Directory
47
+
48
+ ```bash
49
+ mkdir -p packages/plugins/@lego/plugin-my-plugin
50
+ cd packages/plugins/@lego/plugin-my-plugin
51
+ ```
52
+
53
+ ### Step 2: Create package.json
54
+
55
+ ```json
56
+ {
57
+ "name": "@lego/plugin-my-plugin",
58
+ "version": "1.0.0",
59
+ "private": true,
60
+ "type": "module",
61
+ "scripts": {
62
+ "dev": "modern dev",
63
+ "build": "modern build",
64
+ "start": "modern start"
65
+ },
66
+ "dependencies": {
67
+ "@garfish/hooks": "^1.22.0",
68
+ "@modern-js/runtime": "^2.60.0",
69
+ "@modern-js/runtime/garfish": "^2.60.0",
70
+ "@tanstack/react-query": "^5.59.0",
71
+ "lucide-react": "^0.454.0",
72
+ "pocketbase": "^0.21.5",
73
+ "react": "^18.3.1",
74
+ "react-dom": "^18.3.1",
75
+ "zod": "^3.23.8"
76
+ },
77
+ "devDependencies": {
78
+ "@modern-js/app-tools": "^2.60.0",
79
+ "@modern-js/plugin-garfish": "^2.60.0",
80
+ "tailwindcss": "^3.4.0",
81
+ "typescript": "^5.3.0"
82
+ }
83
+ }
84
+ ```
85
+
86
+ ### Step 3: Create modern.config.ts
87
+
88
+ ```typescript
89
+ import { appTools, defineConfig } from '@modern-js/app-tools';
90
+ import { garfishPlugin } from '@modern-js/plugin-garfish';
91
+
92
+ export default defineConfig({
93
+ dev: {
94
+ port: 3003, // Unique port for each plugin
95
+ },
96
+ runtime: {
97
+ router: true,
98
+ state: true,
99
+ },
100
+ deploy: {
101
+ microFrontend: true,
102
+ },
103
+ plugins: [appTools(), garfishPlugin()],
104
+ });
105
+ ```
106
+
107
+ ### Step 4: Create types.ts
108
+
109
+ ```typescript
110
+ export interface MyEntity {
111
+ id: string;
112
+ name: string;
113
+ description?: string;
114
+ organizationId: string;
115
+ ownerId: string;
116
+ created: string;
117
+ updated: string;
118
+ }
119
+
120
+ export interface MyEntityFormData {
121
+ name: string;
122
+ description?: string;
123
+ }
124
+ ```
125
+
126
+ ### Step 5: Create schemas.ts
127
+
128
+ ```typescript
129
+ import { z } from 'zod';
130
+
131
+ export const myEntityFormSchema = z.object({
132
+ name: z.string().min(1, 'Name is required').max(200, 'Name too long'),
133
+ description: z.string().max(1000).optional(),
134
+ });
135
+ ```
136
+
137
+ ### Step 6: Create hooks/usePocketBase.ts
138
+
139
+ ```typescript
140
+ import { useEffect, useState } from 'react';
141
+
142
+ export function usePocketBase() {
143
+ const [pb, setPb] = useState(null);
144
+
145
+ useEffect(() => {
146
+ const kernelState = window.__LEGO_KERNEL_STATE__;
147
+ const pbUrl = import.meta.env.VITE_POCKETBASE_URL || 'http://127.0.0.1:8090';
148
+ const PocketBase = require('pocketbase').default;
149
+ const client = new PocketBase(pbUrl);
150
+
151
+ const state = kernelState?.useGlobalKernelState?.getState();
152
+ if (state?.token) {
153
+ client.authStore.save(state.token);
154
+ }
155
+
156
+ setPb(client);
157
+ }, []);
158
+
159
+ return pb;
160
+ }
161
+ ```
162
+
163
+ ### Step 7: Create hooks/useMyEntities.ts
164
+
165
+ ```typescript
166
+ import { useQuery } from '@tanstack/react-query';
167
+ import { usePocketBase } from './usePocketBase';
168
+
169
+ export function useMyEntities() {
170
+ const pb = usePocketBase();
171
+
172
+ return useQuery({
173
+ queryKey: ['my-entities'],
174
+ queryFn: async () => {
175
+ if (!pb) throw new Error('PB not initialized');
176
+
177
+ const kernelState = window.__LEGO_KERNEL_STATE__;
178
+ const state = kernelState?.useGlobalKernelState?.getState();
179
+ const orgId = state?.organization?.id;
180
+
181
+ const result = await pb.collection('my_entities').getList(1, 50, {
182
+ filter: `organizationId = "${orgId}"`,
183
+ sort: '-created',
184
+ });
185
+
186
+ return result.items;
187
+ },
188
+ enabled: !!pb,
189
+ });
190
+ }
191
+ ```
192
+
193
+ ### Step 8: Create plugin.config.ts
194
+
195
+ ```typescript
196
+ import type { PluginConfig } from '@lego/kernel/plugins';
197
+ import { SidebarWidget } from './components/slots/SidebarWidget';
198
+
199
+ export const pluginConfig: PluginConfig = {
200
+ manifest: {
201
+ name: '@lego/plugin-my-plugin',
202
+ version: '1.0.0',
203
+ displayName: 'My Plugin',
204
+ description: 'Description of what this plugin does',
205
+ permissions: ['myplugin.read', 'myplugin.write'],
206
+ },
207
+ enabled: true,
208
+ slots: [
209
+ {
210
+ slot: 'sidebar:nav',
211
+ component: () => import('./components/slots/SidebarWidget').then(m => m.default),
212
+ order: 100,
213
+ },
214
+ ],
215
+ routes: [
216
+ {
217
+ path: '/my-plugin',
218
+ component: () => import('./pages/MyPluginPage').then(m => m.default),
219
+ protected: true,
220
+ permissions: ['myplugin.read'],
221
+ },
222
+ ],
223
+ };
224
+ ```
225
+
226
+ ### Step 9: Create plugin.ts
227
+
228
+ ```typescript
229
+ import { pluginConfig } from './plugin.config';
230
+ import App from './App';
231
+
232
+ export default {
233
+ config: pluginConfig,
234
+ App,
235
+ };
236
+ ```
237
+
238
+ ### Step 10: Create App.tsx
239
+
240
+ ```typescript
241
+ import { Route, Routes } from '@modern-js/runtime/router';
242
+ import { MyPluginPage } from './pages/MyPluginPage';
243
+
244
+ export function App() {
245
+ return (
246
+ <Routes>
247
+ <Route path="/my-plugin" element={<MyPluginPage />} />
248
+ </Routes>
249
+ );
250
+ }
251
+
252
+ export default App;
253
+ ```
254
+
255
+ ### Step 11: Create components/slots/SidebarWidget.tsx
256
+
257
+ ```typescript
258
+ import { NavLink } from '@modern-js/runtime/router';
259
+ import { MyIcon } from 'lucide-react';
260
+
261
+ export function SidebarWidget() {
262
+ return (
263
+ <NavLink
264
+ to="/my-plugin"
265
+ className={({ isActive }) =>
266
+ `flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors ${
267
+ isActive
268
+ ? 'bg-primary text-primary-foreground'
269
+ : 'text-muted-foreground hover:bg-muted hover:text-foreground'
270
+ }`
271
+ }
272
+ >
273
+ <MyIcon className="h-5 w-5" />
274
+ <span>My Plugin</span>
275
+ </NavLink>
276
+ );
277
+ }
278
+
279
+ export default SidebarWidget;
280
+ ```
281
+
282
+ ### Step 12: Create pages/MyPluginPage.tsx
283
+
284
+ ```typescript
285
+ import { useMyEntities } from '../hooks/useMyEntities';
286
+
287
+ export function MyPluginPage() {
288
+ const { data: entities, isLoading } = useMyEntities();
289
+
290
+ if (isLoading) {
291
+ return <div className="p-8">Loading...</div>;
292
+ }
293
+
294
+ return (
295
+ <div className="container mx-auto p-8">
296
+ <h1 className="text-3xl font-bold">My Plugin</h1>
297
+ <div className="mt-6 space-y-4">
298
+ {entities?.map((entity) => (
299
+ <div key={entity.id} className="rounded border p-4">
300
+ <h3 className="font-semibold">{entity.name}</h3>
301
+ <p className="text-muted-foreground">{entity.description}</p>
302
+ </div>
303
+ ))}
304
+ </div>
305
+ </div>
306
+ );
307
+ }
308
+
309
+ export default MyPluginPage;
310
+ ```
311
+
312
+ ### Step 13: Create global.css
313
+
314
+ ```css
315
+ @tailwind base;
316
+ @tailwind components;
317
+ @tailwind utilities;
318
+
319
+ @layer base {
320
+ :root {
321
+ --background: 0 0% 100%;
322
+ --foreground: 222.2 84% 4.9%;
323
+ /* ... more variables */
324
+ }
325
+ }
326
+ ```
327
+
328
+ ### Step 14: Create tailwind.config.ts
329
+
330
+ ```typescript
331
+ import type { Config } from 'tailwindcss';
332
+
333
+ export default {
334
+ darkMode: ['class'],
335
+ content: ['./src/**/*.{ts,tsx}'],
336
+ theme: {
337
+ extend: {
338
+ colors: {
339
+ border: 'hsl(var(--border))',
340
+ input: 'hsl(var(--input))',
341
+ ring: 'hsl(var(--ring))',
342
+ background: 'hsl(var(--background))',
343
+ foreground: 'hsl(var(--foreground))',
344
+ primary: {
345
+ DEFAULT: 'hsl(var(--primary))',
346
+ foreground: 'hsl(var(--primary-foreground))',
347
+ },
348
+ /* ... more colors */
349
+ },
350
+ },
351
+ },
352
+ plugins: [],
353
+ } satisfies Config;
354
+ ```
355
+
356
+ ### Step 15: Create postcss.config.mjs
357
+
358
+ ```javascript
359
+ export default {
360
+ plugins: {
361
+ tailwindcss: {},
362
+ autoprefixer: {},
363
+ },
364
+ };
365
+ ```
366
+
367
+ ### Step 16: Create tsconfig.json
368
+
369
+ ```json
370
+ {
371
+ "compilerOptions": {
372
+ "target": "ES2022",
373
+ "module": "ESNext",
374
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
375
+ "jsx": "react-jsx",
376
+ "moduleResolution": "bundler",
377
+ "resolveJsonModule": true,
378
+ "allowJs": true,
379
+ "strict": true,
380
+ "esModuleInterop": true,
381
+ "skipLibCheck": true,
382
+ "forceConsistentCasingInFileNames": true,
383
+ "isolatedModules": true,
384
+ "noEmit": true
385
+ },
386
+ "include": ["src/**/*"],
387
+ "exclude": ["node_modules", "dist"]
388
+ }
389
+ ```
390
+
391
+ ### Step 17: Create vite-env.d.ts
392
+
393
+ ```typescript
394
+ declare global {
395
+ interface Window {
396
+ __LEGO_KERNEL_STATE__?: {
397
+ user?: { id: string; email: string; name?: string } | null;
398
+ organization?: { id: string; name: string; slug: string } | null;
399
+ isAuthenticated: boolean;
400
+ useGlobalKernelState?: any;
401
+ };
402
+ __LEGO_CHANNEL_BUS__?: {
403
+ publish: (channel: string, message: any) => void;
404
+ subscribe: (channel: string, callback: (data: any) => void) => () => void;
405
+ };
406
+ }
407
+ }
408
+
409
+ export {};
410
+ ```
411
+
412
+ ---
413
+
414
+ ## Register Plugin with Host
415
+
416
+ ### Step 1: Update host/src/modern.runtime.ts
417
+
418
+ ```typescript
419
+ export default defineRuntimeConfig({
420
+ masterApp: {
421
+ apps: [
422
+ // ... existing apps
423
+ {
424
+ name: '@lego/plugin-my-plugin',
425
+ entry: isDev
426
+ ? 'http://localhost:3003'
427
+ : () => import('@lego/plugin-my-plugin'),
428
+ activeWhen: '/my-plugin',
429
+ },
430
+ ],
431
+ },
432
+ });
433
+ ```
434
+
435
+ ### Step 2: Update host/src/saas.config.ts
436
+
437
+ ```typescript
438
+ export const saasConfig = {
439
+ plugins: [
440
+ // ... existing plugins
441
+ { name: '@lego/plugin-my-plugin', enabled: true },
442
+ ],
443
+ };
444
+ ```
445
+
446
+ ---
447
+
448
+ ## Plugin Patterns
449
+
450
+ ### CRUD Pattern (Like Todo Plugin)
451
+
452
+ 1. **Types** → Define data interfaces
453
+ 2. **Schemas** → Zod validation
454
+ 3. **Hooks** → usePocketBase, useItems, useCreate, useUpdate, useDelete
455
+ 4. **Components** → List, Item, Form, Dialog
456
+ 5. **Pages** → Main page with filters
457
+
458
+ ### Display Pattern (Like Dashboard Plugin)
459
+
460
+ 1. **Hooks** → Stats queries, activity feed
461
+ 2. **Components** → Stat cards, activity feed, quick actions
462
+ 3. **Pages** → Dashboard overview
463
+
464
+ ### Calculation Pattern
465
+
466
+ 1. **Types** → Input/Output types
467
+ 2. **Hooks** → Pure calculation functions
468
+ 3. **Components** → Input form, result display
469
+ 4. **Pages** → Calculator page
470
+
471
+ ---
472
+
473
+ ## Multi-Tenancy for Plugins
474
+
475
+ ### Data Isolation
476
+
477
+ All plugin data MUST be scoped to organization:
478
+
479
+ ```typescript
480
+ const result = await pb.collection('my_entities').getList(1, 50, {
481
+ filter: `organizationId = "${orgId}"`,
482
+ });
483
+ ```
484
+
485
+ ### PocketBase Collection Pattern
486
+
487
+ ```javascript
488
+ {
489
+ name: 'my_entities',
490
+ type: 'base',
491
+ fields: [
492
+ // Multi-tenancy required fields
493
+ { name: 'organizationId', type: 'relation', required: true, options: {
494
+ collectionId: 'organizations',
495
+ displayFields: ['name']
496
+ }},
497
+ { name: 'ownerId', type: 'relation', required: true, options: {
498
+ collectionId: 'users',
499
+ displayFields: ['name', 'email']
500
+ }},
501
+ // Your fields here
502
+ { name: 'name', type: 'text', required: true },
503
+ { name: 'description', type: 'text' },
504
+ ],
505
+ // Multi-tenancy API rules
506
+ listRule: '@request.auth.id != "" && organizationId = @request.auth.membership.organizations',
507
+ viewRule: '@request.auth.id != "" && organizationId = @request.auth.membership.organizations',
508
+ createRule: '@request.auth.id != "" && organizationId = @request.auth.membership.organizations',
509
+ updateRule: '@request.auth.id != "" && organizationId = @request.auth.membership.organizations && ownerId = @request.auth.id',
510
+ deleteRule: '@request.auth.id != "" && organizationId = @request.auth.membership.organizations && ownerId = @request.auth.id',
511
+ }
512
+ ```
513
+
514
+ ---
515
+
516
+ ## Testing Your Plugin
517
+
518
+ ### Local Development
519
+
520
+ 1. **Start plugin dev server:**
521
+ ```bash
522
+ cd packages/plugins/@lego/plugin-my-plugin
523
+ pnpm run dev
524
+ ```
525
+
526
+ 2. **Start host:**
527
+ ```bash
528
+ cd host
529
+ pnpm run dev
530
+ ```
531
+
532
+ 3. **Navigate to:** http://localhost:8080
533
+
534
+ 4. **Plugin should appear** in sidebar navigation
535
+
536
+ ### Production Build Test
537
+
538
+ ```bash
539
+ # Build all
540
+ pnpm run build
541
+
542
+ # Start production server
543
+ cd host && pnpm run start
544
+
545
+ # Navigate to http://localhost:8080
546
+ # Plugin should still work
547
+ ```
548
+
549
+ ---
550
+
551
+ ## Common Issues
552
+
553
+ ### Plugin Not Loading
554
+
555
+ **Checklist:**
556
+ - [ ] Plugin enabled in `saas.config.ts`
557
+ - [ ] Plugin registered in `modern.runtime.ts`
558
+ - [ ] Plugin dev server running (dev mode)
559
+ - [ ] Correct `activeWhen` path
560
+ - [ ] No console errors
561
+
562
+ ### Window Bridge Undefined
563
+
564
+ **Solution:** Add type definitions in `vite-env.d.ts`
565
+
566
+ ### Styles Not Loading
567
+
568
+ **Solutions:**
569
+ - [ ] `global.css` imported in `App.tsx`
570
+ - [ ] Tailwind content paths correct
571
+ - [ ] PostCSS config present
572
+
573
+ ### Route Not Working
574
+
575
+ **Solutions:**
576
+ - [ ] Route defined in `plugin.config.ts`
577
+ - [ ] Component export matches
578
+ - [ ] Path doesn't conflict with existing routes
579
+
580
+ ---
581
+
582
+ **Next:** Read [`08-component-library.md`](./08-component-library.md) for UI components reference.