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,1374 @@
1
+ # PocketBase Setup
2
+
3
+ > **For AI:** Complete all tasks in order. This sets up the entire backend with multitenancy, RBAC, and seed data.
4
+
5
+ **Goal:** Install PocketBase, create all collections with API rules for multi-tenancy, implement migration system, and add seed data.
6
+
7
+ **Architecture:** PocketBase as backend with proper API rules ensuring each organization's data is isolated. Collections: users, organizations, roles, permissions, user_roles, audit_logs, todos.
8
+
9
+ **Tech Stack:** PocketBase v0.22+, JavaScript migrations, admin API for programmatic collection creation
10
+
11
+ ---
12
+
13
+ ## Task 1: Download and Setup PocketBase
14
+
15
+ **Files:**
16
+ - Create: `pocketbase/`
17
+ - Download: PocketBase binary
18
+
19
+ **Step 1: Create pocketbase directory and download binary**
20
+
21
+ ```bash
22
+ # Create directory
23
+ mkdir -p pocketbase
24
+ cd pocketbase
25
+
26
+ # Download PocketBase v0.22.0 for your platform
27
+ # Linux (adjust URL for Mac/Windows if needed)
28
+ wget https://github.com/pocketbase/pocketbase/releases/download/v0.22.0/pocketbase_0.22.0_linux_amd64.zip
29
+
30
+ # Extract
31
+ unzip pocketbase_0.22.0_linux_amd64.zip
32
+
33
+ # Make executable
34
+ chmod +x pocketbase
35
+
36
+ # Verify
37
+ ./pocketbase --version
38
+ ```
39
+
40
+ Expected: Output shows version 0.22.0
41
+
42
+ **Step 2: Create .gitignore for pocketbase**
43
+
44
+ Create `pocketbase/.gitignore`:
45
+
46
+ ```
47
+ # Ignore data directory
48
+ pb_data/
49
+
50
+ # Ignore public uploads
51
+ pb_public/
52
+
53
+ # Keep binary and migrations
54
+ !pocketbase
55
+ !pb_migrations/
56
+ ```
57
+
58
+ **Step 3: Create migrations directory**
59
+
60
+ ```bash
61
+ mkdir -p pb_migrations
62
+ ```
63
+
64
+ **Step 4: Commit**
65
+
66
+ ```bash
67
+ git add pocketbase/
68
+ git commit -m "chore: add PocketBase binary and migrations structure"
69
+ ```
70
+
71
+ ---
72
+
73
+ ## Task 2: Create Migration Types
74
+
75
+ **Files:**
76
+ - Create: `host/src/lib/pocketbase/types.ts`
77
+ - Create: `host/src/lib/pocketbase/migrations.ts`
78
+
79
+ **Step 1: Create PocketBase types**
80
+
81
+ Create `host/src/lib/pocketbase/types.ts`:
82
+
83
+ ```typescript
84
+ // PocketBase field types
85
+ export interface BoolField {
86
+ name: string;
87
+ type: 'bool';
88
+ required?: boolean;
89
+ default?: boolean;
90
+ }
91
+
92
+ export interface NumberField {
93
+ name: string;
94
+ type: 'number';
95
+ required?: boolean;
96
+ min?: number;
97
+ max?: number;
98
+ default?: number;
99
+ }
100
+
101
+ export interface TextField {
102
+ name: string;
103
+ type: 'text';
104
+ required?: boolean;
105
+ min?: number;
106
+ max?: number;
107
+ default?: string;
108
+ pattern?: string;
109
+ }
110
+
111
+ export interface EmailField {
112
+ name: string;
113
+ type: 'email';
114
+ required?: boolean;
115
+ }
116
+
117
+ export interface UrlField {
118
+ name: string;
119
+ type: 'url';
120
+ required?: boolean;
121
+ }
122
+
123
+ export interface DateField {
124
+ name: string;
125
+ type: 'date';
126
+ required?: boolean;
127
+ }
128
+
129
+ export interface AutodateField {
130
+ name: string;
131
+ type: 'autodate';
132
+ required?: boolean;
133
+ }
134
+
135
+ export interface SelectField {
136
+ name: string;
137
+ type: 'select';
138
+ required?: boolean;
139
+ values: string[];
140
+ default?: string;
141
+ }
142
+
143
+ export interface JsonField {
144
+ name: string;
145
+ type: 'json';
146
+ required?: boolean;
147
+ }
148
+
149
+ export interface RelationField {
150
+ name: string;
151
+ type: 'relation';
152
+ required?: boolean;
153
+ maxSelect?: number;
154
+ collectionId: string;
155
+ cascadeDelete?: boolean;
156
+ }
157
+
158
+ export type Field = BoolField | NumberField | TextField | EmailField | UrlField | DateField | AutodateField | SelectField | JsonField | RelationField;
159
+
160
+ // Collection definition
161
+ export interface Collection {
162
+ type: 'base' | 'auth' | 'view';
163
+ name: string;
164
+ listRule?: string | null;
165
+ viewRule?: string | null;
166
+ createRule?: string | null;
167
+ updateRule?: string | null;
168
+ deleteRule?: string | null;
169
+ fields: Field[];
170
+ indexes?: string[];
171
+ }
172
+
173
+ // Migration function type
174
+ export type Migration = () => Collection | Collection[];
175
+ ```
176
+
177
+ **Step 2: Create migration utilities**
178
+
179
+ Create `host/src/lib/pocketbase/migrations.ts`:
180
+
181
+ ```typescript
182
+ import PocketBase from 'pocketbase';
183
+ import type { Collection, Migration } from './types';
184
+
185
+ export async function runMigrations(pb: PocketBase, migrations: Migration[]) {
186
+ console.log('[Migrations] Starting PocketBase migrations...');
187
+
188
+ for (const migration of migrations) {
189
+ const collections = Array.isArray(migration()) ? migration() : [migration()];
190
+
191
+ for (const collection of collections) {
192
+ await ensureCollection(pb, collection);
193
+ }
194
+ }
195
+
196
+ console.log('[Migrations] ✅ All migrations complete');
197
+ }
198
+
199
+ async function ensureCollection(pb: PocketBase, collection: Collection) {
200
+ const existing = await pb.collections.getList(1, 50, {
201
+ filter: `name = "${collection.name}"`,
202
+ });
203
+
204
+ if (existing.totalItems > 0) {
205
+ console.log(`[Migrations] ✓ Collection exists: ${collection.name}`);
206
+ return;
207
+ }
208
+
209
+ console.log(`[Migrations] → Creating collection: ${collection.name}`);
210
+
211
+ const result = await pb.collections.create({
212
+ type: collection.type,
213
+ name: collection.name,
214
+ listRule: collection.listRule,
215
+ viewRule: collection.viewRule,
216
+ createRule: collection.createRule,
217
+ updateRule: collection.updateRule,
218
+ deleteRule: collection.deleteRule,
219
+ fields: collection.fields,
220
+ indexes: collection.indexes,
221
+ });
222
+
223
+ console.log(`[Migrations] ✅ Created: ${result.name} (${result.id})`);
224
+ }
225
+ ```
226
+
227
+ **Step 3: Commit**
228
+
229
+ ```bash
230
+ git add host/src/lib/pocketbase/
231
+ git commit -m "feat: add PocketBase migration utilities"
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Task 3: Define All Collection Migrations
237
+
238
+ **Files:**
239
+ - Create: `host/src/lib/pocketbase/collections/index.ts`
240
+ - Create: `host/src/lib/pocketbase/collections/users.ts`
241
+ - Create: `host/src/lib/pocketbase/collections/organizations.ts`
242
+ - Create: `host/src/lib/pocketbase/collections/roles.ts`
243
+ - Create: `host/src/lib/pocketbase/collections/permissions.ts`
244
+ - Create: `host/src/lib/pocketbase/collections/user_roles.ts`
245
+ - Create: `host/src/lib/pocketbase/collections/audit_logs.ts`
246
+ - Create: `host/src/lib/pocketbase/collections/todos.ts`
247
+
248
+ **Step 1: Create collections index**
249
+
250
+ Create `host/src/lib/pocketbase/collections/index.ts`:
251
+
252
+ ```typescript
253
+ import { users } from './users';
254
+ import { organizations } from './organizations';
255
+ import { roles } from './roles';
256
+ import { permissions } from './permissions';
257
+ import { userRoles } from './user_roles';
258
+ import { auditLogs } from './audit_logs';
259
+ import { todos } from './todos';
260
+
261
+ export const collections = [
262
+ users,
263
+ organizations,
264
+ roles,
265
+ permissions,
266
+ userRoles,
267
+ auditLogs,
268
+ todos,
269
+ ];
270
+ ```
271
+
272
+ **Step 2: Create users collection**
273
+
274
+ Create `host/src/lib/pocketbase/collections/users.ts`:
275
+
276
+ ```typescript
277
+ import type { Collection } from '../types';
278
+
279
+ export const users: Collection = {
280
+ type: 'auth',
281
+ name: 'users',
282
+ // Users can view their own profile
283
+ viewRule: 'id = @request.auth.id',
284
+ // Users can update their own profile
285
+ updateRule: 'id = @request.auth.id',
286
+ // No public list/create/delete - must be done by org admin
287
+ listRule: null,
288
+ createRule: null,
289
+ deleteRule: null,
290
+ fields: [
291
+ {
292
+ name: 'name',
293
+ type: 'text',
294
+ required: true,
295
+ min: 1,
296
+ max: 100,
297
+ },
298
+ {
299
+ name: 'avatar',
300
+ type: 'url',
301
+ required: false,
302
+ },
303
+ {
304
+ name: 'organizationId',
305
+ type: 'relation',
306
+ required: true,
307
+ maxSelect: 1,
308
+ collectionId: 'organizations',
309
+ cascadeDelete: false, // Don't delete user when org deleted
310
+ },
311
+ {
312
+ name: 'isActive',
313
+ type: 'bool',
314
+ required: true,
315
+ default: true,
316
+ },
317
+ ],
318
+ indexes: ['CREATE INDEX idx_users_org ON users (organizationId)'],
319
+ };
320
+ ```
321
+
322
+ **Step 3: Create organizations collection**
323
+
324
+ Create `host/src/lib/pocketbase/collections/organizations.ts`:
325
+
326
+ ```typescript
327
+ import type { Collection } from '../types';
328
+
329
+ export const organizations: Collection = {
330
+ type: 'base',
331
+ name: 'organizations',
332
+ // Multi-tenancy: Users can only see their organization
333
+ listRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations',
334
+ viewRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations',
335
+ // Only org owners/admins can create/update/delete
336
+ createRule: '@request.auth.id != "" && @request.auth.roles.role.name = "Owner"',
337
+ updateRule: '@request.auth.id != "" && @request.auth.roles.role.name = "Owner"',
338
+ deleteRule: '@request.auth.id != "" && @request.auth.roles.role.name = "Owner"',
339
+ fields: [
340
+ {
341
+ name: 'name',
342
+ type: 'text',
343
+ required: true,
344
+ min: 1,
345
+ max: 100,
346
+ },
347
+ {
348
+ name: 'slug',
349
+ type: 'text',
350
+ required: true,
351
+ unique: true,
352
+ pattern: '^[a-z0-9-]+$',
353
+ },
354
+ {
355
+ name: 'logo',
356
+ type: 'url',
357
+ required: false,
358
+ },
359
+ {
360
+ name: 'ownerId',
361
+ type: 'relation',
362
+ required: true,
363
+ maxSelect: 1,
364
+ collectionId: 'users',
365
+ cascadeDelete: true,
366
+ },
367
+ {
368
+ name: 'settings',
369
+ type: 'json',
370
+ required: false,
371
+ },
372
+ {
373
+ name: 'maxUsers',
374
+ type: 'number',
375
+ required: true,
376
+ default: 10,
377
+ min: 1,
378
+ },
379
+ ],
380
+ indexes: [
381
+ 'CREATE UNIQUE INDEX idx_organizations_slug ON organizations (slug)',
382
+ 'CREATE INDEX idx_organizations_owner ON organizations (ownerId)',
383
+ ],
384
+ };
385
+ ```
386
+
387
+ **Step 4: Create roles collection**
388
+
389
+ Create `host/src/lib/pocketbase/collections/roles.ts`:
390
+
391
+ ```typescript
392
+ import type { Collection } from '../types';
393
+
394
+ export const roles: Collection = {
395
+ type: 'base',
396
+ name: 'roles',
397
+ // Users can see roles in their organization
398
+ listRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations',
399
+ viewRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations',
400
+ // Only org owners/admins can manage roles
401
+ createRule: '@request.auth.id != "" && (@request.auth.roles.role.name = "Owner" || @request.auth.roles.role.name = "Admin")',
402
+ updateRule: '@request.auth.id != "" && (@request.auth.roles.role.name = "Owner" || @request.auth.roles.role.name = "Admin")',
403
+ deleteRule: '@request.auth.id != "" && @request.auth.roles.role.name = "Owner"',
404
+ fields: [
405
+ {
406
+ name: 'name',
407
+ type: 'text',
408
+ required: true,
409
+ min: 1,
410
+ max: 50,
411
+ },
412
+ {
413
+ name: 'slug',
414
+ type: 'text',
415
+ required: true,
416
+ },
417
+ {
418
+ name: 'description',
419
+ type: 'text',
420
+ required: false,
421
+ },
422
+ {
423
+ name: 'organizationId',
424
+ type: 'relation',
425
+ required: true,
426
+ maxSelect: 1,
427
+ collectionId: 'organizations',
428
+ cascadeDelete: true,
429
+ },
430
+ {
431
+ name: 'isSystem',
432
+ type: 'bool',
433
+ required: true,
434
+ default: false, // System roles (Owner, Admin, Member, Guest) cannot be deleted
435
+ },
436
+ ],
437
+ indexes: [
438
+ 'CREATE UNIQUE INDEX idx_roles_org_slug ON roles (organizationId, slug)',
439
+ 'CREATE INDEX idx_roles_org ON roles (organizationId)',
440
+ ],
441
+ };
442
+ ```
443
+
444
+ **Step 5: Create permissions collection**
445
+
446
+ Create `host/src/lib/pocketbase/collections/permissions.ts`:
447
+
448
+ ```typescript
449
+ import type { Collection } from '../types';
450
+
451
+ export const permissions: Collection = {
452
+ type: 'base',
453
+ name: 'permissions',
454
+ // Users can see permissions for their organization
455
+ listRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations',
456
+ viewRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations',
457
+ // Only org owners/admins can manage permissions
458
+ createRule: '@request.auth.id != "" && (@request.auth.roles.role.name = "Owner" || @request.auth.roles.role.name = "Admin")',
459
+ updateRule: '@request.auth.id != "" && (@request.auth.roles.role.name = "Owner" || @request.auth.roles.role.name = "Admin")',
460
+ deleteRule: '@request.auth.id != "" && @request.auth.roles.role.name = "Owner"',
461
+ fields: [
462
+ {
463
+ name: 'name',
464
+ type: 'text',
465
+ required: true,
466
+ },
467
+ {
468
+ name: 'slug',
469
+ type: 'text',
470
+ required: true,
471
+ },
472
+ {
473
+ name: 'description',
474
+ type: 'text',
475
+ required: false,
476
+ },
477
+ {
478
+ name: 'organizationId',
479
+ type: 'relation',
480
+ required: true,
481
+ maxSelect: 1,
482
+ collectionId: 'organizations',
483
+ cascadeDelete: true,
484
+ },
485
+ {
486
+ name: 'resource',
487
+ type: 'text',
488
+ required: true,
489
+ },
490
+ {
491
+ name: 'action',
492
+ type: 'text',
493
+ required: true,
494
+ },
495
+ ],
496
+ indexes: [
497
+ 'CREATE UNIQUE INDEX idx_permissions_org_slug ON permissions (organizationId, slug)',
498
+ 'CREATE INDEX idx_permissions_resource_action ON permissions (resource, action)',
499
+ ],
500
+ };
501
+ ```
502
+
503
+ **Step 6: Create user_roles junction collection**
504
+
505
+ Create `host/src/lib/pocketbase/collections/user_roles.ts`:
506
+
507
+ ```typescript
508
+ import type { Collection } from '../types';
509
+
510
+ export const userRoles: Collection = {
511
+ type: 'base',
512
+ name: 'user_roles',
513
+ // Users can see who has roles in their org
514
+ listRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations',
515
+ viewRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations',
516
+ // Only org owners/admins can assign roles
517
+ createRule: '@request.auth.id != "" && (@request.auth.roles.role.name = "Owner" || @request.auth.roles.role.name = "Admin")',
518
+ updateRule: '@request.auth.id != "" && (@request.auth.roles.role.name = "Owner" || @request.auth.roles.role.name = "Admin")',
519
+ deleteRule: '@request.auth.id != "" && (@request.auth.roles.role.name = "Owner" || @request.auth.roles.role.name = "Admin")',
520
+ fields: [
521
+ {
522
+ name: 'userId',
523
+ type: 'relation',
524
+ required: true,
525
+ maxSelect: 1,
526
+ collectionId: 'users',
527
+ cascadeDelete: true,
528
+ },
529
+ {
530
+ name: 'roleId',
531
+ type: 'relation',
532
+ required: true,
533
+ maxSelect: 1,
534
+ collectionId: 'roles',
535
+ cascadeDelete: true,
536
+ },
537
+ {
538
+ name: 'organizationId',
539
+ type: 'relation',
540
+ required: true,
541
+ maxSelect: 1,
542
+ collectionId: 'organizations',
543
+ cascadeDelete: false,
544
+ },
545
+ {
546
+ name: 'assignedBy',
547
+ type: 'relation',
548
+ required: true,
549
+ maxSelect: 1,
550
+ collectionId: 'users',
551
+ cascadeDelete: true,
552
+ },
553
+ ],
554
+ indexes: [
555
+ 'CREATE UNIQUE INDEX idx_user_roles_user_role ON user_roles (userId, roleId)',
556
+ 'CREATE INDEX idx_user_roles_org ON user_roles (organizationId)',
557
+ 'CREATE INDEX idx_user_roles_user ON user_roles (userId)',
558
+ ],
559
+ };
560
+ ```
561
+
562
+ **Step 7: Create audit_logs collection**
563
+
564
+ Create `host/src/lib/pocketbase/collections/audit_logs.ts`:
565
+
566
+ ```typescript
567
+ import type { Collection } from '../types';
568
+
569
+ export const auditLogs: Collection = {
570
+ type: 'base',
571
+ name: 'audit_logs',
572
+ // Users can see audit logs for their organization
573
+ listRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations',
574
+ viewRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations',
575
+ // System creates audit logs, users cannot manually create
576
+ createRule: null,
577
+ updateRule: null,
578
+ deleteRule: null,
579
+ fields: [
580
+ {
581
+ name: 'action',
582
+ type: 'select',
583
+ required: true,
584
+ values: ['create', 'update', 'delete', 'login', 'logout', 'invite_user', 'remove_user', 'assign_role', 'revoke_role'],
585
+ },
586
+ {
587
+ name: 'entityType',
588
+ type: 'select',
589
+ required: true,
590
+ values: ['user', 'organization', 'role', 'permission', 'plugin'],
591
+ },
592
+ {
593
+ name: 'entityId',
594
+ type: 'text',
595
+ required: true,
596
+ },
597
+ {
598
+ name: 'entityName',
599
+ type: 'text',
600
+ required: false,
601
+ },
602
+ {
603
+ name: 'organizationId',
604
+ type: 'relation',
605
+ required: true,
606
+ maxSelect: 1,
607
+ collectionId: 'organizations',
608
+ cascadeDelete: true,
609
+ },
610
+ {
611
+ name: 'userId',
612
+ type: 'relation',
613
+ required: true,
614
+ maxSelect: 1,
615
+ collectionId: 'users',
616
+ cascadeDelete: true,
617
+ },
618
+ {
619
+ name: 'ipAddress',
620
+ type: 'text',
621
+ required: false,
622
+ },
623
+ {
624
+ name: 'userAgent',
625
+ type: 'text',
626
+ required: false,
627
+ },
628
+ {
629
+ name: 'metadata',
630
+ type: 'json',
631
+ required: false,
632
+ },
633
+ ],
634
+ indexes: [
635
+ 'CREATE INDEX idx_audit_logs_org ON audit_logs (organizationId)',
636
+ 'CREATE INDEX idx_audit_logs_user ON audit_logs (userId)',
637
+ 'CREATE INDEX idx_audit_logs_entity ON audit_logs (entityType, entityId)',
638
+ 'CREATE INDEX idx_audit_logs_action ON audit_logs (action)',
639
+ 'CREATE INDEX idx_audit_logs_created ON audit_logs (created DESC)',
640
+ ],
641
+ };
642
+ ```
643
+
644
+ **Step 8: Create todos collection**
645
+
646
+ Create `host/src/lib/pocketbase/collections/todos.ts`:
647
+
648
+ ```typescript
649
+ import type { Collection } from '../types';
650
+
651
+ export const todos: Collection = {
652
+ type: 'base',
653
+ name: 'todos',
654
+ // Multi-tenancy: Users can only see todos in their organization
655
+ listRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations',
656
+ viewRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations',
657
+ // Authenticated users can create todos
658
+ createRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations',
659
+ // Users can update their own todos
660
+ updateRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations && owner = @request.auth.id',
661
+ // Users can delete their own todos
662
+ deleteRule: '@request.auth.id != "" && organization = @request.auth.membership.organizations && owner = @request.auth.id',
663
+ fields: [
664
+ {
665
+ name: 'title',
666
+ type: 'text',
667
+ required: true,
668
+ min: 1,
669
+ max: 200,
670
+ },
671
+ {
672
+ name: 'description',
673
+ type: 'text',
674
+ required: false,
675
+ },
676
+ {
677
+ name: 'completed',
678
+ type: 'bool',
679
+ required: true,
680
+ default: false,
681
+ },
682
+ {
683
+ name: 'priority',
684
+ type: 'select',
685
+ required: true,
686
+ values: ['low', 'medium', 'high'],
687
+ default: 'medium',
688
+ },
689
+ {
690
+ name: 'dueDate',
691
+ type: 'date',
692
+ required: false,
693
+ },
694
+ {
695
+ name: 'owner',
696
+ type: 'relation',
697
+ required: true,
698
+ maxSelect: 1,
699
+ collectionId: 'users',
700
+ cascadeDelete: true,
701
+ },
702
+ {
703
+ name: 'organizationId',
704
+ type: 'relation',
705
+ required: true,
706
+ maxSelect: 1,
707
+ collectionId: 'organizations',
708
+ cascadeDelete: true,
709
+ },
710
+ ],
711
+ indexes: [
712
+ 'CREATE INDEX idx_todos_org ON todos (organizationId)',
713
+ 'CREATE INDEX idx_todos_owner ON todos (owner)',
714
+ 'CREATE INDEX idx_todos_completed ON todos (completed)',
715
+ 'CREATE INDEX idx_todos_priority ON todos (priority)',
716
+ ],
717
+ };
718
+ ```
719
+
720
+ **Step 9: Commit**
721
+
722
+ ```bash
723
+ git add host/src/lib/pocketbase/
724
+ git commit -m "feat: add all PocketBase collection definitions with multi-tenancy API rules"
725
+ ```
726
+
727
+ ---
728
+
729
+ ## Task 4: Create Seed Data System
730
+
731
+ **Files:**
732
+ - Create: `host/src/lib/pocketbase/seed.ts`
733
+ - Create: `host/src/lib/pocketbase/seed/roles.ts`
734
+ - Create: `host/src/lib/pocketbase/seed/permissions.ts`
735
+
736
+ **Step 1: Create seed roles**
737
+
738
+ Create `host/src/lib/pocketbase/seed/roles.ts`:
739
+
740
+ ```typescript
741
+ import type { Collection } from '../types';
742
+
743
+ // System roles that exist for every organization
744
+ export const systemRoles: Omit<Collection, 'type' | 'indexes'>[] = [
745
+ {
746
+ name: 'roles_owner',
747
+ slug: 'owner',
748
+ description: 'Full access to all resources',
749
+ isSystem: true,
750
+ fields: [] as any,
751
+ },
752
+ {
753
+ name: 'roles_admin',
754
+ slug: 'admin',
755
+ description: 'Can manage users, roles, and most settings',
756
+ isSystem: true,
757
+ fields: [] as any,
758
+ },
759
+ {
760
+ name: 'roles_member',
761
+ slug: 'member',
762
+ description: 'Standard user with basic access',
763
+ isSystem: true,
764
+ fields: [] as any,
765
+ },
766
+ {
767
+ name: 'roles_guest',
768
+ slug: 'guest',
769
+ description: 'Limited access, read-only',
770
+ isSystem: true,
771
+ fields: [] as any,
772
+ },
773
+ ];
774
+ ```
775
+
776
+ **Step 2: Create seed permissions**
777
+
778
+ Create `host/src/lib/pocketbase/seed/permissions.ts`:
779
+
780
+ ```typescript
781
+ import type { Collection } from '../types';
782
+
783
+ export const systemPermissions: Omit<Collection, 'type' | 'indexes'>[] = [
784
+ // User management
785
+ {
786
+ name: 'permissions_users_view',
787
+ slug: 'users.view',
788
+ description: 'View users in organization',
789
+ resource: 'users',
790
+ action: 'view',
791
+ fields: [] as any,
792
+ },
793
+ {
794
+ name: 'permissions_users_create',
795
+ slug: 'users.create',
796
+ description: 'Invite users to organization',
797
+ resource: 'users',
798
+ action: 'create',
799
+ fields: [] as any,
800
+ },
801
+ {
802
+ name: 'permissions_users_update',
803
+ slug: 'users.update',
804
+ description: 'Update user information',
805
+ resource: 'users',
806
+ action: 'update',
807
+ fields: [] as any,
808
+ },
809
+ {
810
+ name: 'permissions_users_delete',
811
+ slug: 'users.delete',
812
+ description: 'Remove users from organization',
813
+ resource: 'users',
814
+ action: 'delete',
815
+ fields: [] as any,
816
+ },
817
+
818
+ // Role management
819
+ {
820
+ name: 'permissions_roles_view',
821
+ slug: 'roles.view',
822
+ description: 'View roles in organization',
823
+ resource: 'roles',
824
+ action: 'view',
825
+ fields: [] as any,
826
+ },
827
+ {
828
+ name: 'permissions_roles_create',
829
+ slug: 'roles.create',
830
+ description: 'Create new roles',
831
+ resource: 'roles',
832
+ action: 'create',
833
+ fields: [] as any,
834
+ },
835
+ {
836
+ name: 'permissions_roles_update',
837
+ slug: 'roles.update',
838
+ description: 'Update roles',
839
+ resource: 'roles',
840
+ action: 'update',
841
+ fields: [] as any,
842
+ },
843
+ {
844
+ name: 'permissions_roles_delete',
845
+ slug: 'roles.delete',
846
+ description: 'Delete roles',
847
+ resource: 'roles',
848
+ action: 'delete',
849
+ fields: [] as any,
850
+ },
851
+
852
+ // Permission management
853
+ {
854
+ name: 'permissions_permissions_view',
855
+ slug: 'permissions.view',
856
+ description: 'View permissions',
857
+ resource: 'permissions',
858
+ action: 'view',
859
+ fields: [] as any,
860
+ },
861
+ {
862
+ name: 'permissions_permissions_create',
863
+ slug: 'permissions.create',
864
+ description: 'Create permissions',
865
+ resource: 'permissions',
866
+ action: 'create',
867
+ fields: [] as any,
868
+ },
869
+ {
870
+ name: 'permissions_permissions_delete',
871
+ slug: 'permissions.delete',
872
+ description: 'Delete permissions',
873
+ resource: 'permissions',
874
+ action: 'delete',
875
+ fields: [] as any,
876
+ },
877
+
878
+ // Organization management
879
+ {
880
+ name: 'permissions_org_update',
881
+ slug: 'org.update',
882
+ description: 'Update organization settings',
883
+ resource: 'organization',
884
+ action: 'update',
885
+ fields: [] as any,
886
+ },
887
+
888
+ // Audit logs
889
+ {
890
+ name: 'permissions_audit_view',
891
+ slug: 'audit.view',
892
+ description: 'View audit logs',
893
+ resource: 'audit_logs',
894
+ action: 'view',
895
+ fields: [] as any,
896
+ },
897
+
898
+ // Todo management
899
+ {
900
+ name: 'permissions_todos_view',
901
+ slug: 'todos.view',
902
+ description: 'View todos',
903
+ resource: 'todos',
904
+ action: 'view',
905
+ fields: [] as any,
906
+ },
907
+ {
908
+ name: 'permissions_todos_manage',
909
+ slug: 'todos.manage',
910
+ description: 'Manage all todos (create, update, delete any)',
911
+ resource: 'todos',
912
+ action: 'manage',
913
+ fields: [] as any,
914
+ },
915
+
916
+ // Plugin management
917
+ {
918
+ name: 'permissions_plugins_view',
919
+ slug: 'plugins.view',
920
+ description: 'View enabled plugins',
921
+ resource: 'plugins',
922
+ action: 'view',
923
+ fields: [] as any,
924
+ },
925
+ {
926
+ name: 'permissions_plugins_manage',
927
+ slug: 'plugins.manage',
928
+ description: 'Enable/disable plugins',
929
+ resource: 'plugins',
930
+ action: 'manage',
931
+ fields: [] as any,
932
+ },
933
+ ];
934
+ ```
935
+
936
+ **Step 3: Create seed function**
937
+
938
+ Create `host/src/lib/pocketbase/seed.ts`:
939
+
940
+ ```typescript
941
+ import PocketBase from 'pocketbase';
942
+ import { env } from '../../env/env.schema';
943
+ import { systemRoles } from './seed/roles';
944
+ import { systemPermissions } from './seed/permissions';
945
+
946
+ interface SeedData {
947
+ adminEmail: string;
948
+ adminPassword: string;
949
+ adminName: string;
950
+ orgName: string;
951
+ }
952
+
953
+ export async function seedDatabase(pb: PocketBase, seedData: SeedData) {
954
+ console.log('[Seed] Starting database seeding...');
955
+
956
+ // Check if already seeded
957
+ const orgs = await pb.collections.getList(1, 1, {
958
+ filter: 'name = "organizations"',
959
+ });
960
+
961
+ if (orgs.totalItems > 0) {
962
+ const existingOrgs = await pb.records.getList('organizations', 1, 1);
963
+ if (existingOrgs.totalItems > 0) {
964
+ console.log('[Seed] ℹ Database already seeded, skipping...');
965
+ return;
966
+ }
967
+ }
968
+
969
+ console.log('[Seed] → Creating admin user...');
970
+
971
+ // Create admin user
972
+ const admin = await pb.users.create({
973
+ email: seedData.adminEmail,
974
+ password: seedData.adminPassword,
975
+ passwordConfirm: seedData.adminPassword,
976
+ name: seedData.adminName,
977
+ });
978
+
979
+ console.log('[Seed] → Creating organization...');
980
+
981
+ // Create organization
982
+ const organization = await pb.records.create('organizations', {
983
+ name: seedData.orgName,
984
+ slug: seedData.orgName.toLowerCase().replace(/\s+/g, '-'),
985
+ ownerId: admin.id,
986
+ maxUsers: 10,
987
+ });
988
+
989
+ // Update admin with organization
990
+ await pb.users.update(admin.id, {
991
+ organizationId: organization.id,
992
+ });
993
+
994
+ console.log('[Seed] → Creating system roles...');
995
+
996
+ // Create system roles
997
+ const roleMap = new Map<string, string>();
998
+
999
+ for (const roleData of systemRoles) {
1000
+ const role = await pb.records.create('roles', {
1001
+ name: roleData.name,
1002
+ slug: roleData.slug,
1003
+ description: roleData.description,
1004
+ organizationId: organization.id,
1005
+ isSystem: roleData.isSystem,
1006
+ });
1007
+ roleMap.set(roleData.slug, role.id);
1008
+ }
1009
+
1010
+ console.log('[Seed] → Creating system permissions...');
1011
+
1012
+ // Create system permissions
1013
+ for (const permData of systemPermissions) {
1014
+ await pb.records.create('permissions', {
1015
+ name: permData.name,
1016
+ slug: permData.slug,
1017
+ description: permData.description,
1018
+ organizationId: organization.id,
1019
+ resource: permData.resource,
1020
+ action: permData.action,
1021
+ });
1022
+ }
1023
+
1024
+ console.log('[Seed] → Assigning Owner role to admin...');
1025
+
1026
+ // Assign Owner role to admin
1027
+ await pb.records.create('user_roles', {
1028
+ userId: admin.id,
1029
+ roleId: roleMap.get('owner')!,
1030
+ organizationId: organization.id,
1031
+ assignedBy: admin.id,
1032
+ });
1033
+
1034
+ console.log('[Seed] → Creating sample todos...');
1035
+
1036
+ // Create sample todos
1037
+ await pb.records.create('todos', {
1038
+ title: 'Welcome to Lego-One! 👋',
1039
+ description: 'This is your first todo item. Try editing or completing it!',
1040
+ completed: false,
1041
+ priority: 'medium',
1042
+ owner: admin.id,
1043
+ organizationId: organization.id,
1044
+ });
1045
+
1046
+ await pb.records.create('todos', {
1047
+ title: 'Explore the Dashboard',
1048
+ description: 'Check out the Dashboard plugin to see your stats and activity.',
1049
+ completed: false,
1050
+ priority: 'low',
1051
+ owner: admin.id,
1052
+ organizationId: organization.id,
1053
+ });
1054
+
1055
+ await pb.records.create('todos', {
1056
+ title: 'Manage your Organization',
1057
+ description: 'Go to Settings to invite team members and configure roles.',
1058
+ completed: false,
1059
+ priority: 'high',
1060
+ owner: admin.id,
1061
+ organizationId: organization.id,
1062
+ });
1063
+
1064
+ console.log('[Seed] ✅ Database seeded successfully!');
1065
+ console.log('');
1066
+ console.log('📧 Login credentials:');
1067
+ console.log(` Email: ${seedData.adminEmail}`);
1068
+ console.log(` Password: ${seedData.adminPassword}`);
1069
+ }
1070
+ ```
1071
+
1072
+ **Step 4: Commit**
1073
+
1074
+ ```bash
1075
+ git add host/src/lib/pocketbase/seed/
1076
+ git commit -m "feat: add database seeding system with roles, permissions, and sample data"
1077
+ ```
1078
+
1079
+ ---
1080
+
1081
+ ## Task 5: Create PocketBase Client Initialization
1082
+
1083
+ **Files:**
1084
+ - Create: `host/src/lib/pocketbase/client.ts`
1085
+ - Create: `host/src/lib/pocketbase/index.ts`
1086
+
1087
+ **Step 1: Create PocketBase client**
1088
+
1089
+ Create `host/src/lib/pocketbase/client.ts`:
1090
+
1091
+ ```typescript
1092
+ import PocketBase from 'pocketbase';
1093
+ import { env } from '../../env/env.schema';
1094
+
1095
+ let pbInstance: PocketBase | null = null;
1096
+
1097
+ export function getPocketBase(): PocketBase {
1098
+ if (pbInstance) {
1099
+ return pbInstance;
1100
+ }
1101
+
1102
+ const pb = new PocketBase(env.VITE_POCKETBASE_URL);
1103
+
1104
+ // Auto-authenticate as admin for server-side operations
1105
+ if (typeof window === 'undefined') {
1106
+ pb.admins.authViaPassword(
1107
+ env.VITE_POCKETBASE_ADMIN_EMAIL,
1108
+ env.VITE_POCKETBASE_ADMIN_PASSWORD
1109
+ ).catch((err) => {
1110
+ console.error('Failed to authenticate with PocketBase:', err);
1111
+ });
1112
+ }
1113
+
1114
+ pbInstance = pb;
1115
+ return pb;
1116
+ }
1117
+
1118
+ export function getPocketBaseAdmin(): PocketBase {
1119
+ const pb = new PocketBase(env.VITE_POCKETBASE_URL);
1120
+
1121
+ // This must be called with admin credentials
1122
+ return pb;
1123
+ }
1124
+
1125
+ // Reset singleton (useful for testing)
1126
+ export function resetPocketBase(): void {
1127
+ pbInstance = null;
1128
+ }
1129
+ ```
1130
+
1131
+ **Step 2: Create barrel export**
1132
+
1133
+ Create `host/src/lib/pocketbase/index.ts`:
1134
+
1135
+ ```typescript
1136
+ export * from './client';
1137
+ export * from './types';
1138
+ export * from './migrations';
1139
+ export * from './collections';
1140
+ export * from './seed';
1141
+ ```
1142
+
1143
+ **Step 3: Commit**
1144
+
1145
+ ```bash
1146
+ git add host/src/lib/pocketbase/
1147
+ git commit -m "feat: add PocketBase client initialization and exports"
1148
+ ```
1149
+
1150
+ ---
1151
+
1152
+ ## Task 6: Create Startup Migration Hook
1153
+
1154
+ **Files:**
1155
+ - Create: `host/src/kernel/use-migrations.ts`
1156
+
1157
+ **Step 1: Create migration hook**
1158
+
1159
+ Create `host/src/kernel/use-migrations.ts`:
1160
+
1161
+ ```typescript
1162
+ import { useEffect, useState } from 'react';
1163
+ import { getPocketBaseAdmin } from '@lib/pocketbase';
1164
+ import { runMigrations } from '@lib/pocketbase/migrations';
1165
+ import { collections } from '@lib/pocketbase/collections';
1166
+ import { seedDatabase } from '@lib/pocketbase/seed';
1167
+ import { env } from '@env/env.schema';
1168
+
1169
+ interface MigrationState {
1170
+ status: 'pending' | 'running' | 'success' | 'error';
1171
+ message: string | null;
1172
+ }
1173
+
1174
+ export function useMigrations() {
1175
+ const [state, setState] = useState<MigrationState>({
1176
+ status: 'pending',
1177
+ message: null,
1178
+ });
1179
+
1180
+ useEffect(() => {
1181
+ let cancelled = false;
1182
+
1183
+ async function run() {
1184
+ if (cancelled) return;
1185
+
1186
+ setState({ status: 'running', message: 'Running database migrations...' });
1187
+
1188
+ try {
1189
+ const pb = getPocketBaseAdmin();
1190
+
1191
+ // Authenticate as admin
1192
+ await pb.admins.authWithPassword(
1193
+ env.VITE_POCKETBASE_ADMIN_EMAIL,
1194
+ env.VITE_POCKETBASE_ADMIN_PASSWORD
1195
+ );
1196
+
1197
+ if (cancelled) return;
1198
+
1199
+ // Run migrations
1200
+ await runMigrations(pb, collections);
1201
+
1202
+ if (cancelled) return;
1203
+
1204
+ // Seed database (only if in development or explicitly requested)
1205
+ if (env.VITE_SEED_ADMIN_EMAIL) {
1206
+ setState({ status: 'running', message: 'Seeding database...' });
1207
+
1208
+ await seedDatabase(pb, {
1209
+ adminEmail: env.VITE_SEED_ADMIN_EMAIL,
1210
+ adminPassword: env.VITE_SEED_ADMIN_PASSWORD || 'admin123',
1211
+ adminName: env.VITE_SEED_ADMIN_NAME || 'Super Admin',
1212
+ orgName: env.VITE_SEED_ORG_NAME || 'Demo Organization',
1213
+ });
1214
+ }
1215
+
1216
+ if (cancelled) return;
1217
+
1218
+ setState({ status: 'success', message: 'Database ready!' });
1219
+ } catch (error) {
1220
+ const message = error instanceof Error ? error.message : 'Unknown error';
1221
+ setState({ status: 'error', message });
1222
+ console.error('[Migrations] Error:', error);
1223
+ }
1224
+ }
1225
+
1226
+ run();
1227
+
1228
+ return () => {
1229
+ cancelled = true;
1230
+ };
1231
+ }, []);
1232
+
1233
+ return state;
1234
+ }
1235
+ ```
1236
+
1237
+ **Step 2: Commit**
1238
+
1239
+ ```bash
1240
+ git add host/src/kernel/use-migrations.ts
1241
+ git commit -m "feat: add database migration hook for startup"
1242
+ ```
1243
+
1244
+ ---
1245
+
1246
+ ## Task 7: Create PocketBase Provider
1247
+
1248
+ **Files:**
1249
+ - Create: `host/src/providers/PocketBaseProvider.tsx`
1250
+
1251
+ **Step 1: Create PocketBase context provider**
1252
+
1253
+ Create `host/src/providers/PocketBaseProvider.tsx`:
1254
+
1255
+ ```typescript
1256
+ import { createContext, useContext, ReactNode } from 'react';
1257
+ import { getPocketBase, resetPocketBase } from '@lib/pocketbase';
1258
+ import type { PocketBase } from 'pocketbase';
1259
+
1260
+ const PocketBaseContext = createContext<PocketBase | null>(null);
1261
+
1262
+ export function PocketBaseProvider({ children }: { children: ReactNode }) {
1263
+ const pb = getPocketBase();
1264
+
1265
+ return (
1266
+ <PocketBaseContext.Provider value={pb}>
1267
+ {children}
1268
+ </PocketBaseContext.Provider>
1269
+ );
1270
+ }
1271
+
1272
+ export function usePocketBase(): PocketBase {
1273
+ const pb = useContext(PocketBaseContext);
1274
+
1275
+ if (!pb) {
1276
+ throw new Error('usePocketBase must be used within PocketBaseProvider');
1277
+ }
1278
+
1279
+ return pb;
1280
+ }
1281
+
1282
+ export function usePocketBaseAdmin() {
1283
+ return getPocketBaseAdmin();
1284
+ }
1285
+
1286
+ // For testing
1287
+ export { resetPocketBase as resetPocketBaseForTesting };
1288
+ ```
1289
+
1290
+ **Step 2: Commit**
1291
+
1292
+ ```bash
1293
+ git add host/src/providers/
1294
+ git commit -m "feat: add PocketBase context provider"
1295
+ ```
1296
+
1297
+ ---
1298
+
1299
+ ## Task 8: Create Initial saas.config.ts
1300
+
1301
+ **Files:**
1302
+ - Create: `saas.config.ts`
1303
+
1304
+ **Step 1: Create SaaS configuration**
1305
+
1306
+ Create `saas.config.ts`:
1307
+
1308
+ ```typescript
1309
+ import { defineConfig } from '@lego/kernel/config';
1310
+
1311
+ export default defineConfig({
1312
+ plugins: [
1313
+ {
1314
+ name: '@lego/plugin-dashboard',
1315
+ enabled: true,
1316
+ },
1317
+ {
1318
+ name: '@lego/plugin-todo',
1319
+ enabled: true,
1320
+ },
1321
+ ],
1322
+ });
1323
+ ```
1324
+
1325
+ **Step 2: Commit**
1326
+
1327
+ ```bash
1328
+ git add saas.config.ts
1329
+ git commit -m "chore: add initial SaaS plugin configuration"
1330
+ ```
1331
+
1332
+ ---
1333
+
1334
+ ## Verification
1335
+
1336
+ After completing all tasks:
1337
+
1338
+ **Step 1: Verify file structure**
1339
+
1340
+ Run:
1341
+ ```bash
1342
+ ls -la host/src/lib/pocketbase/
1343
+ ```
1344
+
1345
+ Expected: `types.ts`, `migrations.ts`, `collections/index.ts`, `seed.ts`, `client.ts`, `seed/` folder
1346
+
1347
+ **Step 2: Verify imports compile**
1348
+
1349
+ Run:
1350
+ ```bash
1351
+ cd host && pnpm install && pnpm typecheck
1352
+ ```
1353
+
1354
+ Expected: Will fail because workspace doesn't exist yet, but should not have TypeScript errors in created files.
1355
+
1356
+ **Step 3: Verify migrations compile**
1357
+
1358
+ No errors in TypeScript files created.
1359
+
1360
+ ---
1361
+
1362
+ ## Summary
1363
+
1364
+ After completing this document, you have:
1365
+
1366
+ ✅ PocketBase downloaded and configured
1367
+ ✅ All 7 collections defined (users, organizations, roles, permissions, user_roles, audit_logs, todos)
1368
+ ✅ Multi-tenancy API rules on all collections
1369
+ ✅ Migration system to create collections on startup
1370
+ ✅ Seed data system with admin + org + roles + permissions + sample todos
1371
+ ✅ PocketBase client with singleton pattern
1372
+ ✅ PocketBase context provider for React
1373
+
1374
+ **Next:** → [`03-host-kernel.md`](./03-host-kernel.md)