@fayz-ai/db 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/index.cjs +39 -0
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +39 -2
  6. package/dist/index.js.map +1 -1
  7. package/dist/schema/spine.d.ts +553 -0
  8. package/dist/schema/spine.d.ts.map +1 -1
  9. package/migrations/025_created_by.sql +75 -0
  10. package/migrations/026_audit_trail.sql +73 -0
  11. package/migrations/027_domain_events.sql +266 -0
  12. package/migrations/028_tenant_scoped_token.sql +127 -0
  13. package/migrations/029_connections.sql +186 -0
  14. package/migrations/030_effect_idempotency.sql +159 -0
  15. package/migrations/031_sync_run_message.sql +39 -0
  16. package/migrations/032_connection_secrets.sql +227 -0
  17. package/migrations/033_sync_schedule.sql +651 -0
  18. package/migrations/034_custom_fields.sql +55 -0
  19. package/migrations/035_field_registry.sql +148 -0
  20. package/migrations/036_analytics_run_batch.sql +84 -0
  21. package/migrations/037_sync_tick_one_at_a_time.sql +256 -0
  22. package/migrations/038_onboarding_responses.sql +103 -0
  23. package/migrations/039_unit_tree.sql +270 -0
  24. package/migrations/040_resource_grants.sql +474 -0
  25. package/migrations/041_scoped_columns.sql +192 -0
  26. package/migrations/042_unit_scope_policies.sql +145 -0
  27. package/migrations/043_view_invoker.sql +81 -0
  28. package/migrations/044_unit_member_facts.sql +47 -0
  29. package/migrations/045_unit_entry.sql +236 -0
  30. package/migrations/046_membership_visible_to_members.sql +85 -0
  31. package/migrations/047_tasks.sql +266 -0
  32. package/migrations/048_every_login_is_a_person.sql +190 -0
  33. package/migrations/049_bookable_people.sql +126 -0
  34. package/package.json +7 -4
@@ -152,4 +152,557 @@ export declare const orderItems: import("drizzle-orm/pg-core").PgTableWithColumn
152
152
  };
153
153
  dialect: "pg";
154
154
  }>;
155
+ /**
156
+ * The connector spine — `plg_connections` / `plg_sync_runs` (migration 029).
157
+ *
158
+ * Declared in full rather than as a bare `id`, because unlike the Ring 0 tables
159
+ * above these two are OURS: 029 is the authority, and a plugin that wants a real
160
+ * FK to a connection (Google Calendar's channel table is the first) has nothing
161
+ * to point at without this. The columns are therefore kept in agreement with
162
+ * 029 by hand — the migration ships the table, this declares its shape.
163
+ *
164
+ * Deliberately NOT in the migration-generating schema set: 029 already creates
165
+ * these, with RLS, grants and a partial index Drizzle would not reproduce.
166
+ */
167
+ export declare const plgConnections: import("drizzle-orm/pg-core").PgTableWithColumns<{
168
+ name: "plg_connections";
169
+ schema: undefined;
170
+ columns: {
171
+ id: import("drizzle-orm/pg-core").PgColumn<{
172
+ name: "id";
173
+ tableName: "plg_connections";
174
+ dataType: "string";
175
+ columnType: "PgUUID";
176
+ data: string;
177
+ driverParam: string;
178
+ notNull: true;
179
+ hasDefault: false;
180
+ isPrimaryKey: true;
181
+ isAutoincrement: false;
182
+ hasRuntimeDefault: false;
183
+ enumValues: undefined;
184
+ baseColumn: never;
185
+ identity: undefined;
186
+ generated: undefined;
187
+ }, {}, {}>;
188
+ tenantId: import("drizzle-orm/pg-core").PgColumn<{
189
+ name: "tenant_id";
190
+ tableName: "plg_connections";
191
+ dataType: "string";
192
+ columnType: "PgUUID";
193
+ data: string;
194
+ driverParam: string;
195
+ notNull: true;
196
+ hasDefault: false;
197
+ isPrimaryKey: false;
198
+ isAutoincrement: false;
199
+ hasRuntimeDefault: false;
200
+ enumValues: undefined;
201
+ baseColumn: never;
202
+ identity: undefined;
203
+ generated: undefined;
204
+ }, {}, {}>;
205
+ connectorId: import("drizzle-orm/pg-core").PgColumn<{
206
+ name: "connector_id";
207
+ tableName: "plg_connections";
208
+ dataType: "string";
209
+ columnType: "PgText";
210
+ data: string;
211
+ driverParam: string;
212
+ notNull: true;
213
+ hasDefault: false;
214
+ isPrimaryKey: false;
215
+ isAutoincrement: false;
216
+ hasRuntimeDefault: false;
217
+ enumValues: [string, ...string[]];
218
+ baseColumn: never;
219
+ identity: undefined;
220
+ generated: undefined;
221
+ }, {}, {}>;
222
+ instanceKey: import("drizzle-orm/pg-core").PgColumn<{
223
+ name: "instance_key";
224
+ tableName: "plg_connections";
225
+ dataType: "string";
226
+ columnType: "PgText";
227
+ data: string;
228
+ driverParam: string;
229
+ notNull: true;
230
+ hasDefault: false;
231
+ isPrimaryKey: false;
232
+ isAutoincrement: false;
233
+ hasRuntimeDefault: false;
234
+ enumValues: [string, ...string[]];
235
+ baseColumn: never;
236
+ identity: undefined;
237
+ generated: undefined;
238
+ }, {}, {}>;
239
+ displayName: import("drizzle-orm/pg-core").PgColumn<{
240
+ name: "display_name";
241
+ tableName: "plg_connections";
242
+ dataType: "string";
243
+ columnType: "PgText";
244
+ data: string;
245
+ driverParam: string;
246
+ notNull: false;
247
+ hasDefault: false;
248
+ isPrimaryKey: false;
249
+ isAutoincrement: false;
250
+ hasRuntimeDefault: false;
251
+ enumValues: [string, ...string[]];
252
+ baseColumn: never;
253
+ identity: undefined;
254
+ generated: undefined;
255
+ }, {}, {}>;
256
+ active: import("drizzle-orm/pg-core").PgColumn<{
257
+ name: "active";
258
+ tableName: "plg_connections";
259
+ dataType: "boolean";
260
+ columnType: "PgBoolean";
261
+ data: boolean;
262
+ driverParam: boolean;
263
+ notNull: true;
264
+ hasDefault: false;
265
+ isPrimaryKey: false;
266
+ isAutoincrement: false;
267
+ hasRuntimeDefault: false;
268
+ enumValues: undefined;
269
+ baseColumn: never;
270
+ identity: undefined;
271
+ generated: undefined;
272
+ }, {}, {}>;
273
+ status: import("drizzle-orm/pg-core").PgColumn<{
274
+ name: "status";
275
+ tableName: "plg_connections";
276
+ dataType: "string";
277
+ columnType: "PgText";
278
+ data: string;
279
+ driverParam: string;
280
+ notNull: true;
281
+ hasDefault: false;
282
+ isPrimaryKey: false;
283
+ isAutoincrement: false;
284
+ hasRuntimeDefault: false;
285
+ enumValues: [string, ...string[]];
286
+ baseColumn: never;
287
+ identity: undefined;
288
+ generated: undefined;
289
+ }, {}, {}>;
290
+ statusDetail: import("drizzle-orm/pg-core").PgColumn<{
291
+ name: "status_detail";
292
+ tableName: "plg_connections";
293
+ dataType: "string";
294
+ columnType: "PgText";
295
+ data: string;
296
+ driverParam: string;
297
+ notNull: false;
298
+ hasDefault: false;
299
+ isPrimaryKey: false;
300
+ isAutoincrement: false;
301
+ hasRuntimeDefault: false;
302
+ enumValues: [string, ...string[]];
303
+ baseColumn: never;
304
+ identity: undefined;
305
+ generated: undefined;
306
+ }, {}, {}>;
307
+ settings: import("drizzle-orm/pg-core").PgColumn<{
308
+ name: "settings";
309
+ tableName: "plg_connections";
310
+ dataType: "json";
311
+ columnType: "PgJsonb";
312
+ data: unknown;
313
+ driverParam: unknown;
314
+ notNull: true;
315
+ hasDefault: false;
316
+ isPrimaryKey: false;
317
+ isAutoincrement: false;
318
+ hasRuntimeDefault: false;
319
+ enumValues: undefined;
320
+ baseColumn: never;
321
+ identity: undefined;
322
+ generated: undefined;
323
+ }, {}, {}>;
324
+ providerAccountKey: import("drizzle-orm/pg-core").PgColumn<{
325
+ name: "provider_account_key";
326
+ tableName: "plg_connections";
327
+ dataType: "string";
328
+ columnType: "PgText";
329
+ data: string;
330
+ driverParam: string;
331
+ notNull: false;
332
+ hasDefault: false;
333
+ isPrimaryKey: false;
334
+ isAutoincrement: false;
335
+ hasRuntimeDefault: false;
336
+ enumValues: [string, ...string[]];
337
+ baseColumn: never;
338
+ identity: undefined;
339
+ generated: undefined;
340
+ }, {}, {}>;
341
+ cursors: import("drizzle-orm/pg-core").PgColumn<{
342
+ name: "cursors";
343
+ tableName: "plg_connections";
344
+ dataType: "json";
345
+ columnType: "PgJsonb";
346
+ data: unknown;
347
+ driverParam: unknown;
348
+ notNull: true;
349
+ hasDefault: false;
350
+ isPrimaryKey: false;
351
+ isAutoincrement: false;
352
+ hasRuntimeDefault: false;
353
+ enumValues: undefined;
354
+ baseColumn: never;
355
+ identity: undefined;
356
+ generated: undefined;
357
+ }, {}, {}>;
358
+ lastSyncAt: import("drizzle-orm/pg-core").PgColumn<{
359
+ name: "last_sync_at";
360
+ tableName: "plg_connections";
361
+ dataType: "date";
362
+ columnType: "PgTimestamp";
363
+ data: Date;
364
+ driverParam: string;
365
+ notNull: false;
366
+ hasDefault: false;
367
+ isPrimaryKey: false;
368
+ isAutoincrement: false;
369
+ hasRuntimeDefault: false;
370
+ enumValues: undefined;
371
+ baseColumn: never;
372
+ identity: undefined;
373
+ generated: undefined;
374
+ }, {}, {}>;
375
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
376
+ name: "created_at";
377
+ tableName: "plg_connections";
378
+ dataType: "date";
379
+ columnType: "PgTimestamp";
380
+ data: Date;
381
+ driverParam: string;
382
+ notNull: true;
383
+ hasDefault: false;
384
+ isPrimaryKey: false;
385
+ isAutoincrement: false;
386
+ hasRuntimeDefault: false;
387
+ enumValues: undefined;
388
+ baseColumn: never;
389
+ identity: undefined;
390
+ generated: undefined;
391
+ }, {}, {}>;
392
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
393
+ name: "updated_at";
394
+ tableName: "plg_connections";
395
+ dataType: "date";
396
+ columnType: "PgTimestamp";
397
+ data: Date;
398
+ driverParam: string;
399
+ notNull: true;
400
+ hasDefault: false;
401
+ isPrimaryKey: false;
402
+ isAutoincrement: false;
403
+ hasRuntimeDefault: false;
404
+ enumValues: undefined;
405
+ baseColumn: never;
406
+ identity: undefined;
407
+ generated: undefined;
408
+ }, {}, {}>;
409
+ };
410
+ dialect: "pg";
411
+ }>;
412
+ export declare const plgSyncRuns: import("drizzle-orm/pg-core").PgTableWithColumns<{
413
+ name: "plg_sync_runs";
414
+ schema: undefined;
415
+ columns: {
416
+ id: import("drizzle-orm/pg-core").PgColumn<{
417
+ name: "id";
418
+ tableName: "plg_sync_runs";
419
+ dataType: "string";
420
+ columnType: "PgUUID";
421
+ data: string;
422
+ driverParam: string;
423
+ notNull: true;
424
+ hasDefault: false;
425
+ isPrimaryKey: true;
426
+ isAutoincrement: false;
427
+ hasRuntimeDefault: false;
428
+ enumValues: undefined;
429
+ baseColumn: never;
430
+ identity: undefined;
431
+ generated: undefined;
432
+ }, {}, {}>;
433
+ tenantId: import("drizzle-orm/pg-core").PgColumn<{
434
+ name: "tenant_id";
435
+ tableName: "plg_sync_runs";
436
+ dataType: "string";
437
+ columnType: "PgUUID";
438
+ data: string;
439
+ driverParam: string;
440
+ notNull: true;
441
+ hasDefault: false;
442
+ isPrimaryKey: false;
443
+ isAutoincrement: false;
444
+ hasRuntimeDefault: false;
445
+ enumValues: undefined;
446
+ baseColumn: never;
447
+ identity: undefined;
448
+ generated: undefined;
449
+ }, {}, {}>;
450
+ connectionId: import("drizzle-orm/pg-core").PgColumn<{
451
+ name: "connection_id";
452
+ tableName: "plg_sync_runs";
453
+ dataType: "string";
454
+ columnType: "PgUUID";
455
+ data: string;
456
+ driverParam: string;
457
+ notNull: true;
458
+ hasDefault: false;
459
+ isPrimaryKey: false;
460
+ isAutoincrement: false;
461
+ hasRuntimeDefault: false;
462
+ enumValues: undefined;
463
+ baseColumn: never;
464
+ identity: undefined;
465
+ generated: undefined;
466
+ }, {}, {}>;
467
+ connectorId: import("drizzle-orm/pg-core").PgColumn<{
468
+ name: "connector_id";
469
+ tableName: "plg_sync_runs";
470
+ dataType: "string";
471
+ columnType: "PgText";
472
+ data: string;
473
+ driverParam: string;
474
+ notNull: true;
475
+ hasDefault: false;
476
+ isPrimaryKey: false;
477
+ isAutoincrement: false;
478
+ hasRuntimeDefault: false;
479
+ enumValues: [string, ...string[]];
480
+ baseColumn: never;
481
+ identity: undefined;
482
+ generated: undefined;
483
+ }, {}, {}>;
484
+ direction: import("drizzle-orm/pg-core").PgColumn<{
485
+ name: "direction";
486
+ tableName: "plg_sync_runs";
487
+ dataType: "string";
488
+ columnType: "PgText";
489
+ data: string;
490
+ driverParam: string;
491
+ notNull: true;
492
+ hasDefault: false;
493
+ isPrimaryKey: false;
494
+ isAutoincrement: false;
495
+ hasRuntimeDefault: false;
496
+ enumValues: [string, ...string[]];
497
+ baseColumn: never;
498
+ identity: undefined;
499
+ generated: undefined;
500
+ }, {}, {}>;
501
+ triggerKind: import("drizzle-orm/pg-core").PgColumn<{
502
+ name: "trigger_kind";
503
+ tableName: "plg_sync_runs";
504
+ dataType: "string";
505
+ columnType: "PgText";
506
+ data: string;
507
+ driverParam: string;
508
+ notNull: true;
509
+ hasDefault: false;
510
+ isPrimaryKey: false;
511
+ isAutoincrement: false;
512
+ hasRuntimeDefault: false;
513
+ enumValues: [string, ...string[]];
514
+ baseColumn: never;
515
+ identity: undefined;
516
+ generated: undefined;
517
+ }, {}, {}>;
518
+ status: import("drizzle-orm/pg-core").PgColumn<{
519
+ name: "status";
520
+ tableName: "plg_sync_runs";
521
+ dataType: "string";
522
+ columnType: "PgText";
523
+ data: string;
524
+ driverParam: string;
525
+ notNull: true;
526
+ hasDefault: false;
527
+ isPrimaryKey: false;
528
+ isAutoincrement: false;
529
+ hasRuntimeDefault: false;
530
+ enumValues: [string, ...string[]];
531
+ baseColumn: never;
532
+ identity: undefined;
533
+ generated: undefined;
534
+ }, {}, {}>;
535
+ stream: import("drizzle-orm/pg-core").PgColumn<{
536
+ name: "stream";
537
+ tableName: "plg_sync_runs";
538
+ dataType: "string";
539
+ columnType: "PgText";
540
+ data: string;
541
+ driverParam: string;
542
+ notNull: false;
543
+ hasDefault: false;
544
+ isPrimaryKey: false;
545
+ isAutoincrement: false;
546
+ hasRuntimeDefault: false;
547
+ enumValues: [string, ...string[]];
548
+ baseColumn: never;
549
+ identity: undefined;
550
+ generated: undefined;
551
+ }, {}, {}>;
552
+ fetched: import("drizzle-orm/pg-core").PgColumn<{
553
+ name: "fetched";
554
+ tableName: "plg_sync_runs";
555
+ dataType: "number";
556
+ columnType: "PgInteger";
557
+ data: number;
558
+ driverParam: string | number;
559
+ notNull: true;
560
+ hasDefault: false;
561
+ isPrimaryKey: false;
562
+ isAutoincrement: false;
563
+ hasRuntimeDefault: false;
564
+ enumValues: undefined;
565
+ baseColumn: never;
566
+ identity: undefined;
567
+ generated: undefined;
568
+ }, {}, {}>;
569
+ written: import("drizzle-orm/pg-core").PgColumn<{
570
+ name: "written";
571
+ tableName: "plg_sync_runs";
572
+ dataType: "number";
573
+ columnType: "PgInteger";
574
+ data: number;
575
+ driverParam: string | number;
576
+ notNull: true;
577
+ hasDefault: false;
578
+ isPrimaryKey: false;
579
+ isAutoincrement: false;
580
+ hasRuntimeDefault: false;
581
+ enumValues: undefined;
582
+ baseColumn: never;
583
+ identity: undefined;
584
+ generated: undefined;
585
+ }, {}, {}>;
586
+ stats: import("drizzle-orm/pg-core").PgColumn<{
587
+ name: "stats";
588
+ tableName: "plg_sync_runs";
589
+ dataType: "json";
590
+ columnType: "PgJsonb";
591
+ data: unknown;
592
+ driverParam: unknown;
593
+ notNull: true;
594
+ hasDefault: false;
595
+ isPrimaryKey: false;
596
+ isAutoincrement: false;
597
+ hasRuntimeDefault: false;
598
+ enumValues: undefined;
599
+ baseColumn: never;
600
+ identity: undefined;
601
+ generated: undefined;
602
+ }, {}, {}>;
603
+ cursor: import("drizzle-orm/pg-core").PgColumn<{
604
+ name: "cursor";
605
+ tableName: "plg_sync_runs";
606
+ dataType: "string";
607
+ columnType: "PgText";
608
+ data: string;
609
+ driverParam: string;
610
+ notNull: false;
611
+ hasDefault: false;
612
+ isPrimaryKey: false;
613
+ isAutoincrement: false;
614
+ hasRuntimeDefault: false;
615
+ enumValues: [string, ...string[]];
616
+ baseColumn: never;
617
+ identity: undefined;
618
+ generated: undefined;
619
+ }, {}, {}>;
620
+ correlationId: import("drizzle-orm/pg-core").PgColumn<{
621
+ name: "correlation_id";
622
+ tableName: "plg_sync_runs";
623
+ dataType: "string";
624
+ columnType: "PgUUID";
625
+ data: string;
626
+ driverParam: string;
627
+ notNull: false;
628
+ hasDefault: false;
629
+ isPrimaryKey: false;
630
+ isAutoincrement: false;
631
+ hasRuntimeDefault: false;
632
+ enumValues: undefined;
633
+ baseColumn: never;
634
+ identity: undefined;
635
+ generated: undefined;
636
+ }, {}, {}>;
637
+ message: import("drizzle-orm/pg-core").PgColumn<{
638
+ name: "message";
639
+ tableName: "plg_sync_runs";
640
+ dataType: "string";
641
+ columnType: "PgText";
642
+ data: string;
643
+ driverParam: string;
644
+ notNull: false;
645
+ hasDefault: false;
646
+ isPrimaryKey: false;
647
+ isAutoincrement: false;
648
+ hasRuntimeDefault: false;
649
+ enumValues: [string, ...string[]];
650
+ baseColumn: never;
651
+ identity: undefined;
652
+ generated: undefined;
653
+ }, {}, {}>;
654
+ error: import("drizzle-orm/pg-core").PgColumn<{
655
+ name: "error";
656
+ tableName: "plg_sync_runs";
657
+ dataType: "string";
658
+ columnType: "PgText";
659
+ data: string;
660
+ driverParam: string;
661
+ notNull: false;
662
+ hasDefault: false;
663
+ isPrimaryKey: false;
664
+ isAutoincrement: false;
665
+ hasRuntimeDefault: false;
666
+ enumValues: [string, ...string[]];
667
+ baseColumn: never;
668
+ identity: undefined;
669
+ generated: undefined;
670
+ }, {}, {}>;
671
+ startedAt: import("drizzle-orm/pg-core").PgColumn<{
672
+ name: "started_at";
673
+ tableName: "plg_sync_runs";
674
+ dataType: "date";
675
+ columnType: "PgTimestamp";
676
+ data: Date;
677
+ driverParam: string;
678
+ notNull: true;
679
+ hasDefault: false;
680
+ isPrimaryKey: false;
681
+ isAutoincrement: false;
682
+ hasRuntimeDefault: false;
683
+ enumValues: undefined;
684
+ baseColumn: never;
685
+ identity: undefined;
686
+ generated: undefined;
687
+ }, {}, {}>;
688
+ finishedAt: import("drizzle-orm/pg-core").PgColumn<{
689
+ name: "finished_at";
690
+ tableName: "plg_sync_runs";
691
+ dataType: "date";
692
+ columnType: "PgTimestamp";
693
+ data: Date;
694
+ driverParam: string;
695
+ notNull: false;
696
+ hasDefault: false;
697
+ isPrimaryKey: false;
698
+ isAutoincrement: false;
699
+ hasRuntimeDefault: false;
700
+ enumValues: undefined;
701
+ baseColumn: never;
702
+ identity: undefined;
703
+ generated: undefined;
704
+ }, {}, {}>;
705
+ };
706
+ dialect: "pg";
707
+ }>;
155
708
  //# sourceMappingURL=spine.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spine.d.ts","sourceRoot":"","sources":["../../src/schema/spine.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;EAElB,CAAA;AAEF,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;EAEjB,CAAA;AAEF,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;EAEjB,CAAA;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;EAEvB,CAAA;AAEF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;EAEnB,CAAA;AAEF,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;EAErB,CAAA"}
1
+ {"version":3,"file":"spine.d.ts","sourceRoot":"","sources":["../../src/schema/spine.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;EAElB,CAAA;AAEF,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;EAEjB,CAAA;AAEF,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;EAEjB,CAAA;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;EAEvB,CAAA;AAEF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;EAEnB,CAAA;AAEF,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;EAErB,CAAA;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAezB,CAAA;AAEF,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsBtB,CAAA"}
@@ -0,0 +1,75 @@
1
+ -- ============================================================================
2
+ -- 025_created_by.sql — quem cadastrou.
3
+ --
4
+ -- Toda tabela do core já nasceu com `created_at` e `updated_at` (001_core,
5
+ -- 004_archetypes) e um gatilho que mantém o segundo em dia. Nenhuma nasceu com
6
+ -- QUEM. A ficha de um cliente sabia dizer o dia em que foi criada e não sabia
7
+ -- dizer por quem — a pergunta que sempre vem depois de "esse cadastro está
8
+ -- errado" é "quem cadastrou", e ela não tinha resposta em lugar nenhum: o
9
+ -- `audit_logs` de 001_core existe como tabela e nunca recebeu uma linha.
10
+ --
11
+ -- A coluna é NULÁVEL e fica assim de propósito:
12
+ --
13
+ -- • as linhas que já existem não têm autor, e nunca terão — inventar um
14
+ -- (o dono do tenant, o primeiro membro) seria fabricar procedência, que é
15
+ -- exatamente o oposto do que a coluna serve para dar. Elas ficam em branco
16
+ -- e a interface omite a frase.
17
+ --
18
+ -- • nem toda escrita tem gente atrás. Importação de CSV, webhook, seed,
19
+ -- job do agente: `auth.uid()` é NULL nesses caminhos, e NULL aqui quer
20
+ -- dizer "o sistema", que é a verdade.
21
+ --
22
+ -- O DEFAULT vem por gatilho e não por `DEFAULT auth.uid()` na coluna porque o
23
+ -- `service_role` (edge functions, backfills) precisa poder gravar um autor
24
+ -- explícito; com o default na coluna, escrever NULL de propósito e "não
25
+ -- escrever nada" viram a mesma coisa e o COALESCE não teria onde morar.
26
+ --
27
+ -- Aditivo e idempotente: ADD COLUMN IF NOT EXISTS de coluna nulável não
28
+ -- reescreve a tabela (PG 11+), e os gatilhos são recriados por DROP IF EXISTS.
29
+ -- ============================================================================
30
+
31
+ CREATE OR REPLACE FUNCTION public.handle_created_by()
32
+ RETURNS trigger
33
+ LANGUAGE plpgsql
34
+ SECURITY DEFINER
35
+ SET search_path = public
36
+ AS $$
37
+ BEGIN
38
+ -- COALESCE e não atribuição direta: uma migração de dados ou uma função de
39
+ -- servidor que JÁ sabe o autor (importou em nome de alguém) manda o valor
40
+ -- certo, e o gatilho não o sobrescreve com o NULL de um contexto sem sessão.
41
+ NEW.created_by := COALESCE(NEW.created_by, auth.uid());
42
+ RETURN NEW;
43
+ END;
44
+ $$;
45
+
46
+ REVOKE ALL ON FUNCTION public.handle_created_by() FROM public;
47
+ REVOKE ALL ON FUNCTION public.handle_created_by() FROM anon;
48
+
49
+ DO $$
50
+ DECLARE
51
+ t text;
52
+ -- As bases de arquétipo (004_archetypes) mais as tabelas de core que um CRUD
53
+ -- desenha como ficha. Tabelas de junção, ledger e evento ficam de fora: elas
54
+ -- já carregam o ator no próprio corpo ou não têm ficha para mostrá-lo.
55
+ tables text[] := ARRAY[
56
+ 'people', 'categories', 'products', 'services', 'locations',
57
+ 'orders', 'transactions', 'schedules', 'appointments'
58
+ ];
59
+ BEGIN
60
+ FOREACH t IN ARRAY tables LOOP
61
+ IF to_regclass('public.' || t) IS NULL THEN
62
+ CONTINUE;
63
+ END IF;
64
+
65
+ EXECUTE format(
66
+ 'ALTER TABLE public.%I ADD COLUMN IF NOT EXISTS created_by uuid REFERENCES auth.users(id) ON DELETE SET NULL',
67
+ t
68
+ );
69
+ EXECUTE format('DROP TRIGGER IF EXISTS %I ON public.%I', t || '_created_by', t);
70
+ EXECUTE format(
71
+ 'CREATE TRIGGER %I BEFORE INSERT ON public.%I FOR EACH ROW EXECUTE FUNCTION public.handle_created_by()',
72
+ t || '_created_by', t
73
+ );
74
+ END LOOP;
75
+ END $$;