@fayz-ai/db 0.12.0 → 0.14.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.
- package/canonical-schema.json +132 -0
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/schema/spine.d.ts +42 -37
- package/dist/schema/spine.d.ts.map +1 -1
- package/migrations/000_baseline.sql +29667 -0
- package/migrations/001_the_tenant_has_apps.sql +314 -0
- package/migrations/002_the_spine_drops_the_vendor_and_the_dead.sql +129 -0
- package/migrations/003_the_role_rpcs_finish_and_the_mirrors_go.sql +135 -0
- package/migrations/004_the_projections_get_a_successor.sql +312 -0
- package/migrations/005_the_archetypes_anchor_to_the_unit.sql +90 -0
- package/migrations/006_the_helpers_read_the_source.sql +153 -0
- package/migrations/007_the_compat_machinery_leaves_with_the_tables.sql +77 -0
- package/migrations/008_the_switchers_see_across_accounts.sql +150 -0
- package/migrations/009_the_compat_aliases_nobody_adopted.sql +57 -0
- package/migrations/010_the_new_tenant_is_born_with_its_trade.sql +201 -0
- package/migrations/011_leadcontrol_joins_the_family.sql +116 -0
- package/migrations/012_chefcontrol_wears_its_own_mark.sql +28 -0
- package/migrations/013_the_workspace_switch_reaches_the_other_half.sql +156 -0
- package/migrations/014_the_chooser_can_read_what_it_offers.sql +91 -0
- package/migrations/015_the_unit_bindings_belong_to_one_workspace.sql +86 -0
- package/migrations/016_the_rule_stops_asking_every_row.sql +543 -0
- package/migrations/017_the_pin_is_checked_against_the_right_workspace.sql +139 -0
- package/migrations/018_the_bootstrap_says_what_you_reach.sql +114 -0
- package/migrations/019_distributing_one_row_stops_costing_the_table.sql +245 -0
- package/migrations/020_the_agenda_asks_where_someone_works.sql +81 -0
- package/migrations/022_the_line_says_which_document_it_belongs_to.sql +109 -0
- package/package.json +3 -2
- package/migrations/0000_legacy_quarantine.sql +0 -86
- package/migrations/0000b_straggler_sweep.sql +0 -37
- package/migrations/000_core_v1_convert.sql +0 -343
- package/migrations/001_core.sql +0 -372
- package/migrations/002_rls_user_tenant_ids.sql +0 -64
- package/migrations/003_invitations.sql +0 -17
- package/migrations/004_archetypes.sql +0 -343
- package/migrations/005_locations_archetype.sql +0 -18
- package/migrations/006_archetype_rls.sql +0 -74
- package/migrations/007_archetype_grants.sql +0 -4
- package/migrations/008_grants.sql +0 -5
- package/migrations/009_anon_hardening.sql +0 -19
- package/migrations/010_migration_ledger.sql +0 -36
- package/migrations/011_anon_write_revoke.sql +0 -12
- package/migrations/012_rename_migration_ledger.sql +0 -61
- package/migrations/013_sequences_rls.sql +0 -22
- package/migrations/014_plan_entitlements.sql +0 -28
- package/migrations/015_agent_guard.sql +0 -108
- package/migrations/016_agent_guard_actor.sql +0 -102
- package/migrations/017_core_addresses.sql +0 -115
- package/migrations/018_global_search.sql +0 -482
- package/migrations/019_tenant_members_person_id.sql +0 -20
- package/migrations/020_fayz_projects.sql +0 -63
- package/migrations/021_tenant_roles.sql +0 -74
- package/migrations/022_invite_acceptance.sql +0 -91
- package/migrations/023_team_visibility.sql +0 -75
- package/migrations/024_analytics_engine.sql +0 -317
- package/migrations/025_created_by.sql +0 -75
- package/migrations/026_audit_trail.sql +0 -73
- package/migrations/027_domain_events.sql +0 -266
- package/migrations/028_tenant_scoped_token.sql +0 -127
- package/migrations/029_connections.sql +0 -186
- package/migrations/030_effect_idempotency.sql +0 -159
- package/migrations/031_sync_run_message.sql +0 -39
- package/migrations/032_connection_secrets.sql +0 -227
- package/migrations/033_sync_schedule.sql +0 -651
- package/migrations/034_custom_fields.sql +0 -55
- package/migrations/035_field_registry.sql +0 -148
- package/migrations/036_analytics_run_batch.sql +0 -84
- package/migrations/037_sync_tick_one_at_a_time.sql +0 -256
- package/migrations/038_onboarding_responses.sql +0 -103
- package/migrations/039_unit_tree.sql +0 -270
- package/migrations/040_resource_grants.sql +0 -474
- package/migrations/041_scoped_columns.sql +0 -192
- package/migrations/042_unit_scope_policies.sql +0 -145
- package/migrations/043_view_invoker.sql +0 -81
- package/migrations/044_unit_member_facts.sql +0 -47
- package/migrations/045_unit_entry.sql +0 -236
- package/migrations/046_membership_visible_to_members.sql +0 -85
- package/migrations/047_tasks.sql +0 -266
- package/migrations/048_every_login_is_a_person.sql +0 -190
- package/migrations/049_bookable_people.sql +0 -126
|
@@ -1,343 +0,0 @@
|
|
|
1
|
-
-- ============================================================================
|
|
2
|
-
-- core archetype tables (public schema)
|
|
3
|
-
-- Shared base entities that project-specific tables extend via FK
|
|
4
|
-
-- ============================================================================
|
|
5
|
-
|
|
6
|
-
-- ---------------------------------------------------------------------------
|
|
7
|
-
-- 1. people — any human entity (staff, customer, supplier, professional)
|
|
8
|
-
-- ---------------------------------------------------------------------------
|
|
9
|
-
CREATE TABLE IF NOT EXISTS public.people (
|
|
10
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
11
|
-
tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
|
|
12
|
-
kind text NOT NULL,
|
|
13
|
-
name text NOT NULL,
|
|
14
|
-
email text,
|
|
15
|
-
phone text,
|
|
16
|
-
document_number text,
|
|
17
|
-
avatar_url text,
|
|
18
|
-
date_of_birth date,
|
|
19
|
-
address text,
|
|
20
|
-
city text,
|
|
21
|
-
state text,
|
|
22
|
-
country text DEFAULT 'BR',
|
|
23
|
-
postal_code text,
|
|
24
|
-
tags text[] DEFAULT '{}',
|
|
25
|
-
is_active boolean DEFAULT true,
|
|
26
|
-
notes text,
|
|
27
|
-
metadata jsonb DEFAULT '{}',
|
|
28
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
29
|
-
updated_at timestamptz NOT NULL DEFAULT now()
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
CREATE INDEX IF NOT EXISTS people_tenant_kind ON public.people(tenant_id, kind);
|
|
33
|
-
DROP TRIGGER IF EXISTS people_updated_at ON public.people;
|
|
34
|
-
CREATE TRIGGER people_updated_at BEFORE UPDATE ON public.people
|
|
35
|
-
FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();
|
|
36
|
-
|
|
37
|
-
-- ---------------------------------------------------------------------------
|
|
38
|
-
-- 2. categories — generic taxonomy (species, menu categories, regions)
|
|
39
|
-
-- ---------------------------------------------------------------------------
|
|
40
|
-
CREATE TABLE IF NOT EXISTS public.categories (
|
|
41
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
42
|
-
tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
|
|
43
|
-
kind text NOT NULL,
|
|
44
|
-
name text NOT NULL,
|
|
45
|
-
slug text,
|
|
46
|
-
parent_id uuid REFERENCES public.categories(id) ON DELETE SET NULL,
|
|
47
|
-
icon text,
|
|
48
|
-
color text,
|
|
49
|
-
sort_order integer DEFAULT 0,
|
|
50
|
-
is_active boolean DEFAULT true,
|
|
51
|
-
metadata jsonb DEFAULT '{}',
|
|
52
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
53
|
-
updated_at timestamptz NOT NULL DEFAULT now()
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
CREATE INDEX IF NOT EXISTS categories_tenant_kind ON public.categories(tenant_id, kind);
|
|
57
|
-
DROP TRIGGER IF EXISTS categories_updated_at ON public.categories;
|
|
58
|
-
CREATE TRIGGER categories_updated_at BEFORE UPDATE ON public.categories
|
|
59
|
-
FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();
|
|
60
|
-
|
|
61
|
-
-- ---------------------------------------------------------------------------
|
|
62
|
-
-- 3. products — physical/trackable items (menu items, equipment, ingredients)
|
|
63
|
-
-- ---------------------------------------------------------------------------
|
|
64
|
-
CREATE TABLE IF NOT EXISTS public.products (
|
|
65
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
66
|
-
tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
|
|
67
|
-
category_id uuid REFERENCES public.categories(id) ON DELETE SET NULL,
|
|
68
|
-
name text NOT NULL,
|
|
69
|
-
description text,
|
|
70
|
-
sku text,
|
|
71
|
-
price numeric,
|
|
72
|
-
cost numeric,
|
|
73
|
-
currency text DEFAULT 'BRL',
|
|
74
|
-
unit text,
|
|
75
|
-
image_url text,
|
|
76
|
-
stock numeric,
|
|
77
|
-
min_stock numeric,
|
|
78
|
-
status text DEFAULT 'active',
|
|
79
|
-
is_active boolean DEFAULT true,
|
|
80
|
-
tags text[] DEFAULT '{}',
|
|
81
|
-
metadata jsonb DEFAULT '{}',
|
|
82
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
83
|
-
updated_at timestamptz NOT NULL DEFAULT now()
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
CREATE INDEX IF NOT EXISTS products_tenant ON public.products(tenant_id);
|
|
87
|
-
DROP TRIGGER IF EXISTS products_updated_at ON public.products;
|
|
88
|
-
CREATE TRIGGER products_updated_at BEFORE UPDATE ON public.products
|
|
89
|
-
FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();
|
|
90
|
-
|
|
91
|
-
-- ---------------------------------------------------------------------------
|
|
92
|
-
-- 4. services — intangible offerings (exam types, consultations)
|
|
93
|
-
-- ---------------------------------------------------------------------------
|
|
94
|
-
CREATE TABLE IF NOT EXISTS public.services (
|
|
95
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
96
|
-
tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
|
|
97
|
-
category_id uuid REFERENCES public.categories(id) ON DELETE SET NULL,
|
|
98
|
-
name text NOT NULL,
|
|
99
|
-
description text,
|
|
100
|
-
price numeric,
|
|
101
|
-
cost numeric,
|
|
102
|
-
currency text DEFAULT 'BRL',
|
|
103
|
-
duration_minutes integer,
|
|
104
|
-
image_url text,
|
|
105
|
-
status text DEFAULT 'active',
|
|
106
|
-
is_active boolean DEFAULT true,
|
|
107
|
-
tags text[] DEFAULT '{}',
|
|
108
|
-
metadata jsonb DEFAULT '{}',
|
|
109
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
110
|
-
updated_at timestamptz NOT NULL DEFAULT now()
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
CREATE INDEX IF NOT EXISTS services_tenant ON public.services(tenant_id);
|
|
114
|
-
DROP TRIGGER IF EXISTS services_updated_at ON public.services;
|
|
115
|
-
CREATE TRIGGER services_updated_at BEFORE UPDATE ON public.services
|
|
116
|
-
FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();
|
|
117
|
-
|
|
118
|
-
-- ---------------------------------------------------------------------------
|
|
119
|
-
-- 5. orders — business orders/jobs
|
|
120
|
-
-- ---------------------------------------------------------------------------
|
|
121
|
-
CREATE TABLE IF NOT EXISTS public.orders (
|
|
122
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
123
|
-
tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
|
|
124
|
-
kind text NOT NULL,
|
|
125
|
-
reference_number text,
|
|
126
|
-
status text DEFAULT 'draft',
|
|
127
|
-
party_id uuid REFERENCES public.people(id) ON DELETE SET NULL,
|
|
128
|
-
assignee_id uuid REFERENCES public.people(id) ON DELETE SET NULL,
|
|
129
|
-
location_id uuid REFERENCES public.locations(id) ON DELETE SET NULL,
|
|
130
|
-
subtotal numeric DEFAULT 0,
|
|
131
|
-
discount numeric DEFAULT 0,
|
|
132
|
-
tax numeric DEFAULT 0,
|
|
133
|
-
total numeric DEFAULT 0,
|
|
134
|
-
currency text DEFAULT 'BRL',
|
|
135
|
-
due_at timestamptz,
|
|
136
|
-
completed_at timestamptz,
|
|
137
|
-
notes text,
|
|
138
|
-
tags text[] DEFAULT '{}',
|
|
139
|
-
metadata jsonb DEFAULT '{}',
|
|
140
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
141
|
-
updated_at timestamptz NOT NULL DEFAULT now()
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
CREATE INDEX IF NOT EXISTS orders_tenant_kind ON public.orders(tenant_id, kind);
|
|
145
|
-
CREATE INDEX IF NOT EXISTS orders_status ON public.orders(tenant_id, status);
|
|
146
|
-
DROP TRIGGER IF EXISTS orders_updated_at ON public.orders;
|
|
147
|
-
CREATE TRIGGER orders_updated_at BEFORE UPDATE ON public.orders
|
|
148
|
-
FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();
|
|
149
|
-
|
|
150
|
-
-- ---------------------------------------------------------------------------
|
|
151
|
-
-- 6. order_items — line items for orders
|
|
152
|
-
-- ---------------------------------------------------------------------------
|
|
153
|
-
CREATE TABLE IF NOT EXISTS public.order_items (
|
|
154
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
155
|
-
order_id uuid NOT NULL REFERENCES public.orders(id) ON DELETE CASCADE,
|
|
156
|
-
product_id uuid REFERENCES public.products(id) ON DELETE SET NULL,
|
|
157
|
-
service_id uuid REFERENCES public.services(id) ON DELETE SET NULL,
|
|
158
|
-
name text NOT NULL,
|
|
159
|
-
description text,
|
|
160
|
-
quantity numeric DEFAULT 1,
|
|
161
|
-
unit_price numeric DEFAULT 0,
|
|
162
|
-
discount numeric DEFAULT 0,
|
|
163
|
-
total numeric DEFAULT 0,
|
|
164
|
-
sort_order integer DEFAULT 0,
|
|
165
|
-
metadata jsonb DEFAULT '{}',
|
|
166
|
-
created_at timestamptz NOT NULL DEFAULT now()
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
CREATE INDEX IF NOT EXISTS order_items_order ON public.order_items(order_id);
|
|
170
|
-
|
|
171
|
-
-- ---------------------------------------------------------------------------
|
|
172
|
-
-- 7. transactions — financial movements (payments, refunds, expenses)
|
|
173
|
-
-- ---------------------------------------------------------------------------
|
|
174
|
-
CREATE TABLE IF NOT EXISTS public.transactions (
|
|
175
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
176
|
-
tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
|
|
177
|
-
kind text NOT NULL,
|
|
178
|
-
order_id uuid REFERENCES public.orders(id) ON DELETE SET NULL,
|
|
179
|
-
party_id uuid REFERENCES public.people(id) ON DELETE SET NULL,
|
|
180
|
-
amount numeric NOT NULL,
|
|
181
|
-
currency text DEFAULT 'BRL',
|
|
182
|
-
payment_method text,
|
|
183
|
-
reference text,
|
|
184
|
-
status text DEFAULT 'completed',
|
|
185
|
-
transacted_at timestamptz DEFAULT now(),
|
|
186
|
-
notes text,
|
|
187
|
-
metadata jsonb DEFAULT '{}',
|
|
188
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
189
|
-
updated_at timestamptz NOT NULL DEFAULT now()
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
CREATE INDEX IF NOT EXISTS transactions_tenant_kind ON public.transactions(tenant_id, kind);
|
|
193
|
-
DROP TRIGGER IF EXISTS transactions_updated_at ON public.transactions;
|
|
194
|
-
CREATE TRIGGER transactions_updated_at BEFORE UPDATE ON public.transactions
|
|
195
|
-
FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();
|
|
196
|
-
|
|
197
|
-
-- ---------------------------------------------------------------------------
|
|
198
|
-
-- 8. appointments — reservations/appointments
|
|
199
|
-
-- ---------------------------------------------------------------------------
|
|
200
|
-
CREATE TABLE IF NOT EXISTS public.appointments (
|
|
201
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
202
|
-
tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
|
|
203
|
-
kind text NOT NULL,
|
|
204
|
-
party_id uuid REFERENCES public.people(id) ON DELETE SET NULL,
|
|
205
|
-
assignee_id uuid REFERENCES public.people(id) ON DELETE SET NULL,
|
|
206
|
-
location_id uuid REFERENCES public.locations(id) ON DELETE SET NULL,
|
|
207
|
-
order_id uuid REFERENCES public.orders(id) ON DELETE SET NULL,
|
|
208
|
-
starts_at timestamptz NOT NULL,
|
|
209
|
-
ends_at timestamptz,
|
|
210
|
-
status text DEFAULT 'pending',
|
|
211
|
-
notes text,
|
|
212
|
-
metadata jsonb DEFAULT '{}',
|
|
213
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
214
|
-
updated_at timestamptz NOT NULL DEFAULT now()
|
|
215
|
-
);
|
|
216
|
-
|
|
217
|
-
CREATE INDEX IF NOT EXISTS appointments_tenant_kind ON public.appointments(tenant_id, kind);
|
|
218
|
-
CREATE INDEX IF NOT EXISTS appointments_starts ON public.appointments(tenant_id, starts_at);
|
|
219
|
-
DROP TRIGGER IF EXISTS appointments_updated_at ON public.appointments;
|
|
220
|
-
CREATE TRIGGER appointments_updated_at BEFORE UPDATE ON public.appointments
|
|
221
|
-
FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();
|
|
222
|
-
|
|
223
|
-
-- ---------------------------------------------------------------------------
|
|
224
|
-
-- 9. appointment_items — services within an appointment
|
|
225
|
-
-- (booking_id column name preserved for parity with converted pools —
|
|
226
|
-
-- the in-place converter renames the table, not the FK column)
|
|
227
|
-
-- ---------------------------------------------------------------------------
|
|
228
|
-
CREATE TABLE IF NOT EXISTS public.appointment_items (
|
|
229
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
230
|
-
booking_id uuid NOT NULL REFERENCES public.appointments(id) ON DELETE CASCADE,
|
|
231
|
-
service_id uuid REFERENCES public.services(id) ON DELETE SET NULL,
|
|
232
|
-
assignee_id uuid REFERENCES public.people(id) ON DELETE SET NULL,
|
|
233
|
-
name text NOT NULL,
|
|
234
|
-
duration_minutes integer,
|
|
235
|
-
price numeric DEFAULT 0,
|
|
236
|
-
sort_order integer DEFAULT 0,
|
|
237
|
-
notes text,
|
|
238
|
-
metadata jsonb DEFAULT '{}',
|
|
239
|
-
created_at timestamptz NOT NULL DEFAULT now()
|
|
240
|
-
);
|
|
241
|
-
|
|
242
|
-
CREATE INDEX IF NOT EXISTS appointment_items_booking ON public.appointment_items(booking_id);
|
|
243
|
-
|
|
244
|
-
-- ---------------------------------------------------------------------------
|
|
245
|
-
-- 10. schedules — recurring availability/shifts
|
|
246
|
-
-- ---------------------------------------------------------------------------
|
|
247
|
-
CREATE TABLE IF NOT EXISTS public.schedules (
|
|
248
|
-
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
249
|
-
tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
|
|
250
|
-
kind text NOT NULL,
|
|
251
|
-
assignee_id uuid REFERENCES public.people(id) ON DELETE CASCADE,
|
|
252
|
-
location_id uuid REFERENCES public.locations(id) ON DELETE SET NULL,
|
|
253
|
-
day_of_week smallint,
|
|
254
|
-
specific_date date,
|
|
255
|
-
starts_at time NOT NULL,
|
|
256
|
-
ends_at time NOT NULL,
|
|
257
|
-
is_active boolean DEFAULT true,
|
|
258
|
-
metadata jsonb DEFAULT '{}',
|
|
259
|
-
created_at timestamptz NOT NULL DEFAULT now(),
|
|
260
|
-
updated_at timestamptz NOT NULL DEFAULT now()
|
|
261
|
-
);
|
|
262
|
-
|
|
263
|
-
CREATE INDEX IF NOT EXISTS schedules_tenant_kind ON public.schedules(tenant_id, kind);
|
|
264
|
-
CREATE INDEX IF NOT EXISTS schedules_assignee ON public.schedules(assignee_id, day_of_week);
|
|
265
|
-
DROP TRIGGER IF EXISTS schedules_updated_at ON public.schedules;
|
|
266
|
-
CREATE TRIGGER schedules_updated_at BEFORE UPDATE ON public.schedules
|
|
267
|
-
FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();
|
|
268
|
-
|
|
269
|
-
-- ============================================================================
|
|
270
|
-
-- RLS policies — tenant isolation for all archetype tables
|
|
271
|
-
-- ============================================================================
|
|
272
|
-
|
|
273
|
-
DO $$
|
|
274
|
-
DECLARE
|
|
275
|
-
tbl text;
|
|
276
|
-
BEGIN
|
|
277
|
-
FOREACH tbl IN ARRAY ARRAY[
|
|
278
|
-
'people', 'categories', 'products', 'services',
|
|
279
|
-
'orders', 'transactions', 'appointments', 'schedules'
|
|
280
|
-
]
|
|
281
|
-
LOOP
|
|
282
|
-
EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', tbl);
|
|
283
|
-
-- Drop first so a replay on an already-provisioned pool no-ops cleanly.
|
|
284
|
-
EXECUTE format('DROP POLICY IF EXISTS "%s_select" ON public.%I', tbl, tbl);
|
|
285
|
-
EXECUTE format('DROP POLICY IF EXISTS "%s_insert" ON public.%I', tbl, tbl);
|
|
286
|
-
EXECUTE format('DROP POLICY IF EXISTS "%s_update" ON public.%I', tbl, tbl);
|
|
287
|
-
EXECUTE format('DROP POLICY IF EXISTS "%s_delete" ON public.%I', tbl, tbl);
|
|
288
|
-
EXECUTE format(
|
|
289
|
-
'CREATE POLICY "%s_select" ON public.%I FOR SELECT TO authenticated USING (tenant_id IN (SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid()))',
|
|
290
|
-
tbl, tbl
|
|
291
|
-
);
|
|
292
|
-
EXECUTE format(
|
|
293
|
-
'CREATE POLICY "%s_insert" ON public.%I FOR INSERT TO authenticated WITH CHECK (tenant_id IN (SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid()))',
|
|
294
|
-
tbl, tbl
|
|
295
|
-
);
|
|
296
|
-
EXECUTE format(
|
|
297
|
-
'CREATE POLICY "%s_update" ON public.%I FOR UPDATE TO authenticated USING (tenant_id IN (SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid()))',
|
|
298
|
-
tbl, tbl
|
|
299
|
-
);
|
|
300
|
-
EXECUTE format(
|
|
301
|
-
'CREATE POLICY "%s_delete" ON public.%I FOR DELETE TO authenticated USING (tenant_id IN (SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid()))',
|
|
302
|
-
tbl, tbl
|
|
303
|
-
);
|
|
304
|
-
END LOOP;
|
|
305
|
-
|
|
306
|
-
-- Child tables (order_items, appointment_items) — RLS via parent FK
|
|
307
|
-
FOREACH tbl IN ARRAY ARRAY['order_items', 'appointment_items']
|
|
308
|
-
LOOP
|
|
309
|
-
EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', tbl);
|
|
310
|
-
END LOOP;
|
|
311
|
-
END $$;
|
|
312
|
-
|
|
313
|
-
-- order_items: access via parent order's tenant
|
|
314
|
-
DROP POLICY IF EXISTS "order_items_select" ON public.order_items;
|
|
315
|
-
CREATE POLICY "order_items_select" ON public.order_items FOR SELECT TO authenticated
|
|
316
|
-
USING (order_id IN (SELECT id FROM public.orders WHERE tenant_id IN (SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid())));
|
|
317
|
-
DROP POLICY IF EXISTS "order_items_insert" ON public.order_items;
|
|
318
|
-
CREATE POLICY "order_items_insert" ON public.order_items FOR INSERT TO authenticated
|
|
319
|
-
WITH CHECK (order_id IN (SELECT id FROM public.orders WHERE tenant_id IN (SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid())));
|
|
320
|
-
DROP POLICY IF EXISTS "order_items_update" ON public.order_items;
|
|
321
|
-
CREATE POLICY "order_items_update" ON public.order_items FOR UPDATE TO authenticated
|
|
322
|
-
USING (order_id IN (SELECT id FROM public.orders WHERE tenant_id IN (SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid())));
|
|
323
|
-
DROP POLICY IF EXISTS "order_items_delete" ON public.order_items;
|
|
324
|
-
CREATE POLICY "order_items_delete" ON public.order_items FOR DELETE TO authenticated
|
|
325
|
-
USING (order_id IN (SELECT id FROM public.orders WHERE tenant_id IN (SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid())));
|
|
326
|
-
|
|
327
|
-
-- appointment_items: access via parent appointment's tenant
|
|
328
|
-
DROP POLICY IF EXISTS "appointment_items_select" ON public.appointment_items;
|
|
329
|
-
CREATE POLICY "appointment_items_select" ON public.appointment_items FOR SELECT TO authenticated
|
|
330
|
-
USING (booking_id IN (SELECT id FROM public.appointments WHERE tenant_id IN (SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid())));
|
|
331
|
-
DROP POLICY IF EXISTS "appointment_items_insert" ON public.appointment_items;
|
|
332
|
-
CREATE POLICY "appointment_items_insert" ON public.appointment_items FOR INSERT TO authenticated
|
|
333
|
-
WITH CHECK (booking_id IN (SELECT id FROM public.appointments WHERE tenant_id IN (SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid())));
|
|
334
|
-
DROP POLICY IF EXISTS "appointment_items_update" ON public.appointment_items;
|
|
335
|
-
CREATE POLICY "appointment_items_update" ON public.appointment_items FOR UPDATE TO authenticated
|
|
336
|
-
USING (booking_id IN (SELECT id FROM public.appointments WHERE tenant_id IN (SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid())));
|
|
337
|
-
DROP POLICY IF EXISTS "appointment_items_delete" ON public.appointment_items;
|
|
338
|
-
CREATE POLICY "appointment_items_delete" ON public.appointment_items FOR DELETE TO authenticated
|
|
339
|
-
USING (booking_id IN (SELECT id FROM public.appointments WHERE tenant_id IN (SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid())));
|
|
340
|
-
|
|
341
|
-
-- Grant access to archetype tables
|
|
342
|
-
GRANT ALL ON ALL TABLES IN SCHEMA public TO authenticated, service_role;
|
|
343
|
-
GRANT SELECT ON ALL TABLES IN SCHEMA public TO anon;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
-- Bring public.locations in line with other archetype tables
|
|
2
|
-
ALTER TABLE public.locations
|
|
3
|
-
ADD COLUMN IF NOT EXISTS kind text NOT NULL DEFAULT 'branch',
|
|
4
|
-
ADD COLUMN IF NOT EXISTS email text,
|
|
5
|
-
ADD COLUMN IF NOT EXISTS postal_code text,
|
|
6
|
-
ADD COLUMN IF NOT EXISTS tags text[] DEFAULT '{}',
|
|
7
|
-
ADD COLUMN IF NOT EXISTS notes text,
|
|
8
|
-
ADD COLUMN IF NOT EXISTS metadata jsonb DEFAULT '{}';
|
|
9
|
-
|
|
10
|
-
-- Migrate settings → metadata for existing rows (if settings column still exists)
|
|
11
|
-
DO $$ BEGIN
|
|
12
|
-
IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'locations' AND column_name = 'settings') THEN
|
|
13
|
-
UPDATE public.locations SET metadata = settings WHERE metadata = '{}' AND settings != '{}';
|
|
14
|
-
ALTER TABLE public.locations DROP COLUMN settings;
|
|
15
|
-
END IF;
|
|
16
|
-
END $$;
|
|
17
|
-
|
|
18
|
-
CREATE INDEX IF NOT EXISTS locations_tenant_kind ON public.locations(tenant_id, kind);
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
-- Fix archetype RLS policies to use SECURITY DEFINER function
|
|
2
|
-
-- The raw subquery on tenant_members fails due to recursive RLS
|
|
3
|
-
|
|
4
|
-
-- Ensure the SECURITY DEFINER helper exists (bypasses RLS)
|
|
5
|
-
CREATE OR REPLACE FUNCTION public.user_tenant_ids()
|
|
6
|
-
RETURNS SETOF uuid
|
|
7
|
-
LANGUAGE sql STABLE SECURITY DEFINER AS $$
|
|
8
|
-
SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid();
|
|
9
|
-
$$;
|
|
10
|
-
|
|
11
|
-
-- Drop and recreate all archetype table policies using the SECURITY DEFINER function
|
|
12
|
-
DO $$
|
|
13
|
-
DECLARE
|
|
14
|
-
tbl text;
|
|
15
|
-
BEGIN
|
|
16
|
-
FOREACH tbl IN ARRAY ARRAY[
|
|
17
|
-
'people', 'categories', 'products', 'services',
|
|
18
|
-
'orders', 'transactions', 'appointments', 'schedules'
|
|
19
|
-
]
|
|
20
|
-
LOOP
|
|
21
|
-
-- Drop old policies
|
|
22
|
-
EXECUTE format('DROP POLICY IF EXISTS "%s_select" ON public.%I', tbl, tbl);
|
|
23
|
-
EXECUTE format('DROP POLICY IF EXISTS "%s_insert" ON public.%I', tbl, tbl);
|
|
24
|
-
EXECUTE format('DROP POLICY IF EXISTS "%s_update" ON public.%I', tbl, tbl);
|
|
25
|
-
EXECUTE format('DROP POLICY IF EXISTS "%s_delete" ON public.%I', tbl, tbl);
|
|
26
|
-
|
|
27
|
-
-- Create new policies using SECURITY DEFINER function
|
|
28
|
-
EXECUTE format(
|
|
29
|
-
'CREATE POLICY "%s_select" ON public.%I FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))',
|
|
30
|
-
tbl, tbl
|
|
31
|
-
);
|
|
32
|
-
EXECUTE format(
|
|
33
|
-
'CREATE POLICY "%s_insert" ON public.%I FOR INSERT TO authenticated WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()))',
|
|
34
|
-
tbl, tbl
|
|
35
|
-
);
|
|
36
|
-
EXECUTE format(
|
|
37
|
-
'CREATE POLICY "%s_update" ON public.%I FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))',
|
|
38
|
-
tbl, tbl
|
|
39
|
-
);
|
|
40
|
-
EXECUTE format(
|
|
41
|
-
'CREATE POLICY "%s_delete" ON public.%I FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))',
|
|
42
|
-
tbl, tbl
|
|
43
|
-
);
|
|
44
|
-
END LOOP;
|
|
45
|
-
END $$;
|
|
46
|
-
|
|
47
|
-
-- Fix child table policies too
|
|
48
|
-
DROP POLICY IF EXISTS "order_items_select" ON public.order_items;
|
|
49
|
-
DROP POLICY IF EXISTS "order_items_insert" ON public.order_items;
|
|
50
|
-
DROP POLICY IF EXISTS "order_items_update" ON public.order_items;
|
|
51
|
-
DROP POLICY IF EXISTS "order_items_delete" ON public.order_items;
|
|
52
|
-
|
|
53
|
-
CREATE POLICY "order_items_select" ON public.order_items FOR SELECT TO authenticated
|
|
54
|
-
USING (order_id IN (SELECT id FROM public.orders WHERE tenant_id IN (SELECT public.user_tenant_ids())));
|
|
55
|
-
CREATE POLICY "order_items_insert" ON public.order_items FOR INSERT TO authenticated
|
|
56
|
-
WITH CHECK (order_id IN (SELECT id FROM public.orders WHERE tenant_id IN (SELECT public.user_tenant_ids())));
|
|
57
|
-
CREATE POLICY "order_items_update" ON public.order_items FOR UPDATE TO authenticated
|
|
58
|
-
USING (order_id IN (SELECT id FROM public.orders WHERE tenant_id IN (SELECT public.user_tenant_ids())));
|
|
59
|
-
CREATE POLICY "order_items_delete" ON public.order_items FOR DELETE TO authenticated
|
|
60
|
-
USING (order_id IN (SELECT id FROM public.orders WHERE tenant_id IN (SELECT public.user_tenant_ids())));
|
|
61
|
-
|
|
62
|
-
DROP POLICY IF EXISTS "appointment_items_select" ON public.appointment_items;
|
|
63
|
-
DROP POLICY IF EXISTS "appointment_items_insert" ON public.appointment_items;
|
|
64
|
-
DROP POLICY IF EXISTS "appointment_items_update" ON public.appointment_items;
|
|
65
|
-
DROP POLICY IF EXISTS "appointment_items_delete" ON public.appointment_items;
|
|
66
|
-
|
|
67
|
-
CREATE POLICY "appointment_items_select" ON public.appointment_items FOR SELECT TO authenticated
|
|
68
|
-
USING (booking_id IN (SELECT id FROM public.appointments WHERE tenant_id IN (SELECT public.user_tenant_ids())));
|
|
69
|
-
CREATE POLICY "appointment_items_insert" ON public.appointment_items FOR INSERT TO authenticated
|
|
70
|
-
WITH CHECK (booking_id IN (SELECT id FROM public.appointments WHERE tenant_id IN (SELECT public.user_tenant_ids())));
|
|
71
|
-
CREATE POLICY "appointment_items_update" ON public.appointment_items FOR UPDATE TO authenticated
|
|
72
|
-
USING (booking_id IN (SELECT id FROM public.appointments WHERE tenant_id IN (SELECT public.user_tenant_ids())));
|
|
73
|
-
CREATE POLICY "appointment_items_delete" ON public.appointment_items FOR DELETE TO authenticated
|
|
74
|
-
USING (booking_id IN (SELECT id FROM public.appointments WHERE tenant_id IN (SELECT public.user_tenant_ids())));
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
-- Grant access to archetype tables created in migration 004
|
|
2
|
-
-- The original GRANT ALL ON ALL TABLES only covered tables that existed at that time
|
|
3
|
-
GRANT ALL ON ALL TABLES IN SCHEMA public TO authenticated, service_role;
|
|
4
|
-
GRANT SELECT ON ALL TABLES IN SCHEMA public TO anon;
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
-- Ensure all roles have access to the public schema
|
|
2
|
-
GRANT USAGE ON SCHEMA public TO anon, authenticated, service_role;
|
|
3
|
-
GRANT ALL ON ALL TABLES IN SCHEMA public TO authenticated, service_role;
|
|
4
|
-
GRANT SELECT ON ALL TABLES IN SCHEMA public TO anon;
|
|
5
|
-
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO anon, authenticated, service_role;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
-- ============================================================================
|
|
2
|
-
-- 009: anon hardening — close 008's blanket grants for the anon role.
|
|
3
|
-
--
|
|
4
|
-
-- 008_grants.sql grants SELECT on all tables and EXECUTE on all functions to
|
|
5
|
-
-- anon. RLS (policies are TO authenticated) already returns zero rows for
|
|
6
|
-
-- table reads, but EXECUTE on SECURITY DEFINER functions like
|
|
7
|
-
-- create_tenant_with_owner is a real abuse surface on projects that serve
|
|
8
|
-
-- public (anon-key) pages. Revoke everything; anon-facing surfaces must grant
|
|
9
|
-
-- themselves explicitly (e.g. plugin-agenda's public booking RPCs/views).
|
|
10
|
-
--
|
|
11
|
-
-- Apply AFTER 008 and BEFORE plugin migrations that grant anon access.
|
|
12
|
-
-- ============================================================================
|
|
13
|
-
|
|
14
|
-
REVOKE EXECUTE ON ALL FUNCTIONS IN SCHEMA public FROM anon;
|
|
15
|
-
|
|
16
|
-
REVOKE SELECT ON ALL TABLES IN SCHEMA public FROM anon;
|
|
17
|
-
|
|
18
|
-
-- Future objects: don't default-grant anon anything.
|
|
19
|
-
ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE EXECUTE ON FUNCTIONS FROM anon;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
-- ============================================================================
|
|
2
|
-
-- 010_migration_ledger.sql — per-pool applied-migration ledger.
|
|
3
|
-
--
|
|
4
|
-
-- The Runner v2 executor records every applied SQL file here (plugin_id +
|
|
5
|
-
-- file_name + checksum) so re-applies are detected and checksum drift on an
|
|
6
|
-
-- already-applied file is a HARD STOP.
|
|
7
|
-
--
|
|
8
|
-
-- service_role only: no anon/authenticated grants, RLS enabled with NO
|
|
9
|
-
-- policies, so PostgREST (anon/authenticated) is deny-all. Only the service
|
|
10
|
-
-- role (which bypasses RLS) — i.e. the runner — can read/write it.
|
|
11
|
-
--
|
|
12
|
-
-- Naming: the ledger is an internal, non-API table, so it uses the `_`-prefixed
|
|
13
|
-
-- `public._migrations` name (excluded from the project_rls auto-policy pass by
|
|
14
|
-
-- the `NOT LIKE '\_%'` filter). Legacy pools provisioned as `fayz_migration_ledger`
|
|
15
|
-
-- are migrated by 012_rename_migration_ledger.sql (and by the runner's
|
|
16
|
-
-- ensureLedger guard); fresh installs are born as `_migrations` here.
|
|
17
|
-
-- ============================================================================
|
|
18
|
-
|
|
19
|
-
CREATE TABLE IF NOT EXISTS public._migrations (
|
|
20
|
-
id bigserial PRIMARY KEY,
|
|
21
|
-
plugin_id text NOT NULL,
|
|
22
|
-
file_name text NOT NULL,
|
|
23
|
-
checksum text NOT NULL,
|
|
24
|
-
plugin_version text,
|
|
25
|
-
applied_at timestamptz NOT NULL DEFAULT now(),
|
|
26
|
-
applied_by text,
|
|
27
|
-
UNIQUE(plugin_id, file_name)
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
ALTER TABLE public._migrations ENABLE ROW LEVEL SECURITY;
|
|
31
|
-
|
|
32
|
-
-- Deny-all through PostgREST: revoke any inherited grants, grant to nobody but
|
|
33
|
-
-- service_role (which bypasses RLS anyway). No policies = no anon/authenticated access.
|
|
34
|
-
REVOKE ALL ON public._migrations FROM anon, authenticated;
|
|
35
|
-
GRANT ALL ON public._migrations TO service_role;
|
|
36
|
-
GRANT USAGE, SELECT ON SEQUENCE public._migrations_id_seq TO service_role;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
-- 009 revoked anon SELECT/EXECUTE but Supabase default privileges also hand
|
|
2
|
-
-- anon INSERT/UPDATE/DELETE/... on every table created by postgres. RLS blocks
|
|
3
|
-
-- those writes today; make the grant layer agree and stop future tables from
|
|
4
|
-
-- being born writable-by-anon.
|
|
5
|
-
|
|
6
|
-
REVOKE INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER
|
|
7
|
-
ON ALL TABLES IN SCHEMA public FROM anon;
|
|
8
|
-
|
|
9
|
-
ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
|
10
|
-
REVOKE INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER ON TABLES FROM anon;
|
|
11
|
-
|
|
12
|
-
ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE SELECT ON TABLES FROM anon;
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
-- ============================================================================
|
|
2
|
-
-- 012_rename_migration_ledger.sql — rename the migration ledger onto the
|
|
3
|
-
-- internal `_`-prefixed baseline name:
|
|
4
|
-
--
|
|
5
|
-
-- public.fayz_migration_ledger → public._migrations
|
|
6
|
-
--
|
|
7
|
-
-- Legacy-pool remediation ONLY: 010_migration_ledger.sql now creates `_migrations`
|
|
8
|
-
-- directly, so fresh installs never reach a rename branch. The runner's
|
|
9
|
-
-- ensureLedger (cli/src/lib/ledger.ts) performs the same guarded rename at the
|
|
10
|
-
-- START of every apply, so on a real pool the ledger is already `_migrations`
|
|
11
|
-
-- by the time this migration runs — this file is the declarative backstop.
|
|
12
|
-
--
|
|
13
|
-
-- Fully idempotent + guarded: each RENAME fires only when the old object exists
|
|
14
|
-
-- and the new one does not. A table RENAME preserves the rows (the applied-file
|
|
15
|
-
-- history MUST survive), plus RLS state, grants and constraints; re-assert the
|
|
16
|
-
-- deny-all grants afterwards to keep the baseline explicit.
|
|
17
|
-
-- ============================================================================
|
|
18
|
-
|
|
19
|
-
DO $$
|
|
20
|
-
BEGIN
|
|
21
|
-
-- Table (carries the applied-migration history — never drop + recreate).
|
|
22
|
-
IF to_regclass('public.fayz_migration_ledger') IS NOT NULL
|
|
23
|
-
AND to_regclass('public._migrations') IS NULL THEN
|
|
24
|
-
ALTER TABLE public.fayz_migration_ledger RENAME TO _migrations;
|
|
25
|
-
END IF;
|
|
26
|
-
|
|
27
|
-
-- bigserial owns fayz_migration_ledger_id_seq — a table rename does not move it.
|
|
28
|
-
IF to_regclass('public.fayz_migration_ledger_id_seq') IS NOT NULL
|
|
29
|
-
AND to_regclass('public._migrations_id_seq') IS NULL THEN
|
|
30
|
-
ALTER SEQUENCE public.fayz_migration_ledger_id_seq RENAME TO _migrations_id_seq;
|
|
31
|
-
END IF;
|
|
32
|
-
|
|
33
|
-
-- Named constraints are auto-named after the old table; rename for parity with
|
|
34
|
-
-- a fresh install. Guard on the new table existing so this is safe pre-rename.
|
|
35
|
-
IF to_regclass('public._migrations') IS NOT NULL THEN
|
|
36
|
-
IF EXISTS (SELECT 1 FROM pg_constraint
|
|
37
|
-
WHERE conname = 'fayz_migration_ledger_pkey'
|
|
38
|
-
AND conrelid = 'public._migrations'::regclass) THEN
|
|
39
|
-
ALTER TABLE public._migrations RENAME CONSTRAINT fayz_migration_ledger_pkey TO _migrations_pkey;
|
|
40
|
-
END IF;
|
|
41
|
-
IF EXISTS (SELECT 1 FROM pg_constraint
|
|
42
|
-
WHERE conname = 'fayz_migration_ledger_plugin_id_file_name_key'
|
|
43
|
-
AND conrelid = 'public._migrations'::regclass) THEN
|
|
44
|
-
ALTER TABLE public._migrations
|
|
45
|
-
RENAME CONSTRAINT fayz_migration_ledger_plugin_id_file_name_key
|
|
46
|
-
TO _migrations_plugin_id_file_name_key;
|
|
47
|
-
END IF;
|
|
48
|
-
END IF;
|
|
49
|
-
END $$;
|
|
50
|
-
|
|
51
|
-
-- Re-assert the deny-all posture (idempotent; RLS/grants survive a rename but the
|
|
52
|
-
-- baseline keeps this explicit so a manually-created ledger converges too).
|
|
53
|
-
DO $$
|
|
54
|
-
BEGIN
|
|
55
|
-
IF to_regclass('public._migrations') IS NOT NULL THEN
|
|
56
|
-
EXECUTE 'ALTER TABLE public._migrations ENABLE ROW LEVEL SECURITY';
|
|
57
|
-
EXECUTE 'REVOKE ALL ON public._migrations FROM anon, authenticated';
|
|
58
|
-
EXECUTE 'GRANT ALL ON public._migrations TO service_role';
|
|
59
|
-
EXECUTE 'GRANT USAGE, SELECT ON SEQUENCE public._migrations_id_seq TO service_role';
|
|
60
|
-
END IF;
|
|
61
|
-
END $$;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
-- ============================================================================
|
|
2
|
-
-- 013_sequences_rls.sql — close the RLS drift on public.sequences.
|
|
3
|
-
--
|
|
4
|
-
-- public.sequences (the REC-/PAG- numbering counter, created by the financial
|
|
5
|
-
-- plugin's 004_order_to_cash.sql) shipped WITHOUT row-level security on a set of
|
|
6
|
-
-- pools. Baseline = RLS ON, deny-all (no policies), exactly like the salon pool:
|
|
7
|
-
-- the table is written ONLY through the SECURITY DEFINER function
|
|
8
|
-
-- public.next_sequence(), which runs as the table owner and so bypasses RLS.
|
|
9
|
-
-- With RLS on and no policy, the PostgREST anon/authenticated surface is deny-all,
|
|
10
|
-
-- so the counter can never be read or tampered with directly by a tenant.
|
|
11
|
-
--
|
|
12
|
-
-- Legacy-pool remediation: guarded so it is a no-op on pools that never enabled
|
|
13
|
-
-- Payments (sequences absent) and idempotent on pools already at RLS ON. Fresh
|
|
14
|
-
-- installs are born with RLS via the financial plugin's own 004_order_to_cash.sql.
|
|
15
|
-
--
|
|
16
|
-
-- NOTE: next_sequence() MUST be SECURITY DEFINER for the deny-all baseline to
|
|
17
|
-
-- keep working — it is called directly via PostgREST RPC by authenticated users
|
|
18
|
-
-- (plugins/plugin-financial/src/data/supabase.ts → createInvoice). That fix ships
|
|
19
|
-
-- in the financial plugin migration alongside this one.
|
|
20
|
-
-- ============================================================================
|
|
21
|
-
|
|
22
|
-
ALTER TABLE IF EXISTS public.sequences ENABLE ROW LEVEL SECURITY;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
-- ============================================================================
|
|
2
|
-
-- 014_plan_entitlements.sql — plans carry machine-readable entitlements.
|
|
3
|
-
--
|
|
4
|
-
-- public.plans shipped with `features jsonb` as DISPLAY BULLETS only — nothing
|
|
5
|
-
-- in the pool encodes what a plan actually gates. Server-side enforcement (the
|
|
6
|
-
-- agent RPCs' role→plan→limit guard, and eventually RLS defense-in-depth)
|
|
7
|
-
-- needs the SAME `{features: {id: bool}, limits: {key: number}}` structure the
|
|
8
|
-
-- client resolves from `config.billing` (@fayz-ai/core PlanEntitlements; -1 =
|
|
9
|
-
-- unlimited, absent feature = allowed).
|
|
10
|
-
--
|
|
11
|
-
-- Writer: the app's plan catalog is code (billing.ts) → synced into this table
|
|
12
|
-
-- (transitionally by the app seed, then by the Fayz platform on
|
|
13
|
-
-- `fayz manifest sync` — the manifest carries billing.plans verbatim).
|
|
14
|
-
--
|
|
15
|
-
-- `hidden` retires the "qa-free-test plans visible on SubscriptionPage" debt:
|
|
16
|
-
-- QA/internal plans stay selectable by id but are never rendered.
|
|
17
|
-
--
|
|
18
|
-
-- Guarded + idempotent: no-op when the pool predates public.plans (legacy
|
|
19
|
-
-- saas_core pools run their app-local mirror of this ALTER instead).
|
|
20
|
-
-- ============================================================================
|
|
21
|
-
|
|
22
|
-
DO $$
|
|
23
|
-
BEGIN
|
|
24
|
-
IF to_regclass('public.plans') IS NOT NULL THEN
|
|
25
|
-
ALTER TABLE public.plans ADD COLUMN IF NOT EXISTS entitlements jsonb NOT NULL DEFAULT '{}'::jsonb;
|
|
26
|
-
ALTER TABLE public.plans ADD COLUMN IF NOT EXISTS hidden boolean NOT NULL DEFAULT false;
|
|
27
|
-
END IF;
|
|
28
|
-
END $$;
|