@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
package/README.md CHANGED
@@ -5,6 +5,8 @@
5
5
  [![npm](https://img.shields.io/npm/v/@fayz-ai/plugin-agenda.svg)](https://www.npmjs.com/package/@fayz-ai/plugin-agenda)
6
6
  [![license](https://img.shields.io/npm/l/@fayz-ai/plugin-agenda.svg)](https://github.com/FayaLabs/fayz-sdk/blob/main/LICENSE)
7
7
 
8
+ **Status:** beta — pre-1.0. Core surface is stable; some backend facets (see `PLUGIN_PATTERNS.md`) are still landing. APIs may change before 1.0.
9
+
8
10
  Every service business runs on a calendar. Salons book stylists, clinics book doctors, studios book rooms — the same primitive, rebuilt badly a thousand times. `plugin-agenda` is that primitive done once: a resource-aware calendar with appointments, blocks, working hours, conflict detection, and drag-and-drop, all driven by config instead of forks.
9
11
 
10
12
  It snaps into any `defineSaas` app and reshapes itself per vertical — booking types, statuses, professional/client/service lookups, and locations are all options. Pair it with `@fayz-ai/plugin-financial` and a booking can auto-create an order, so scheduling and revenue stay in sync from the first appointment. One engine, every vertical, no rewrite.
@@ -1 +1 @@
1
- {"version":3,"file":"create-financial-bridge.d.ts","sourceRoot":"","sources":["../../src/bridges/create-financial-bridge.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACtE,OAAO,KAAK,EAAE,qBAAqB,EAAqE,MAAM,qBAAqB,CAAA;AAGnI;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAKlF;AAeD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,qBAAqB,CA4O5F"}
1
+ {"version":3,"file":"create-financial-bridge.d.ts","sourceRoot":"","sources":["../../src/bridges/create-financial-bridge.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACtE,OAAO,KAAK,EAAE,qBAAqB,EAAqE,MAAM,qBAAqB,CAAA;AAGnI;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAKlF;AAeD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,qBAAqB,CA0O5F"}
package/dist/config.d.ts CHANGED
@@ -62,11 +62,11 @@ export interface AgendaPluginOptions {
62
62
  locale?: string;
63
63
  symbol?: string;
64
64
  };
65
- /** Booking kind used in saas_core.bookings.kind (default: 'appointment') */
65
+ /** Booking kind used in public.appointments.kind (default: 'appointment') */
66
66
  bookingKind?: string;
67
67
  /** Order kind for financial records (default: 'service_order') */
68
68
  orderKind?: string;
69
- /** Schedule kind in saas_core.schedules.kind (default: 'working_hours') */
69
+ /** Schedule kind in public.schedules.kind (default: 'working_hours') */
70
70
  scheduleKind?: string;
71
71
  /** Booking type tabs shown in the appointment modal */
72
72
  bookingTypes?: BookingTypeConfig[];
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../src/data/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AA+MjD,wBAAgB,4BAA4B,IAAI,kBAAkB,CAqXjE"}
1
+ {"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../src/data/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAgNjD,wBAAgB,4BAA4B,IAAI,kBAAkB,CAqXjE"}
package/dist/index.cjs CHANGED
@@ -1733,7 +1733,7 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, external
1733
1733
  for (const [k, v] of Object.entries(data)) {
1734
1734
  dbData[k.replace(/[A-Z]/g, (m) => "_" + m.toLowerCase())] = v;
1735
1735
  }
1736
- await supabase.schema("saas_core").from("persons").update(dbData).eq("id", clientId);
1736
+ await supabase.from("people").update(dbData).eq("id", clientId);
1737
1737
  setClientData({ ...clientData, ...data });
1738
1738
  setClientEditing(false);
1739
1739
  } catch {
@@ -1893,7 +1893,7 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, external
1893
1893
  const supabase = getSupabaseClientOptional4();
1894
1894
  const tenantId = getAgendaTenantId2();
1895
1895
  if (!supabase || !tenantId) throw new Error("Not initialized");
1896
- const { data: personRow, error: personError } = await supabase.schema("saas_core").from("persons").insert({
1896
+ const { data: personRow, error: personError } = await supabase.from("people").insert({
1897
1897
  tenant_id: tenantId,
1898
1898
  kind: config.clientKind,
1899
1899
  name: newClientName.trim(),
@@ -1906,7 +1906,7 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, external
1906
1906
  tenant_id: tenantId
1907
1907
  });
1908
1908
  if (clientError) {
1909
- await supabase.schema("saas_core").from("persons").delete().eq("id", personRow.id);
1909
+ await supabase.from("people").delete().eq("id", personRow.id);
1910
1910
  throw clientError;
1911
1911
  }
1912
1912
  setClientId(personRow.id);
@@ -3486,7 +3486,7 @@ function snakeToCamel(obj) {
3486
3486
  function getClients() {
3487
3487
  const supabase = core.getSupabaseClientOptional();
3488
3488
  if (!supabase) throw new Error("Supabase not initialized");
3489
- return { core: supabase.schema("saas_core"), pub: supabase };
3489
+ return { core: supabase, pub: supabase };
3490
3490
  }
3491
3491
  function mapBooking(row) {
3492
3492
  return snakeToCamel(row);
@@ -3543,7 +3543,7 @@ async function hydrateCanonicalBookings(core, bookings) {
3543
3543
  { data: orders, error: ordersError },
3544
3544
  { data: items, error: itemsError }
3545
3545
  ] = await Promise.all([
3546
- personIds.length ? core.from("persons").select("id, name, phone, email, avatar_url").in("id", personIds) : Promise.resolve({ data: [], error: null }),
3546
+ personIds.length ? core.from("people").select("id, name, phone, email, avatar_url").in("id", personIds) : Promise.resolve({ data: [], error: null }),
3547
3547
  locationIds.length ? core.from("locations").select("id, name").in("id", locationIds) : Promise.resolve({ data: [], error: null }),
3548
3548
  orderIds.length ? core.from("orders").select("id, total, status").in("id", orderIds) : Promise.resolve({ data: [], error: null }),
3549
3549
  orderIds.length ? core.from("order_items").select("id, order_id, service_id, name, duration_minutes, unit_price, assignee_id, sort_order").in("order_id", orderIds) : Promise.resolve({ data: [], error: null })
@@ -3601,7 +3601,7 @@ async function hydrateCanonicalBookings(core, bookings) {
3601
3601
  });
3602
3602
  }
3603
3603
  async function getCanonicalBookings(core, query) {
3604
- let q = core.from("bookings").select("id, tenant_id, kind, starts_at, ends_at, status, notes, order_id, location_id, metadata, party_id, assignee_id, created_at, updated_at").gte("starts_at", query.dateRange.start).lte("starts_at", query.dateRange.end);
3604
+ let q = core.from("appointments").select("id, tenant_id, kind, starts_at, ends_at, status, notes, order_id, location_id, metadata, party_id, assignee_id, created_at, updated_at").gte("starts_at", query.dateRange.start).lte("starts_at", query.dateRange.end);
3605
3605
  if (query.kind) q = q.eq("kind", query.kind);
3606
3606
  if (query.statuses?.length) q = q.in("status", query.statuses);
3607
3607
  if (query.professionalIds?.length) q = q.in("assignee_id", query.professionalIds);
@@ -3612,10 +3612,10 @@ async function getCanonicalBookings(core, query) {
3612
3612
  }
3613
3613
  async function getCanonicalBookingById(core, id) {
3614
3614
  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";
3615
- let { data, error } = await core.from("bookings").select(columns).eq("id", id).maybeSingle();
3615
+ let { data, error } = await core.from("appointments").select(columns).eq("id", id).maybeSingle();
3616
3616
  if (error) throw error;
3617
3617
  if (!data) {
3618
- const fallback = await core.from("bookings").select(columns).eq("order_id", id).maybeSingle();
3618
+ const fallback = await core.from("appointments").select(columns).eq("order_id", id).maybeSingle();
3619
3619
  if (fallback.error) throw fallback.error;
3620
3620
  data = fallback.data;
3621
3621
  }
@@ -3625,10 +3625,10 @@ async function getCanonicalBookingById(core, id) {
3625
3625
  }
3626
3626
  function createSupabaseAgendaProvider() {
3627
3627
  return {
3628
- // v_bookings is in public schema (PostgREST default)
3628
+ // v_appointments is in public schema (PostgREST default)
3629
3629
  async getBookings(query) {
3630
3630
  const { core, pub } = getClients();
3631
- let q = pub.from("v_bookings").select("*").gte("starts_at", query.dateRange.start).lte("starts_at", query.dateRange.end);
3631
+ let q = pub.from("v_appointments").select("*").gte("starts_at", query.dateRange.start).lte("starts_at", query.dateRange.end);
3632
3632
  if (query.kind) q = q.eq("kind", query.kind);
3633
3633
  if (query.statuses?.length) q = q.in("status", query.statuses);
3634
3634
  if (query.professionalIds?.length) q = q.in("professional_id", query.professionalIds);
@@ -3642,7 +3642,7 @@ function createSupabaseAgendaProvider() {
3642
3642
  },
3643
3643
  async getBookingById(id) {
3644
3644
  const { core, pub } = getClients();
3645
- const { data, error } = await pub.from("v_bookings").select("*").eq("id", id).maybeSingle();
3645
+ const { data, error } = await pub.from("v_appointments").select("*").eq("id", id).maybeSingle();
3646
3646
  if (error) throw error;
3647
3647
  if (data) return mapBooking(data);
3648
3648
  return getCanonicalBookingById(core, id);
@@ -3658,7 +3658,7 @@ function createSupabaseAgendaProvider() {
3658
3658
  const serviceNames = input.services.map((s) => s.name).join(", ");
3659
3659
  let contactName;
3660
3660
  if (input.clientId) {
3661
- const { data: person } = await core.from("persons").select("name").eq("id", input.clientId).single();
3661
+ const { data: person } = await core.from("people").select("name").eq("id", input.clientId).single();
3662
3662
  contactName = person?.name;
3663
3663
  }
3664
3664
  const eventTitle = input.title?.trim() || void 0;
@@ -3680,7 +3680,7 @@ function createSupabaseAgendaProvider() {
3680
3680
  }
3681
3681
  }).select("id").single();
3682
3682
  if (orderErr) throw orderErr;
3683
- const { data: booking, error: bookingErr } = await core.from("bookings").insert({
3683
+ const { data: booking, error: bookingErr } = await core.from("appointments").insert({
3684
3684
  tenant_id: tenantId,
3685
3685
  kind: input.kind ?? "appointment",
3686
3686
  party_id: input.clientId || null,
@@ -3720,7 +3720,7 @@ function createSupabaseAgendaProvider() {
3720
3720
  },
3721
3721
  async updateBooking(id, data) {
3722
3722
  const { core } = getClients();
3723
- const { data: existing, error: existingErr } = await core.from("bookings").select("id, order_id, starts_at, assignee_id, metadata").eq("id", id).single();
3723
+ const { data: existing, error: existingErr } = await core.from("appointments").select("id, order_id, starts_at, assignee_id, metadata").eq("id", id).single();
3724
3724
  if (existingErr) throw existingErr;
3725
3725
  const updates = {};
3726
3726
  if (data.startsAt) updates.starts_at = data.startsAt;
@@ -3745,7 +3745,7 @@ function createSupabaseAgendaProvider() {
3745
3745
  }
3746
3746
  }
3747
3747
  const effectiveAssigneeId = data.professionalId ?? existing?.assignee_id ?? null;
3748
- const { error } = await core.from("bookings").update(updates).eq("id", id);
3748
+ const { error } = await core.from("appointments").update(updates).eq("id", id);
3749
3749
  if (error) throw error;
3750
3750
  const orderId = existing?.order_id;
3751
3751
  if (orderId) {
@@ -3786,21 +3786,21 @@ function createSupabaseAgendaProvider() {
3786
3786
  },
3787
3787
  async deleteBooking(id) {
3788
3788
  const { core, pub } = getClients();
3789
- const { data: booking, error: bookingErr } = await core.from("bookings").select("order_id").eq("id", id).single();
3789
+ const { data: booking, error: bookingErr } = await core.from("appointments").select("order_id").eq("id", id).single();
3790
3790
  if (bookingErr) throw bookingErr;
3791
3791
  const orderId = booking?.order_id;
3792
- const { count, error: movementErr } = orderId ? await pub.from("financial_movements").select("id", { count: "exact", head: true }).eq("invoice_id", orderId) : { count: 0, error: null };
3792
+ const { count, error: movementErr } = orderId ? await pub.from("plg_financial_movements").select("id", { count: "exact", head: true }).eq("invoice_id", orderId) : { count: 0, error: null };
3793
3793
  if (movementErr) throw movementErr;
3794
3794
  if (orderId && (count ?? 0) > 0) {
3795
- await pub.from("financial_movements").update({ status: "cancelled" }).eq("invoice_id", orderId);
3795
+ await pub.from("plg_financial_movements").update({ status: "cancelled" }).eq("invoice_id", orderId);
3796
3796
  await core.from("orders").update({ status: "cancelled" }).eq("id", orderId);
3797
- const { error } = await core.from("bookings").update({ status: "cancelled" }).eq("id", id);
3797
+ const { error } = await core.from("appointments").update({ status: "cancelled" }).eq("id", id);
3798
3798
  if (error) throw error;
3799
3799
  } else {
3800
3800
  if (orderId) {
3801
- await pub.from("financial_movements").delete().eq("invoice_id", orderId);
3801
+ await pub.from("plg_financial_movements").delete().eq("invoice_id", orderId);
3802
3802
  }
3803
- const { error } = await core.from("bookings").delete().eq("id", id);
3803
+ const { error } = await core.from("appointments").delete().eq("id", id);
3804
3804
  if (error) throw error;
3805
3805
  if (orderId) {
3806
3806
  const { error: orderErr } = await core.from("orders").delete().eq("id", orderId);
@@ -3813,7 +3813,7 @@ function createSupabaseAgendaProvider() {
3813
3813
  },
3814
3814
  async checkConflict(params) {
3815
3815
  const { core } = getClients();
3816
- let q = core.from("bookings").select("id", { count: "exact", head: true }).eq("assignee_id", params.assigneeId).eq("kind", "appointment").not("status", "in", '("cancelled","no_show")').not("starts_at", "is", null).lt("starts_at", params.endsAt).gt("ends_at", params.startsAt);
3816
+ let q = core.from("appointments").select("id", { count: "exact", head: true }).eq("assignee_id", params.assigneeId).eq("kind", "appointment").not("status", "in", '("cancelled","no_show")').not("starts_at", "is", null).lt("starts_at", params.endsAt).gt("ends_at", params.startsAt);
3817
3817
  if (params.excludeBookingId) {
3818
3818
  q = q.neq("id", params.excludeBookingId);
3819
3819
  }
@@ -3868,7 +3868,7 @@ function createSupabaseAgendaProvider() {
3868
3868
  },
3869
3869
  async getProfessionals() {
3870
3870
  const { core } = getClients();
3871
- const { data, error } = await core.from("persons").select("id, name, avatar_url, is_active").eq("kind", "staff").eq("is_active", true).order("name");
3871
+ const { data, error } = await core.from("people").select("id, name, avatar_url, is_active").eq("kind", "staff").eq("is_active", true).order("name");
3872
3872
  if (error) throw error;
3873
3873
  return (data ?? []).map((p) => ({
3874
3874
  id: p.id,
@@ -3890,23 +3890,23 @@ function createSupabaseAgendaProvider() {
3890
3890
  const now = (/* @__PURE__ */ new Date()).toISOString();
3891
3891
  const cutoff = /* @__PURE__ */ new Date();
3892
3892
  cutoff.setDate(cutoff.getDate() + daysAhead);
3893
- const { data, error } = await pub.from("v_bookings").select("*").eq("status", "scheduled").gte("starts_at", now).lte("starts_at", cutoff.toISOString()).order("starts_at");
3893
+ const { data, error } = await pub.from("v_appointments").select("*").eq("status", "scheduled").gte("starts_at", now).lte("starts_at", cutoff.toISOString()).order("starts_at");
3894
3894
  if (error) throw error;
3895
3895
  return (data ?? []).map(mapBooking);
3896
3896
  },
3897
3897
  async sendConfirmation(bookingId, channel) {
3898
3898
  const { core } = getClients();
3899
- const { data: booking } = await core.from("bookings").select("metadata").eq("id", bookingId).single();
3899
+ const { data: booking } = await core.from("appointments").select("metadata").eq("id", bookingId).single();
3900
3900
  const metadata = booking?.metadata ?? {};
3901
3901
  const confirmations = metadata.confirmations ?? [];
3902
3902
  confirmations.push({ channel, sentAt: (/* @__PURE__ */ new Date()).toISOString(), status: "sent" });
3903
- await core.from("bookings").update({ metadata: { ...metadata, confirmations } }).eq("id", bookingId);
3903
+ await core.from("appointments").update({ metadata: { ...metadata, confirmations } }).eq("id", bookingId);
3904
3904
  },
3905
3905
  async completeBooking(bookingId) {
3906
3906
  const { core } = getClients();
3907
- const { data: existing, error: existingErr } = await core.from("bookings").select("order_id").eq("id", bookingId).single();
3907
+ const { data: existing, error: existingErr } = await core.from("appointments").select("order_id").eq("id", bookingId).single();
3908
3908
  if (existingErr) throw existingErr;
3909
- const { error } = await core.from("bookings").update({ status: "completed" }).eq("id", bookingId);
3909
+ const { error } = await core.from("appointments").update({ status: "completed" }).eq("id", bookingId);
3910
3910
  if (error) throw error;
3911
3911
  const orderId = existing?.order_id;
3912
3912
  const booking = await this.getBookingById(bookingId);
@@ -4135,7 +4135,6 @@ var holidayEntity = {
4135
4135
  ],
4136
4136
  data: {
4137
4137
  table: "holidays",
4138
- schema: "saas_core",
4139
4138
  tenantScoped: true
4140
4139
  }
4141
4140
  };
@@ -4669,36 +4668,49 @@ var MIGRATION_001_PUBLIC_BOOKING = `-- =========================================
4669
4668
  -- plugin-agenda 001: booking read model + public (anon) booking surface
4670
4669
  --
4671
4670
  -- Ships the objects the agenda providers reference but the spine (packages/db
4672
- -- migrations 001\u2013008) does not define:
4671
+ -- migrations 001\u2013010) does not define:
4672
+ -- \xA70 converted-pool cleanup \u2014 drop the pre-rename v_bookings view / indexes
4673
4673
  -- \xA71 order_items columns the admin provider writes (duration/assignee)
4674
- -- \xA72 public.v_bookings \u2014 admin read model (authenticated, RLS applies)
4674
+ -- \xA72 public.v_appointments \u2014 admin read model (authenticated, RLS applies)
4675
4675
  -- \xA73 public.v_public_services \u2014 anon-readable service catalog
4676
4676
  -- \xA74 public.get_available_slots \u2014 anon RPC (mirrors the mock algorithm)
4677
4677
  -- \xA75 public.create_public_booking \u2014 anon RPC (validated, race-safe write)
4678
4678
  --
4679
+ -- Core v1 lives directly in PUBLIC (no separate core schema): people (was
4680
+ -- persons), appointments (was bookings). This migration is written against public
4681
+ -- names and is idempotent + safe on both fresh and converted pools.
4682
+ --
4679
4683
  -- Anon-access design: public booking pages run with the publishable key and no
4680
4684
  -- session, so the canonical tenant RLS yields nothing. Anon access is granted
4681
4685
  -- ONLY via the column-whitelisted view (\xA73) and SECURITY DEFINER RPCs (\xA74, \xA75)
4682
4686
  -- with tight input validation and hardcoded statuses.
4683
4687
  -- ============================================================================
4684
4688
 
4689
+ -- \xA70 \u2014 converted-pool cleanup. The pre-industry-pool shape shipped a v_bookings
4690
+ -- view and persons_/bookings_-named indexes; drop them so this file re-emits the
4691
+ -- canonical v_appointments view + people_/appointments_ indexes without leaving
4692
+ -- duplicates. All guarded with IF EXISTS \u2192 no-ops on a fresh pool.
4693
+ DROP VIEW IF EXISTS public.v_bookings;
4694
+ DROP INDEX IF EXISTS public.persons_tenant_customer_phone;
4695
+ DROP INDEX IF EXISTS public.bookings_assignee_time;
4696
+
4685
4697
  -- \xA71 \u2014 columns the agenda provider writes but 004_archetypes lacks
4686
- ALTER TABLE saas_core.order_items
4698
+ ALTER TABLE public.order_items
4687
4699
  ADD COLUMN IF NOT EXISTS duration_minutes integer,
4688
- ADD COLUMN IF NOT EXISTS assignee_id uuid REFERENCES saas_core.persons(id) ON DELETE SET NULL;
4700
+ ADD COLUMN IF NOT EXISTS assignee_id uuid REFERENCES public.people(id) ON DELETE SET NULL;
4689
4701
 
4690
4702
  -- Upsert key for public customers (per tenant, by normalized phone)
4691
- CREATE UNIQUE INDEX IF NOT EXISTS persons_tenant_customer_phone
4692
- ON saas_core.persons(tenant_id, phone)
4703
+ CREATE UNIQUE INDEX IF NOT EXISTS people_tenant_customer_phone
4704
+ ON public.people(tenant_id, phone)
4693
4705
  WHERE kind = 'customer' AND phone IS NOT NULL;
4694
4706
 
4695
4707
  -- Slot-conflict scan
4696
- CREATE INDEX IF NOT EXISTS bookings_assignee_time
4697
- ON saas_core.bookings(assignee_id, starts_at, ends_at)
4708
+ CREATE INDEX IF NOT EXISTS appointments_assignee_time
4709
+ ON public.appointments(assignee_id, starts_at, ends_at)
4698
4710
  WHERE status NOT IN ('cancelled', 'no_show');
4699
4711
 
4700
4712
  -- \xA72 \u2014 admin read model (security_invoker \u2192 underlying RLS applies; anon sees 0 rows)
4701
- CREATE OR REPLACE VIEW public.v_bookings
4713
+ CREATE OR REPLACE VIEW public.v_appointments
4702
4714
  WITH (security_invoker = true) AS
4703
4715
  SELECT
4704
4716
  b.id, b.tenant_id, b.kind, b.starts_at, b.ends_at, b.status, b.notes,
@@ -4716,14 +4728,14 @@ SELECT
4716
4728
  o.status AS order_status,
4717
4729
  (EXTRACT(EPOCH FROM (COALESCE(b.ends_at, b.starts_at) - b.starts_at))::int / 60)
4718
4730
  AS total_duration_minutes
4719
- FROM saas_core.bookings b
4720
- LEFT JOIN saas_core.persons pc ON pc.id = b.party_id
4721
- LEFT JOIN saas_core.persons ps ON ps.id = b.assignee_id
4722
- LEFT JOIN saas_core.locations l ON l.id = b.location_id
4723
- LEFT JOIN saas_core.orders o ON o.id = b.order_id;
4731
+ FROM public.appointments b
4732
+ LEFT JOIN public.people pc ON pc.id = b.party_id
4733
+ LEFT JOIN public.people ps ON ps.id = b.assignee_id
4734
+ LEFT JOIN public.locations l ON l.id = b.location_id
4735
+ LEFT JOIN public.orders o ON o.id = b.order_id;
4724
4736
 
4725
- GRANT SELECT ON public.v_bookings TO authenticated, service_role;
4726
- REVOKE SELECT ON public.v_bookings FROM anon;
4737
+ GRANT SELECT ON public.v_appointments TO authenticated, service_role;
4738
+ REVOKE SELECT ON public.v_appointments FROM anon;
4727
4739
 
4728
4740
  -- \xA73 \u2014 anon-readable public catalog (owner-rights view = deliberate, whitelisted)
4729
4741
  CREATE OR REPLACE VIEW public.v_public_services AS
@@ -4732,7 +4744,7 @@ SELECT
4732
4744
  COALESCE(s.duration_minutes, 30) AS duration_minutes,
4733
4745
  s.image_url,
4734
4746
  COALESCE((s.metadata->>'sort_order')::int, 0) AS sort_order
4735
- FROM saas_core.services s
4747
+ FROM public.services s
4736
4748
  WHERE s.is_active AND s.status = 'active';
4737
4749
 
4738
4750
  GRANT SELECT ON public.v_public_services TO anon, authenticated, service_role;
@@ -4746,7 +4758,7 @@ CREATE OR REPLACE FUNCTION public.get_available_slots(
4746
4758
  p_slot_interval integer DEFAULT 30
4747
4759
  ) RETURNS TABLE (slot_start timestamptz, slot_end timestamptz)
4748
4760
  LANGUAGE plpgsql STABLE SECURITY DEFINER
4749
- SET search_path = saas_core, public
4761
+ SET search_path = public
4750
4762
  AS $$
4751
4763
  DECLARE
4752
4764
  v_tz text;
@@ -4794,7 +4806,7 @@ BEGIN
4794
4806
  SELECT DISTINCT c.s_start, c.s_end
4795
4807
  FROM candidate c
4796
4808
  WHERE NOT EXISTS (
4797
- SELECT 1 FROM bookings b
4809
+ SELECT 1 FROM appointments b
4798
4810
  WHERE b.tenant_id = p_tenant_id
4799
4811
  AND b.assignee_id = c.assignee_id
4800
4812
  AND b.status NOT IN ('cancelled', 'no_show')
@@ -4820,7 +4832,7 @@ CREATE OR REPLACE FUNCTION public.create_public_booking(
4820
4832
  p_notes text DEFAULT NULL
4821
4833
  ) RETURNS TABLE (booking_id uuid, starts_at timestamptz, ends_at timestamptz)
4822
4834
  LANGUAGE plpgsql SECURITY DEFINER
4823
- SET search_path = saas_core, public
4835
+ SET search_path = public
4824
4836
  AS $$
4825
4837
  DECLARE
4826
4838
  v_service record;
@@ -4882,7 +4894,7 @@ BEGIN
4882
4894
  PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_assignee::text, 0));
4883
4895
 
4884
4896
  IF EXISTS (
4885
- SELECT 1 FROM bookings b
4897
+ SELECT 1 FROM appointments b
4886
4898
  WHERE b.tenant_id = p_tenant_id
4887
4899
  AND b.assignee_id = v_assignee
4888
4900
  AND b.status NOT IN ('cancelled', 'no_show')
@@ -4894,8 +4906,8 @@ BEGIN
4894
4906
 
4895
4907
  -- anti-spam: cap open future public bookings per phone per tenant
4896
4908
  IF (
4897
- SELECT count(*) FROM bookings b
4898
- JOIN persons p ON p.id = b.party_id
4909
+ SELECT count(*) FROM appointments b
4910
+ JOIN people p ON p.id = b.party_id
4899
4911
  WHERE b.tenant_id = p_tenant_id
4900
4912
  AND p.phone = v_phone
4901
4913
  AND b.starts_at > now()
@@ -4904,14 +4916,14 @@ BEGIN
4904
4916
  RAISE EXCEPTION 'too many open bookings for this phone';
4905
4917
  END IF;
4906
4918
 
4907
- -- upsert the customer by (tenant, phone) \u2014 matches persons_tenant_customer_phone
4908
- INSERT INTO persons (tenant_id, kind, name, phone, email, metadata)
4919
+ -- upsert the customer by (tenant, phone) \u2014 matches people_tenant_customer_phone
4920
+ INSERT INTO people (tenant_id, kind, name, phone, email, metadata)
4909
4921
  VALUES (p_tenant_id, 'customer', trim(p_name), v_phone, p_email,
4910
4922
  jsonb_build_object('source', 'public_booking'))
4911
4923
  ON CONFLICT (tenant_id, phone) WHERE kind = 'customer' AND phone IS NOT NULL
4912
4924
  DO UPDATE SET
4913
4925
  name = EXCLUDED.name,
4914
- email = COALESCE(EXCLUDED.email, persons.email),
4926
+ email = COALESCE(EXCLUDED.email, people.email),
4915
4927
  updated_at = now()
4916
4928
  RETURNING id INTO v_person_id;
4917
4929
 
@@ -4924,7 +4936,7 @@ BEGIN
4924
4936
  'contactName', trim(p_name)))
4925
4937
  RETURNING id INTO v_order;
4926
4938
 
4927
- INSERT INTO bookings (tenant_id, kind, party_id, assignee_id, order_id,
4939
+ INSERT INTO appointments (tenant_id, kind, party_id, assignee_id, order_id,
4928
4940
  starts_at, ends_at, status, notes, metadata)
4929
4941
  VALUES (p_tenant_id, 'appointment', v_person_id, v_assignee, v_order,
4930
4942
  p_starts_at, v_ends, 'scheduled', v_notes,
@@ -4971,8 +4983,8 @@ function createFinancialBridge(provider2) {
4971
4983
  if (!supabase) return result;
4972
4984
  try {
4973
4985
  const [{ data: orders }, { data: movements }] = await Promise.all([
4974
- supabase.schema("saas_core").from("orders").select("id, kind, status, total, reference_number, metadata").in("id", orderIds),
4975
- supabase.from("financial_movements").select("invoice_id, status, paid_amount").in("invoice_id", orderIds)
4986
+ supabase.from("orders").select("id, kind, status, total, reference_number, metadata").in("id", orderIds),
4987
+ supabase.from("plg_financial_movements").select("invoice_id, status, paid_amount").in("invoice_id", orderIds)
4976
4988
  ]);
4977
4989
  const movementsByOrderId = /* @__PURE__ */ new Map();
4978
4990
  for (const movement of movements ?? []) {
@@ -5000,8 +5012,8 @@ function createFinancialBridge(provider2) {
5000
5012
  const supabase = core.getSupabaseClientOptional();
5001
5013
  if (!supabase) return null;
5002
5014
  const [orderRes, movRes] = await Promise.all([
5003
- supabase.schema("saas_core").from("orders").select("id, status, total, reference_number, metadata").eq("id", orderId).single(),
5004
- supabase.from("financial_movements").select("*").eq("invoice_id", orderId).order("due_date")
5015
+ supabase.from("orders").select("id, status, total, reference_number, metadata").eq("id", orderId).single(),
5016
+ supabase.from("plg_financial_movements").select("*").eq("invoice_id", orderId).order("due_date")
5005
5017
  ]);
5006
5018
  const order = orderRes.data;
5007
5019
  if (!order) return null;
@@ -5009,7 +5021,7 @@ function createFinancialBridge(provider2) {
5009
5021
  const typeIds = [...new Set((movRes.data ?? []).map((m) => m.payment_method_type_id).filter(Boolean))];
5010
5022
  let typeNames = {};
5011
5023
  if (typeIds.length > 0) {
5012
- const { data: types } = await supabase.from("payment_method_types").select("id, name").in("id", typeIds);
5024
+ const { data: types } = await supabase.from("plg_financial_payment_method_types").select("id, name").in("id", typeIds);
5013
5025
  typeNames = Object.fromEntries((types ?? []).map((t) => [t.id, t.name]));
5014
5026
  }
5015
5027
  const movements = (movRes.data ?? []).map((m) => ({
@@ -5061,17 +5073,17 @@ function createFinancialBridge(provider2) {
5061
5073
  async createCommissionMovement(orderId, options) {
5062
5074
  const supabase = core.getSupabaseClientOptional();
5063
5075
  if (!supabase) return null;
5064
- const { data: order } = await supabase.schema("saas_core").from("orders").select("id, tenant_id, assignee_id, total").eq("id", orderId).single();
5076
+ const { data: order } = await supabase.from("orders").select("id, tenant_id, assignee_id, total").eq("id", orderId).single();
5065
5077
  if (!order || !order.assignee_id) return null;
5066
5078
  const { data: staff } = await supabase.from("v_staff").select("commission_rate").eq("id", order.assignee_id).single();
5067
5079
  const rate = Number(staff?.commission_rate) || 0;
5068
5080
  const base = Number(order.total) || 0;
5069
5081
  const amount = computeCommissionAmount(base, rate);
5070
5082
  if (amount <= 0) return null;
5071
- const { data: existing } = await supabase.from("financial_movements").select("id").eq("invoice_id", orderId).eq("movement_kind", "commission").limit(1);
5083
+ const { data: existing } = await supabase.from("plg_financial_movements").select("id").eq("invoice_id", orderId).eq("movement_kind", "commission").limit(1);
5072
5084
  if (existing && existing.length > 0) return existing[0].id;
5073
5085
  const dueDate = options?.dueDate ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
5074
- const { data: inserted } = await supabase.from("financial_movements").insert({
5086
+ const { data: inserted } = await supabase.from("plg_financial_movements").insert({
5075
5087
  tenant_id: order.tenant_id,
5076
5088
  invoice_id: orderId,
5077
5089
  direction: "debit",
@@ -5508,7 +5520,7 @@ function createAgendaPlugin(options) {
5508
5520
  id: "agenda-001-public-booking",
5509
5521
  version: "0.3.0",
5510
5522
  sql: MIGRATION_001_PUBLIC_BOOKING,
5511
- description: "Booking read model (v_bookings) + anon public booking surface (v_public_services, get_available_slots, create_public_booking) + order_items duration/assignee columns"
5523
+ description: "Booking read model (v_appointments) + anon public booking surface (v_public_services, get_available_slots, create_public_booking) + order_items duration/assignee columns"
5512
5524
  }
5513
5525
  ],
5514
5526
  locales: agendaLocales