@fayz-ai/plugin-agenda 0.3.0 → 0.8.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 (36) hide show
  1. package/README.md +2 -0
  2. package/dist/bridges/create-financial-bridge.d.ts.map +1 -1
  3. package/dist/config.d.ts +2 -2
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/data/supabase.d.ts.map +1 -1
  6. package/dist/index.cjs +77 -65
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.js +77 -65
  9. package/dist/index.js.map +1 -1
  10. package/dist/migrations/index.d.ts +8 -1
  11. package/dist/migrations/index.d.ts.map +1 -1
  12. package/dist/public/createPublicBookingPlugin.d.ts.map +1 -1
  13. package/dist/public/index.cjs +16 -16
  14. package/dist/public/index.cjs.map +1 -1
  15. package/dist/public/index.js +17 -17
  16. package/dist/public/index.js.map +1 -1
  17. package/dist/registries.d.ts.map +1 -1
  18. package/dist/types.d.ts +3 -3
  19. package/dist/types.d.ts.map +1 -1
  20. package/package.json +20 -14
  21. package/src/bridges/create-financial-bridge.ts +6 -8
  22. package/src/components/AppointmentModal.tsx +4 -4
  23. package/src/config.ts +2 -2
  24. package/src/data/supabase.ts +26 -25
  25. package/src/index.ts +1 -1
  26. package/src/integrations/google-calendar/index.ts +1 -1
  27. package/src/integrations/google-calendar/migrations/001_google_calendar.sql +6 -6
  28. package/src/migrations/000b_v_bookings_rename.sql +21 -0
  29. package/src/migrations/000c_dedupe_customer_phones.sql +43 -0
  30. package/src/migrations/001_public_booking.sql +40 -27
  31. package/src/migrations/002_v_bookings_compat.sql +14 -0
  32. package/src/migrations/index.ts +134 -29
  33. package/src/public/createPublicBookingPlugin.ts +23 -20
  34. package/src/public/data.supabase.ts +4 -4
  35. package/src/registries.ts +1 -2
  36. package/src/types.ts +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"registries.d.ts","sourceRoot":"","sources":["../src/registries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AA4BtD,eAAO,MAAM,gBAAgB,EAAE,iBAAiB,EAO/C,CAAA"}
1
+ {"version":3,"file":"registries.d.ts","sourceRoot":"","sources":["../src/registries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AA2BtD,eAAO,MAAM,gBAAgB,EAAE,iBAAiB,EAO/C,CAAA"}
package/dist/types.d.ts CHANGED
@@ -23,7 +23,7 @@ export interface BookingTypeConfig {
23
23
  requiresServices: boolean;
24
24
  requiresClient: boolean;
25
25
  }
26
- /** A booking service line item (from saas_core.booking_items) */
26
+ /** A booking service line item (from public.appointment_items) */
27
27
  export interface BookingService {
28
28
  id: string;
29
29
  serviceId: string | null;
@@ -32,7 +32,7 @@ export interface BookingService {
32
32
  price: number;
33
33
  assigneeId: string | null;
34
34
  }
35
- /** Calendar booking — the main entity rendered on the calendar (from v_bookings view on orders) */
35
+ /** Calendar booking — the main entity rendered on the calendar (from v_appointments view on orders) */
36
36
  export interface CalendarBooking {
37
37
  id: string;
38
38
  tenantId: string;
@@ -76,7 +76,7 @@ export interface Professional {
76
76
  locationName: string | null;
77
77
  isActive: boolean;
78
78
  }
79
- /** Working hours schedule (from saas_core.schedules) */
79
+ /** Working hours schedule (from public.schedules) */
80
80
  export interface Schedule {
81
81
  id: string;
82
82
  tenantId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AASA,+BAA+B;AAC/B,MAAM,MAAM,aAAa,GACrB,WAAW,GACX,WAAW,GACX,aAAa,GACb,WAAW,GACX,WAAW,GACX,SAAS,CAAA;AAEb,mCAAmC;AACnC,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,CAAA;AAE9E,oEAAoE;AACpE,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,MAAM,GAAG,eAAe,GAAG,OAAO,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAE9F,oDAAoD;AACpD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,aAAa,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE;QACN;+EACuE;QACvE,KAAK,CAAC,EAAE,OAAO,CAAA;QACf,MAAM,EAAE,OAAO,CAAA;QACf,YAAY,EAAE,OAAO,CAAA;QACrB,QAAQ,EAAE,OAAO,CAAA;QACjB,QAAQ,EAAE,OAAO,CAAA;QACjB,MAAM,EAAE,OAAO,CAAA;KAChB,CAAA;IACD,gBAAgB,EAAE,OAAO,CAAA;IACzB,cAAc,EAAE,OAAO,CAAA;CACxB;AAMD,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,eAAe,EAAE,MAAM,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED,uGAAuG;AACvG,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,MAAM,EAAE,aAAa,CAAA;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,kEAAkE;IAClE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAGjC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAG9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAA;IAGpC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAG3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,iEAAiE;IACjE,aAAa,CAAC,EAAE,OAAO,oBAAoB,EAAE,oBAAoB,CAAA;IAGjE,QAAQ,EAAE,cAAc,EAAE,GAAG,IAAI,CAAA;IACjC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;IAEnC,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,qDAAqD;AACrD,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC;AAED,0BAA0B;AAC1B,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,qDAAqD;AACrD,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,kBAAkB,CAAA;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAMD;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,eAAe,GAAG,YAAY,CAAA;AAE1E,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,2DAA2D;IAC3D,aAAa,CAAC,EAAE,kBAAkB,CAAA;CACnC;AAED,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAQxF;AAMD,wDAAwD;AACxD,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACzE,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAA;IAC1C,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAA;IACpD,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAA;CAC7F;AAMD,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;iEAC6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,yBAAyB,EAAE,CAAA;CACtC;AAED,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,eAAe,EAAE,MAAM,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,aAAa,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,yBAAyB,EAAE,CAAA;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC;AAMD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IACzC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,eAAe,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB"}
package/package.json CHANGED
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "name": "@fayz-ai/plugin-agenda",
3
- "version": "0.3.0",
3
+ "fayz": {
4
+ "status": "beta"
5
+ },
6
+ "version": "0.8.0",
4
7
  "description": "Fayz SDK — plugin-agenda plugin",
5
8
  "type": "module",
6
9
  "main": "./dist/index.cjs",
@@ -29,29 +32,29 @@
29
32
  "react-dom": "^18.0.0 || ^19.0.0"
30
33
  },
31
34
  "dependencies": {
35
+ "lucide-react": "^0.400.0",
36
+ "zustand": "^4.5.0",
32
37
  "@fullcalendar/core": "^6.1.20",
33
38
  "@fullcalendar/daygrid": "^6.1.20",
34
- "@fullcalendar/interaction": "^6.1.20",
35
- "@fullcalendar/list": "^6.1.0",
36
- "@fullcalendar/react": "^6.1.20",
37
- "@fullcalendar/resource-timegrid": "^6.1.0",
38
39
  "@fullcalendar/timegrid": "^6.1.20",
40
+ "@fullcalendar/react": "^6.1.20",
41
+ "@fullcalendar/interaction": "^6.1.20",
39
42
  "@tanstack/react-table": "^8.20.0",
40
- "lucide-react": "^0.400.0",
41
- "zustand": "^4.5.0",
42
- "@fayz-ai/plugin-financial": "^0.2.0",
43
- "@fayz-ai/saas": "^0.7.0",
44
- "@fayz-ai/ui": "^0.7.0",
45
- "@fayz-ai/core": "^0.7.1"
43
+ "@fullcalendar/resource-timegrid": "^6.1.0",
44
+ "@fullcalendar/list": "^6.1.0",
45
+ "@fayz-ai/saas": "^0.8.0",
46
+ "@fayz-ai/ui": "^0.8.0",
47
+ "@fayz-ai/core": "^0.8.0",
48
+ "@fayz-ai/plugin-financial": "^0.8.0"
46
49
  },
47
50
  "devDependencies": {
48
51
  "@types/react": "^18.3.0",
49
- "@types/react-dom": "^18.3.0",
50
52
  "react": "^18.3.0",
51
- "react-dom": "^18.3.0",
52
53
  "tsup": "^8.2.0",
53
54
  "typescript": "^5.5.0",
54
- "vitest": "^2.1.9"
55
+ "@types/react-dom": "^18.3.0",
56
+ "vitest": "^2.1.9",
57
+ "react-dom": "^18.3.0"
55
58
  },
56
59
  "license": "MIT",
57
60
  "keywords": [
@@ -59,6 +62,9 @@
59
62
  "fayz-plugin",
60
63
  "fayz-sdk"
61
64
  ],
65
+ "publishConfig": {
66
+ "access": "public"
67
+ },
62
68
  "scripts": {
63
69
  "build": "tsup && tsc --emitDeclarationOnly --declaration --declarationMap --noEmit false",
64
70
  "dev": "tsup --watch",
@@ -54,12 +54,11 @@ export function createFinancialBridge(provider: FinancialDataProvider): AgendaFi
54
54
  try {
55
55
  const [{ data: orders }, { data: movements }] = await Promise.all([
56
56
  supabase
57
- .schema('saas_core')
58
57
  .from('orders')
59
58
  .select('id, kind, status, total, reference_number, metadata')
60
59
  .in('id', orderIds),
61
60
  supabase
62
- .from('financial_movements')
61
+ .from('plg_financial_movements')
63
62
  .select('invoice_id, status, paid_amount')
64
63
  .in('invoice_id', orderIds),
65
64
  ])
@@ -97,8 +96,8 @@ export function createFinancialBridge(provider: FinancialDataProvider): AgendaFi
97
96
 
98
97
  // Single query: get order + movements in parallel
99
98
  const [orderRes, movRes] = await Promise.all([
100
- supabase.schema('saas_core').from('orders').select('id, status, total, reference_number, metadata').eq('id', orderId).single(),
101
- supabase.from('financial_movements').select('*').eq('invoice_id', orderId).order('due_date'),
99
+ supabase.from('orders').select('id, status, total, reference_number, metadata').eq('id', orderId).single(),
100
+ supabase.from('plg_financial_movements').select('*').eq('invoice_id', orderId).order('due_date'),
102
101
  ])
103
102
 
104
103
  const order = orderRes.data
@@ -109,7 +108,7 @@ export function createFinancialBridge(provider: FinancialDataProvider): AgendaFi
109
108
  const typeIds = [...new Set((movRes.data ?? []).map((m: any) => m.payment_method_type_id).filter(Boolean))]
110
109
  let typeNames: Record<string, string> = {}
111
110
  if (typeIds.length > 0) {
112
- const { data: types } = await supabase.from('payment_method_types').select('id, name').in('id', typeIds)
111
+ const { data: types } = await supabase.from('plg_financial_payment_method_types').select('id, name').in('id', typeIds)
113
112
  typeNames = Object.fromEntries((types ?? []).map((t: any) => [t.id, t.name]))
114
113
  }
115
114
 
@@ -176,7 +175,6 @@ export function createFinancialBridge(provider: FinancialDataProvider): AgendaFi
176
175
 
177
176
  // Order carries the assigned professional (assignee_id) and realized total.
178
177
  const { data: order } = await supabase
179
- .schema('saas_core')
180
178
  .from('orders')
181
179
  .select('id, tenant_id, assignee_id, total')
182
180
  .eq('id', orderId)
@@ -197,7 +195,7 @@ export function createFinancialBridge(provider: FinancialDataProvider): AgendaFi
197
195
 
198
196
  // Idempotent: one commission accrual per order. Reuse if already present.
199
197
  const { data: existing } = await supabase
200
- .from('financial_movements')
198
+ .from('plg_financial_movements')
201
199
  .select('id')
202
200
  .eq('invoice_id', orderId)
203
201
  .eq('movement_kind', 'commission')
@@ -207,7 +205,7 @@ export function createFinancialBridge(provider: FinancialDataProvider): AgendaFi
207
205
  const dueDate = options?.dueDate ?? new Date().toISOString().slice(0, 10)
208
206
 
209
207
  const { data: inserted } = await supabase
210
- .from('financial_movements')
208
+ .from('plg_financial_movements')
211
209
  .insert({
212
210
  tenant_id: order.tenant_id,
213
211
  invoice_id: orderId,
@@ -724,7 +724,7 @@ export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, e
724
724
  for (const [k, v] of Object.entries(data)) {
725
725
  dbData[k.replace(/[A-Z]/g, (m) => '_' + m.toLowerCase())] = v
726
726
  }
727
- await supabase.schema('saas_core').from('persons').update(dbData).eq('id', clientId)
727
+ await supabase.from('people').update(dbData).eq('id', clientId)
728
728
  setClientData({ ...clientData, ...data })
729
729
  setClientEditing(false)
730
730
  } catch { /* toast */ }
@@ -851,8 +851,8 @@ export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, e
851
851
  const tenantId = getAgendaTenantId()
852
852
  if (!supabase || !tenantId) throw new Error('Not initialized')
853
853
 
854
- // 1. Insert into saas_core.persons (archetype table)
855
- const { data: personRow, error: personError } = await supabase.schema('saas_core').from('persons').insert({
854
+ // 1. Insert into public.people (archetype base table)
855
+ const { data: personRow, error: personError } = await supabase.from('people').insert({
856
856
  tenant_id: tenantId, kind: config.clientKind, name: newClientName.trim(),
857
857
  phone: newClientPhone.trim() || null, email: newClientEmail.trim() || null,
858
858
  }).select('id, name').single()
@@ -864,7 +864,7 @@ export function AppointmentModal({ open, mode, bookingId, prefill, initialTab, e
864
864
  })
865
865
  if (clientError) {
866
866
  // Rollback person if extension insert fails
867
- await supabase.schema('saas_core').from('persons').delete().eq('id', personRow.id)
867
+ await supabase.from('people').delete().eq('id', personRow.id)
868
868
  throw clientError
869
869
  }
870
870
 
package/src/config.ts CHANGED
@@ -70,13 +70,13 @@ export interface AgendaPluginOptions {
70
70
  labels?: Partial<AgendaPluginLabels>
71
71
  currency?: { code?: string; locale?: string; symbol?: string }
72
72
 
73
- /** Booking kind used in saas_core.bookings.kind (default: 'appointment') */
73
+ /** Booking kind used in public.appointments.kind (default: 'appointment') */
74
74
  bookingKind?: string
75
75
 
76
76
  /** Order kind for financial records (default: 'service_order') */
77
77
  orderKind?: string
78
78
 
79
- /** Schedule kind in saas_core.schedules.kind (default: 'working_hours') */
79
+ /** Schedule kind in public.schedules.kind (default: 'working_hours') */
80
80
  scheduleKind?: string
81
81
 
82
82
  /** Booking type tabs shown in the appointment modal */
@@ -28,7 +28,8 @@ function snakeToCamel(obj: Record<string, unknown>): Record<string, unknown> {
28
28
  function getClients() {
29
29
  const supabase = getSupabaseClientOptional() as any
30
30
  if (!supabase) throw new Error('Supabase not initialized')
31
- return { core: supabase.schema('saas_core'), pub: supabase }
31
+ // Core v1 lives in PUBLIC — a single client serves both core and view reads.
32
+ return { core: supabase, pub: supabase }
32
33
  }
33
34
 
34
35
  function mapBooking(row: Record<string, unknown>): CalendarBooking {
@@ -97,7 +98,7 @@ async function hydrateCanonicalBookings(core: any, bookings: any[]): Promise<Cal
97
98
  { data: items, error: itemsError },
98
99
  ] = await Promise.all([
99
100
  personIds.length
100
- ? core.from('persons').select('id, name, phone, email, avatar_url').in('id', personIds)
101
+ ? core.from('people').select('id, name, phone, email, avatar_url').in('id', personIds)
101
102
  : Promise.resolve({ data: [], error: null }),
102
103
  locationIds.length
103
104
  ? core.from('locations').select('id, name').in('id', locationIds)
@@ -170,7 +171,7 @@ async function hydrateCanonicalBookings(core: any, bookings: any[]): Promise<Cal
170
171
  }
171
172
 
172
173
  async function getCanonicalBookings(core: any, query: BookingQuery): Promise<CalendarBooking[]> {
173
- let q = core.from('bookings')
174
+ let q = core.from('appointments')
174
175
  .select('id, tenant_id, kind, starts_at, ends_at, status, notes, order_id, location_id, metadata, party_id, assignee_id, created_at, updated_at')
175
176
  .gte('starts_at', query.dateRange.start)
176
177
  .lte('starts_at', query.dateRange.end)
@@ -187,11 +188,11 @@ async function getCanonicalBookings(core: any, query: BookingQuery): Promise<Cal
187
188
 
188
189
  async function getCanonicalBookingById(core: any, id: string): Promise<CalendarBooking | null> {
189
190
  const columns = 'id, tenant_id, kind, starts_at, ends_at, status, notes, order_id, location_id, metadata, party_id, assignee_id, created_at, updated_at'
190
- let { data, error } = await core.from('bookings').select(columns).eq('id', id).maybeSingle()
191
+ let { data, error } = await core.from('appointments').select(columns).eq('id', id).maybeSingle()
191
192
  if (error) throw error
192
193
 
193
194
  if (!data) {
194
- const fallback = await core.from('bookings').select(columns).eq('order_id', id).maybeSingle()
195
+ const fallback = await core.from('appointments').select(columns).eq('order_id', id).maybeSingle()
195
196
  if (fallback.error) throw fallback.error
196
197
  data = fallback.data
197
198
  }
@@ -207,10 +208,10 @@ async function getCanonicalBookingById(core: any, id: string): Promise<CalendarB
207
208
 
208
209
  export function createSupabaseAgendaProvider(): AgendaDataProvider {
209
210
  return {
210
- // v_bookings is in public schema (PostgREST default)
211
+ // v_appointments is in public schema (PostgREST default)
211
212
  async getBookings(query: BookingQuery): Promise<CalendarBooking[]> {
212
213
  const { core, pub } = getClients()
213
- let q = pub.from('v_bookings').select('*')
214
+ let q = pub.from('v_appointments').select('*')
214
215
  .gte('starts_at', query.dateRange.start)
215
216
  .lte('starts_at', query.dateRange.end)
216
217
 
@@ -230,7 +231,7 @@ export function createSupabaseAgendaProvider(): AgendaDataProvider {
230
231
 
231
232
  async getBookingById(id: string): Promise<CalendarBooking | null> {
232
233
  const { core, pub } = getClients()
233
- const { data, error } = await pub.from('v_bookings').select('*').eq('id', id).maybeSingle()
234
+ const { data, error } = await pub.from('v_appointments').select('*').eq('id', id).maybeSingle()
234
235
  if (error) throw error
235
236
  if (data) return mapBooking(data as Record<string, unknown>)
236
237
  return getCanonicalBookingById(core, id)
@@ -250,7 +251,7 @@ export function createSupabaseAgendaProvider(): AgendaDataProvider {
250
251
  // Resolve client name for metadata (used by financial detail view)
251
252
  let contactName: string | undefined
252
253
  if (input.clientId) {
253
- const { data: person } = await core.from('persons').select('name').eq('id', input.clientId).single()
254
+ const { data: person } = await core.from('people').select('name').eq('id', input.clientId).single()
254
255
  contactName = person?.name as string | undefined
255
256
  }
256
257
 
@@ -277,7 +278,7 @@ export function createSupabaseAgendaProvider(): AgendaDataProvider {
277
278
  }).select('id').single()
278
279
  if (orderErr) throw orderErr
279
280
 
280
- const { data: booking, error: bookingErr } = await core.from('bookings').insert({
281
+ const { data: booking, error: bookingErr } = await core.from('appointments').insert({
281
282
  tenant_id: tenantId,
282
283
  kind: input.kind ?? 'appointment',
283
284
  party_id: input.clientId || null,
@@ -321,7 +322,7 @@ export function createSupabaseAgendaProvider(): AgendaDataProvider {
321
322
 
322
323
  async updateBooking(id: string, data: UpdateBookingInput): Promise<CalendarBooking> {
323
324
  const { core } = getClients()
324
- const { data: existing, error: existingErr } = await core.from('bookings')
325
+ const { data: existing, error: existingErr } = await core.from('appointments')
325
326
  .select('id, order_id, starts_at, assignee_id, metadata')
326
327
  .eq('id', id)
327
328
  .single()
@@ -357,7 +358,7 @@ export function createSupabaseAgendaProvider(): AgendaDataProvider {
357
358
 
358
359
  const effectiveAssigneeId = data.professionalId ?? (existing?.assignee_id as string | null | undefined) ?? null
359
360
 
360
- const { error } = await core.from('bookings').update(updates).eq('id', id)
361
+ const { error } = await core.from('appointments').update(updates).eq('id', id)
361
362
  if (error) throw error
362
363
 
363
364
  // S4: services are updated only in order_items below (booking_items deprecated).
@@ -405,7 +406,7 @@ export function createSupabaseAgendaProvider(): AgendaDataProvider {
405
406
 
406
407
  async deleteBooking(id: string): Promise<void> {
407
408
  const { core, pub } = getClients()
408
- const { data: booking, error: bookingErr } = await core.from('bookings')
409
+ const { data: booking, error: bookingErr } = await core.from('appointments')
409
410
  .select('order_id')
410
411
  .eq('id', id)
411
412
  .single()
@@ -413,22 +414,22 @@ export function createSupabaseAgendaProvider(): AgendaDataProvider {
413
414
 
414
415
  const orderId = booking?.order_id as string | null | undefined
415
416
  const { count, error: movementErr } = orderId
416
- ? await pub.from('financial_movements').select('id', { count: 'exact', head: true }).eq('invoice_id', orderId)
417
+ ? await pub.from('plg_financial_movements').select('id', { count: 'exact', head: true }).eq('invoice_id', orderId)
417
418
  : { count: 0, error: null }
418
419
  if (movementErr) throw movementErr
419
420
 
420
421
  if (orderId && (count ?? 0) > 0) {
421
422
  // Cancel movements + order (don't delete financial records)
422
- await pub.from('financial_movements').update({ status: 'cancelled' }).eq('invoice_id', orderId)
423
+ await pub.from('plg_financial_movements').update({ status: 'cancelled' }).eq('invoice_id', orderId)
423
424
  await core.from('orders').update({ status: 'cancelled' }).eq('id', orderId)
424
- const { error } = await core.from('bookings').update({ status: 'cancelled' }).eq('id', id)
425
+ const { error } = await core.from('appointments').update({ status: 'cancelled' }).eq('id', id)
425
426
  if (error) throw error
426
427
  } else {
427
428
  // Safe to delete — remove any movements first (FK constraint)
428
429
  if (orderId) {
429
- await pub.from('financial_movements').delete().eq('invoice_id', orderId)
430
+ await pub.from('plg_financial_movements').delete().eq('invoice_id', orderId)
430
431
  }
431
- const { error } = await core.from('bookings').delete().eq('id', id)
432
+ const { error } = await core.from('appointments').delete().eq('id', id)
432
433
  if (error) throw error
433
434
  if (orderId) {
434
435
  const { error: orderErr } = await core.from('orders').delete().eq('id', orderId)
@@ -443,7 +444,7 @@ export function createSupabaseAgendaProvider(): AgendaDataProvider {
443
444
 
444
445
  async checkConflict(params: ConflictCheckParams): Promise<boolean> {
445
446
  const { core } = getClients()
446
- let q = core.from('bookings').select('id', { count: 'exact', head: true })
447
+ let q = core.from('appointments').select('id', { count: 'exact', head: true })
447
448
  .eq('assignee_id', params.assigneeId)
448
449
  .eq('kind', 'appointment')
449
450
  .not('status', 'in', '("cancelled","no_show")')
@@ -513,7 +514,7 @@ export function createSupabaseAgendaProvider(): AgendaDataProvider {
513
514
 
514
515
  async getProfessionals(): Promise<Professional[]> {
515
516
  const { core } = getClients()
516
- const { data, error } = await core.from('persons')
517
+ const { data, error } = await core.from('people')
517
518
  .select('id, name, avatar_url, is_active')
518
519
  .eq('kind', 'staff')
519
520
  .eq('is_active', true)
@@ -541,7 +542,7 @@ export function createSupabaseAgendaProvider(): AgendaDataProvider {
541
542
  const cutoff = new Date()
542
543
  cutoff.setDate(cutoff.getDate() + daysAhead)
543
544
 
544
- const { data, error } = await pub.from('v_bookings').select('*')
545
+ const { data, error } = await pub.from('v_appointments').select('*')
545
546
  .eq('status', 'scheduled')
546
547
  .gte('starts_at', now)
547
548
  .lte('starts_at', cutoff.toISOString())
@@ -552,22 +553,22 @@ export function createSupabaseAgendaProvider(): AgendaDataProvider {
552
553
 
553
554
  async sendConfirmation(bookingId: string, channel: string): Promise<void> {
554
555
  const { core } = getClients()
555
- const { data: booking } = await core.from('bookings').select('metadata').eq('id', bookingId).single()
556
+ const { data: booking } = await core.from('appointments').select('metadata').eq('id', bookingId).single()
556
557
  const metadata = (booking?.metadata ?? {}) as Record<string, unknown>
557
558
  const confirmations = (metadata.confirmations as any[] ?? [])
558
559
  confirmations.push({ channel, sentAt: new Date().toISOString(), status: 'sent' })
559
- await core.from('bookings').update({ metadata: { ...metadata, confirmations } }).eq('id', bookingId)
560
+ await core.from('appointments').update({ metadata: { ...metadata, confirmations } }).eq('id', bookingId)
560
561
  },
561
562
 
562
563
  async completeBooking(bookingId: string): Promise<{ booking: CalendarBooking; orderId: string }> {
563
564
  const { core } = getClients()
564
- const { data: existing, error: existingErr } = await core.from('bookings')
565
+ const { data: existing, error: existingErr } = await core.from('appointments')
565
566
  .select('order_id')
566
567
  .eq('id', bookingId)
567
568
  .single()
568
569
  if (existingErr) throw existingErr
569
570
 
570
- const { error } = await core.from('bookings')
571
+ const { error } = await core.from('appointments')
571
572
  .update({ status: 'completed' })
572
573
  .eq('id', bookingId)
573
574
  if (error) throw error
package/src/index.ts CHANGED
@@ -186,7 +186,7 @@ export function createAgendaPlugin(options?: AgendaPluginOptions): PluginManifes
186
186
  version: '0.3.0',
187
187
  sql: MIGRATION_001_PUBLIC_BOOKING,
188
188
  description:
189
- 'Booking read model (v_bookings) + anon public booking surface (v_public_services, get_available_slots, create_public_booking) + order_items duration/assignee columns',
189
+ 'Booking read model (v_appointments) + anon public booking surface (v_public_services, get_available_slots, create_public_booking) + order_items duration/assignee columns',
190
190
  },
191
191
  ],
192
192
 
@@ -5,7 +5,7 @@
5
5
  // Google) is automatic via a DB trigger; inbound (Google → booking) via pg_cron
6
6
  // or a Google watch webhook. The data plane is the google-calendar-sync edge
7
7
  // function (see ./functions/google-calendar-sync). The booking↔event link lives
8
- // on saas_core.bookings.metadata.googleCalendarEventId.
8
+ // on public.appointments.metadata.googleCalendarEventId.
9
9
  //
10
10
  // Graduation path: extract to its own `@fayz-ai/plugin-google-calendar` package.
11
11
  import type { PluginManifest } from '@fayz-ai/core'
@@ -1,15 +1,15 @@
1
1
  -- ---------------------------------------------------------------------------
2
2
  -- Google Calendar integration (bidirectional) — connection + audit + triggers
3
3
  -- ---------------------------------------------------------------------------
4
- -- Outbound (Fayz booking → Google event) fires from a trigger on saas_core.bookings
4
+ -- Outbound (Fayz booking → Google event) fires from a trigger on public.appointments
5
5
  -- via pg_net to the google-calendar-sync edge function (push_event). Inbound
6
6
  -- (Google → booking) runs on a pg_cron schedule (pull_events) and/or a Google
7
7
  -- watch-channel webhook. The booking↔event link is stored on
8
- -- saas_core.bookings.metadata.googleCalendarEventId (no schema change there).
8
+ -- public.appointments.metadata.googleCalendarEventId (no schema change there).
9
9
 
10
10
  CREATE TABLE IF NOT EXISTS public.calendar_integrations (
11
11
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
12
- tenant_id uuid NOT NULL REFERENCES saas_core.tenants(id) ON DELETE CASCADE,
12
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
13
13
  provider text NOT NULL DEFAULT 'google',
14
14
  oauth_refresh_token text,
15
15
  oauth_access_token text,
@@ -31,7 +31,7 @@ CREATE INDEX IF NOT EXISTS idx_calendar_integrations_tenant ON public.calendar_i
31
31
 
32
32
  CREATE TABLE IF NOT EXISTS public.calendar_sync_log (
33
33
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
34
- tenant_id uuid NOT NULL REFERENCES saas_core.tenants(id) ON DELETE CASCADE,
34
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
35
35
  direction text NOT NULL, -- inbound | outbound
36
36
  trigger text, -- on-write | scheduled | webhook | manual
37
37
  status text NOT NULL DEFAULT 'success', -- success | partial | error
@@ -80,9 +80,9 @@ BEGIN
80
80
  RETURN COALESCE(NEW, OLD);
81
81
  END $$;
82
82
 
83
- DROP TRIGGER IF EXISTS trg_gcal_push ON saas_core.bookings;
83
+ DROP TRIGGER IF EXISTS trg_gcal_push ON public.appointments;
84
84
  CREATE TRIGGER trg_gcal_push
85
- AFTER INSERT OR UPDATE OR DELETE ON saas_core.bookings
85
+ AFTER INSERT OR UPDATE OR DELETE ON public.appointments
86
86
  FOR EACH ROW EXECUTE FUNCTION public.fn_gcal_push_booking();
87
87
 
88
88
  -- Inbound schedule (optional): pull external changes every 10 minutes.
@@ -0,0 +1,21 @@
1
+ -- Salon-only unblock: the pre-pools beauty deployment built rep_* report
2
+ -- views on top of its (wider) v_bookings view, so 001's cleanup DROP cannot
3
+ -- run there. Renaming keeps the dependents attached (they track the OID) and
4
+ -- frees the name for 001; 002_v_bookings_compat re-creates v_bookings as a
5
+ -- thin alias for live pre-M5 clients. No-op on fresh pools and on pools whose
6
+ -- v_bookings has no dependents (001's DROP handles those).
7
+
8
+ DO $rename$
9
+ BEGIN
10
+ IF to_regclass('public.v_bookings') IS NOT NULL
11
+ AND to_regclass('public.v_bookings_legacy_beauty') IS NULL
12
+ AND EXISTS (
13
+ SELECT 1 FROM pg_depend d
14
+ JOIN pg_rewrite rw ON rw.oid = d.objid
15
+ JOIN pg_class dep ON dep.oid = rw.ev_class
16
+ JOIN pg_class ref ON ref.oid = d.refobjid
17
+ WHERE ref.relname = 'v_bookings' AND dep.relname <> 'v_bookings'
18
+ ) THEN
19
+ EXECUTE 'ALTER VIEW public.v_bookings RENAME TO v_bookings_legacy_beauty';
20
+ END IF;
21
+ END $rename$;
@@ -0,0 +1,43 @@
1
+ -- 001 needs the customer-phone upsert key UNIQUE(tenant_id, phone). Converted
2
+ -- pools can carry duplicates (found live on salon: 9 dogfood test records all
3
+ -- sharing the founder's phone). Non-destructive dedupe: per (tenant_id, phone)
4
+ -- customer group keep the row with most appointments (tie: oldest), NULL the
5
+ -- phone on the rest and stash the original in metadata->'dedupedPhone'.
6
+ -- Idempotent: reruns find no groups > 1.
7
+
8
+ DO $dedupe$
9
+ DECLARE
10
+ r record;
11
+ BEGIN
12
+ IF to_regclass('public.people') IS NULL THEN
13
+ RETURN;
14
+ END IF;
15
+
16
+ FOR r IN
17
+ SELECT p.id, p.phone
18
+ FROM public.people p
19
+ JOIN LATERAL (
20
+ SELECT count(*) AS appts
21
+ FROM public.appointments a WHERE a.party_id = p.id
22
+ ) ac ON true
23
+ WHERE p.kind = 'customer' AND p.phone IS NOT NULL
24
+ AND p.id NOT IN (
25
+ SELECT DISTINCT ON (p2.tenant_id, p2.phone) p2.id
26
+ FROM public.people p2
27
+ WHERE p2.kind = 'customer' AND p2.phone IS NOT NULL
28
+ ORDER BY p2.tenant_id, p2.phone,
29
+ (SELECT count(*) FROM public.appointments a2 WHERE a2.party_id = p2.id) DESC,
30
+ p2.created_at ASC
31
+ )
32
+ AND (p.tenant_id, p.phone) IN (
33
+ SELECT tenant_id, phone FROM public.people
34
+ WHERE kind = 'customer' AND phone IS NOT NULL
35
+ GROUP BY tenant_id, phone HAVING count(*) > 1
36
+ )
37
+ LOOP
38
+ UPDATE public.people
39
+ SET metadata = COALESCE(metadata, '{}'::jsonb) || jsonb_build_object('dedupedPhone', r.phone),
40
+ phone = NULL
41
+ WHERE id = r.id;
42
+ END LOOP;
43
+ END $dedupe$;