@selvajs/supabase-provider 0.12.0 → 0.13.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.
@@ -1,3 +1,48 @@
1
+ -- ============================================================================
2
+ -- 0. Dedicated `selva` schema
3
+ -- All engine objects live here, never in `public`, so a consuming app that
4
+ -- shares the database keeps `public` entirely for its own tables. Cross-schema
5
+ -- refs from the app (FKs into selva.orgs, calls to selva.is_org_member) are
6
+ -- supported. The provider's data client targets it (db: { schema: 'selva' }).
7
+ --
8
+ -- PostgREST must expose `selva` to serve it over REST. We do that HERE, from the
9
+ -- migration, rather than from config.toml's static `[api] schemas`: that config
10
+ -- is read at stack boot, before migrations run, so naming a not-yet-created
11
+ -- schema there fails the health check and aborts `supabase start`. Setting it on
12
+ -- the `authenticator` role after the schema exists, then signalling a reload,
13
+ -- avoids the bootstrap race and works identically on hosted projects.
14
+ -- ============================================================================
15
+ create schema if not exists selva;
16
+ grant usage on schema selva to anon, authenticated, service_role;
17
+ alter default privileges in schema selva grant all on tables to anon, authenticated, service_role;
18
+ alter default privileges in schema selva grant all on functions to anon, authenticated, service_role;
19
+ alter default privileges in schema selva grant all on sequences to anon, authenticated, service_role;
20
+
21
+ -- Expose `selva` over PostgREST (additive to whatever is already exposed).
22
+ do $$
23
+ declare
24
+ current_schemas text;
25
+ begin
26
+ select coalesce(
27
+ (select setting from pg_db_role_setting s
28
+ join pg_roles r on r.oid = s.setrole
29
+ cross join lateral unnest(s.setconfig) as setting
30
+ where r.rolname = 'authenticator' and setting like 'pgrst.db_schemas=%'),
31
+ 'pgrst.db_schemas=public, graphql_public'
32
+ ) into current_schemas;
33
+
34
+ if current_schemas not like '%selva%' then
35
+ execute format(
36
+ 'alter role authenticator set pgrst.db_schemas = %L',
37
+ replace(current_schemas, 'pgrst.db_schemas=', '') || ', selva'
38
+ );
39
+ end if;
40
+ end $$;
41
+
42
+ notify pgrst, 'reload config';
43
+ notify pgrst, 'reload schema';
44
+
45
+
1
46
  -- ============================================================================
2
47
  -- Selva — initial schema (consolidated bootstrap).
3
48
  --
@@ -27,7 +72,7 @@
27
72
  -- Maintains updated_at on every UPDATE without adapter involvement.
28
73
  -- ============================================================================
29
74
 
30
- create or replace function public.set_updated_at()
75
+ create or replace function selva.set_updated_at()
31
76
  returns trigger
32
77
  language plpgsql
33
78
  as $$
@@ -44,7 +89,7 @@ $$;
44
89
  -- starred definitions, recent runs). Auto-seeded by trigger on signup.
45
90
  -- ============================================================================
46
91
 
47
- create table if not exists public.user_profiles (
92
+ create table if not exists selva.user_profiles (
48
93
  user_id uuid primary key references auth.users(id) on delete cascade,
49
94
  display_name text,
50
95
  platform_permissions text[] not null default '{}',
@@ -54,14 +99,14 @@ create table if not exists public.user_profiles (
54
99
  last_login_at timestamptz
55
100
  );
56
101
 
57
- create or replace function public.handle_new_auth_user()
102
+ create or replace function selva.handle_new_auth_user()
58
103
  returns trigger
59
104
  language plpgsql
60
105
  security definer
61
106
  set search_path = public
62
107
  as $$
63
108
  begin
64
- insert into public.user_profiles (user_id)
109
+ insert into selva.user_profiles (user_id)
65
110
  values (new.id)
66
111
  on conflict (user_id) do nothing;
67
112
  return new;
@@ -71,17 +116,17 @@ $$;
71
116
  drop trigger if exists trg_auth_user_created on auth.users;
72
117
  create trigger trg_auth_user_created
73
118
  after insert on auth.users
74
- for each row execute function public.handle_new_auth_user();
119
+ for each row execute function selva.handle_new_auth_user();
75
120
 
76
- alter table public.user_profiles enable row level security;
121
+ alter table selva.user_profiles enable row level security;
77
122
 
78
123
  create policy "user_profiles: any authenticated can read"
79
- on public.user_profiles for select
124
+ on selva.user_profiles for select
80
125
  to authenticated
81
126
  using (true);
82
127
 
83
128
  create policy "user_profiles: users can update own"
84
- on public.user_profiles for update
129
+ on selva.user_profiles for update
85
130
  to authenticated
86
131
  using (user_id = auth.uid())
87
132
  with check (
@@ -89,7 +134,7 @@ with check (
89
134
  -- Users cannot escalate their own platform permissions; only service-role
90
135
  -- writes (which bypass RLS) may change that column.
91
136
  and platform_permissions is not distinct from (
92
- select platform_permissions from public.user_profiles where user_id = auth.uid()
137
+ select platform_permissions from selva.user_profiles where user_id = auth.uid()
93
138
  )
94
139
  );
95
140
 
@@ -100,7 +145,7 @@ with check (
100
145
  -- reads filter deleted_at IS NULL.
101
146
  -- ============================================================================
102
147
 
103
- create table if not exists public.orgs (
148
+ create table if not exists selva.orgs (
104
149
  id uuid primary key,
105
150
  name text not null,
106
151
  slug text not null unique,
@@ -111,10 +156,10 @@ create table if not exists public.orgs (
111
156
  updated_at timestamptz not null default now(),
112
157
  deleted_at timestamptz
113
158
  );
114
- create index if not exists idx_orgs_live on public.orgs(id) where deleted_at is null;
159
+ create index if not exists idx_orgs_live on selva.orgs(id) where deleted_at is null;
115
160
 
116
- create table if not exists public.org_members (
117
- org_id uuid not null references public.orgs(id) on delete cascade,
161
+ create table if not exists selva.org_members (
162
+ org_id uuid not null references selva.orgs(id) on delete cascade,
118
163
  user_id uuid not null references auth.users(id) on delete cascade,
119
164
  role text not null check (role in ('owner', 'admin', 'member')),
120
165
  permissions text[] not null default '{}',
@@ -125,11 +170,11 @@ create table if not exists public.org_members (
125
170
  primary key (org_id, user_id)
126
171
  );
127
172
  create index if not exists idx_org_members_user
128
- on public.org_members(user_id) where deleted_at is null;
173
+ on selva.org_members(user_id) where deleted_at is null;
129
174
 
130
- create table if not exists public.projects (
175
+ create table if not exists selva.projects (
131
176
  id uuid primary key,
132
- org_id uuid not null references public.orgs(id) on delete cascade,
177
+ org_id uuid not null references selva.orgs(id) on delete cascade,
133
178
  name text not null,
134
179
  slug text not null,
135
180
  description text,
@@ -142,19 +187,19 @@ create table if not exists public.projects (
142
187
  updated_at timestamptz not null default now(),
143
188
  deleted_at timestamptz,
144
189
  unique (org_id, slug),
145
- -- Spec §4: commons mode requires visibility=public.
190
+ -- Spec §4: commons mode requires visibility=selva.
146
191
  constraint projects_commons_requires_public check (
147
192
  auto_join_on_upload = false or visibility = 'public'
148
193
  )
149
194
  );
150
195
  create index if not exists idx_projects_org
151
- on public.projects(org_id) where deleted_at is null;
196
+ on selva.projects(org_id) where deleted_at is null;
152
197
  -- Case-insensitive unique name per org (defense beyond slug uniqueness).
153
198
  create unique index if not exists projects_org_name_unique
154
- on public.projects (org_id, lower(name));
199
+ on selva.projects (org_id, lower(name));
155
200
 
156
- create table if not exists public.project_members (
157
- project_id uuid not null references public.projects(id) on delete cascade,
201
+ create table if not exists selva.project_members (
202
+ project_id uuid not null references selva.projects(id) on delete cascade,
158
203
  user_id uuid not null references auth.users(id) on delete cascade,
159
204
  role text not null check (role in ('owner', 'editor', 'viewer')),
160
205
  joined_at timestamptz not null default now(),
@@ -164,21 +209,21 @@ create table if not exists public.project_members (
164
209
  primary key (project_id, user_id)
165
210
  );
166
211
  create index if not exists idx_project_members_user
167
- on public.project_members(user_id) where deleted_at is null;
212
+ on selva.project_members(user_id) where deleted_at is null;
168
213
 
169
214
 
170
215
  -- ============================================================================
171
216
  -- 4. updated_at triggers
172
217
  -- ============================================================================
173
218
 
174
- create trigger trg_orgs_updated_at before update on public.orgs
175
- for each row execute function public.set_updated_at();
176
- create trigger trg_projects_updated_at before update on public.projects
177
- for each row execute function public.set_updated_at();
178
- create trigger trg_org_members_updated_at before update on public.org_members
179
- for each row execute function public.set_updated_at();
180
- create trigger trg_project_members_updated_at before update on public.project_members
181
- for each row execute function public.set_updated_at();
219
+ create trigger trg_orgs_updated_at before update on selva.orgs
220
+ for each row execute function selva.set_updated_at();
221
+ create trigger trg_projects_updated_at before update on selva.projects
222
+ for each row execute function selva.set_updated_at();
223
+ create trigger trg_org_members_updated_at before update on selva.org_members
224
+ for each row execute function selva.set_updated_at();
225
+ create trigger trg_project_members_updated_at before update on selva.project_members
226
+ for each row execute function selva.set_updated_at();
182
227
 
183
228
 
184
229
  -- ============================================================================
@@ -187,83 +232,83 @@ create trigger trg_project_members_updated_at before update on public.project_me
187
232
  -- recursion). All filter deleted_at IS NULL.
188
233
  -- ============================================================================
189
234
 
190
- create or replace function public.is_instance_admin()
235
+ create or replace function selva.is_instance_admin()
191
236
  returns boolean
192
237
  language sql stable security definer set search_path = public
193
238
  as $$
194
239
  select exists (
195
- select 1 from public.user_profiles
240
+ select 1 from selva.user_profiles
196
241
  where user_id = auth.uid() and 'instance_admin' = any(platform_permissions)
197
242
  );
198
243
  $$;
199
244
 
200
- create or replace function public.is_org_member(o uuid)
245
+ create or replace function selva.is_org_member(o uuid)
201
246
  returns boolean
202
247
  language sql stable security definer set search_path = public
203
248
  as $$
204
249
  select exists (
205
- select 1 from public.org_members
250
+ select 1 from selva.org_members
206
251
  where org_id = o and user_id = auth.uid() and deleted_at is null
207
252
  );
208
253
  $$;
209
254
 
210
- create or replace function public.is_org_admin(o uuid)
255
+ create or replace function selva.is_org_admin(o uuid)
211
256
  returns boolean
212
257
  language sql stable security definer set search_path = public
213
258
  as $$
214
259
  select exists (
215
- select 1 from public.org_members
260
+ select 1 from selva.org_members
216
261
  where org_id = o and user_id = auth.uid() and deleted_at is null
217
262
  and role in ('owner', 'admin')
218
263
  );
219
264
  $$;
220
265
 
221
- create or replace function public.is_org_owner(o uuid)
266
+ create or replace function selva.is_org_owner(o uuid)
222
267
  returns boolean
223
268
  language sql stable security definer set search_path = public
224
269
  as $$
225
270
  select exists (
226
- select 1 from public.org_members
271
+ select 1 from selva.org_members
227
272
  where org_id = o and user_id = auth.uid() and deleted_at is null
228
273
  and role = 'owner'
229
274
  );
230
275
  $$;
231
276
 
232
- create or replace function public.has_org_permission(o uuid, perm text)
277
+ create or replace function selva.has_org_permission(o uuid, perm text)
233
278
  returns boolean
234
279
  language sql stable security definer set search_path = public
235
280
  as $$
236
- select public.is_instance_admin() or exists (
237
- select 1 from public.org_members
281
+ select selva.is_instance_admin() or exists (
282
+ select 1 from selva.org_members
238
283
  where org_id = o and user_id = auth.uid() and deleted_at is null
239
284
  and perm = any(permissions)
240
285
  );
241
286
  $$;
242
287
 
243
- create or replace function public.is_project_member(p uuid)
288
+ create or replace function selva.is_project_member(p uuid)
244
289
  returns boolean
245
290
  language sql stable security definer set search_path = public
246
291
  as $$
247
292
  select exists (
248
- select 1 from public.project_members
293
+ select 1 from selva.project_members
249
294
  where project_id = p and user_id = auth.uid() and deleted_at is null
250
295
  );
251
296
  $$;
252
297
 
253
298
  -- Spec §5 canView: private → member, org → org member, public → everyone.
254
- create or replace function public.visible_project(p uuid)
299
+ create or replace function selva.visible_project(p uuid)
255
300
  returns boolean
256
301
  language sql stable security definer set search_path = public
257
302
  as $$
258
- select public.is_instance_admin() or exists (
303
+ select selva.is_instance_admin() or exists (
259
304
  select 1
260
- from public.projects
305
+ from selva.projects
261
306
  where id = p
262
307
  and deleted_at is null
263
308
  and (
264
309
  visibility = 'public'
265
- or (visibility = 'org' and public.is_org_member(org_id))
266
- or public.is_project_member(id)
310
+ or (visibility = 'org' and selva.is_org_member(org_id))
311
+ or selva.is_project_member(id)
267
312
  )
268
313
  );
269
314
  $$;
@@ -273,7 +318,7 @@ $$;
273
318
  -- 6. Org / project RLS policies
274
319
  -- ============================================================================
275
320
 
276
- alter table public.orgs enable row level security;
321
+ alter table selva.orgs enable row level security;
277
322
 
278
323
  -- RLS gates "may this principal touch this row?", not "is the row in a state
279
324
  -- worth showing?". Soft-delete filtering (`deleted_at is null`) belongs at the
@@ -284,118 +329,118 @@ alter table public.orgs enable row level security;
284
329
  -- out the just-tombstoned row and surfaces as "new row violates RLS". Same
285
330
  -- trap for `revoked_at` on share_links below.
286
331
  create policy "orgs: members and instance admins can read"
287
- on public.orgs for select
332
+ on selva.orgs for select
288
333
  to authenticated
289
- using (public.is_instance_admin() or public.is_org_member(id));
334
+ using (selva.is_instance_admin() or selva.is_org_member(id));
290
335
 
291
336
  create policy "orgs: authenticated can create their own"
292
- on public.orgs for insert
337
+ on selva.orgs for insert
293
338
  to authenticated
294
- with check (public.is_instance_admin() or owner_id = auth.uid());
339
+ with check (selva.is_instance_admin() or owner_id = auth.uid());
295
340
 
296
341
  create policy "orgs: owners and instance admins can update"
297
- on public.orgs for update
342
+ on selva.orgs for update
298
343
  to authenticated
299
- using (public.is_instance_admin() or public.is_org_owner(id))
300
- with check (public.is_instance_admin() or public.is_org_owner(id));
344
+ using (selva.is_instance_admin() or selva.is_org_owner(id))
345
+ with check (selva.is_instance_admin() or selva.is_org_owner(id));
301
346
 
302
347
  create policy "orgs: owners and instance admins can delete"
303
- on public.orgs for delete
348
+ on selva.orgs for delete
304
349
  to authenticated
305
- using (public.is_instance_admin() or public.is_org_owner(id));
350
+ using (selva.is_instance_admin() or selva.is_org_owner(id));
306
351
 
307
- alter table public.org_members enable row level security;
352
+ alter table selva.org_members enable row level security;
308
353
 
309
354
  create policy "org_members: org members can read roster"
310
- on public.org_members for select
355
+ on selva.org_members for select
311
356
  to authenticated
312
- using (public.is_instance_admin() or public.is_org_member(org_id));
357
+ using (selva.is_instance_admin() or selva.is_org_member(org_id));
313
358
 
314
359
  create policy "org_members: admins can insert"
315
- on public.org_members for insert
360
+ on selva.org_members for insert
316
361
  to authenticated
317
- with check (public.is_instance_admin() or public.is_org_admin(org_id));
362
+ with check (selva.is_instance_admin() or selva.is_org_admin(org_id));
318
363
 
319
364
  create policy "org_members: admins can update"
320
- on public.org_members for update
365
+ on selva.org_members for update
321
366
  to authenticated
322
- using (public.is_instance_admin() or public.is_org_admin(org_id))
323
- with check (public.is_instance_admin() or public.is_org_admin(org_id));
367
+ using (selva.is_instance_admin() or selva.is_org_admin(org_id))
368
+ with check (selva.is_instance_admin() or selva.is_org_admin(org_id));
324
369
 
325
370
  create policy "org_members: admins can delete"
326
- on public.org_members for delete
371
+ on selva.org_members for delete
327
372
  to authenticated
328
- using (public.is_instance_admin() or public.is_org_admin(org_id));
373
+ using (selva.is_instance_admin() or selva.is_org_admin(org_id));
329
374
 
330
- alter table public.projects enable row level security;
375
+ alter table selva.projects enable row level security;
331
376
 
332
377
  create policy "projects: visible to members"
333
- on public.projects for select
378
+ on selva.projects for select
334
379
  to authenticated
335
- using (public.visible_project(id));
380
+ using (selva.visible_project(id));
336
381
 
337
382
  create policy "projects: manage_projects can create"
338
- on public.projects for insert
383
+ on selva.projects for insert
339
384
  to authenticated
340
- with check (public.has_org_permission(org_id, 'manage_projects'));
385
+ with check (selva.has_org_permission(org_id, 'manage_projects'));
341
386
 
342
387
  -- Project settings (name, slug, description, visibility, flags) are owner-only.
343
388
  create policy "projects: owners can update"
344
- on public.projects for update
389
+ on selva.projects for update
345
390
  to authenticated
346
- using (public.is_instance_admin() or owner_id = auth.uid())
347
- with check (public.is_instance_admin() or owner_id = auth.uid());
391
+ using (selva.is_instance_admin() or owner_id = auth.uid())
392
+ with check (selva.is_instance_admin() or owner_id = auth.uid());
348
393
 
349
394
  create policy "projects: owners can delete"
350
- on public.projects for delete
395
+ on selva.projects for delete
351
396
  to authenticated
352
- using (public.is_instance_admin() or owner_id = auth.uid());
397
+ using (selva.is_instance_admin() or owner_id = auth.uid());
353
398
 
354
- alter table public.project_members enable row level security;
399
+ alter table selva.project_members enable row level security;
355
400
 
356
401
  create policy "project_members: visible to project members"
357
- on public.project_members for select
402
+ on selva.project_members for select
358
403
  to authenticated
359
- using (public.is_instance_admin() or public.visible_project(project_id));
404
+ using (selva.is_instance_admin() or selva.visible_project(project_id));
360
405
 
361
406
  -- canManage (§5) collapses to owner-only; org admins no longer silently
362
407
  -- manage project members.
363
408
  create policy "project_members: managers can insert"
364
- on public.project_members for insert
409
+ on selva.project_members for insert
365
410
  to authenticated
366
411
  with check (
367
- public.is_instance_admin()
412
+ selva.is_instance_admin()
368
413
  or exists (
369
- select 1 from public.projects p
414
+ select 1 from selva.projects p
370
415
  where p.id = project_id and p.deleted_at is null and p.owner_id = auth.uid()
371
416
  )
372
417
  );
373
418
 
374
419
  create policy "project_members: managers can update"
375
- on public.project_members for update
420
+ on selva.project_members for update
376
421
  to authenticated
377
422
  using (
378
- public.is_instance_admin()
423
+ selva.is_instance_admin()
379
424
  or exists (
380
- select 1 from public.projects p
425
+ select 1 from selva.projects p
381
426
  where p.id = project_id and p.deleted_at is null and p.owner_id = auth.uid()
382
427
  )
383
428
  )
384
429
  with check (
385
- public.is_instance_admin()
430
+ selva.is_instance_admin()
386
431
  or exists (
387
- select 1 from public.projects p
432
+ select 1 from selva.projects p
388
433
  where p.id = project_id and p.deleted_at is null and p.owner_id = auth.uid()
389
434
  )
390
435
  );
391
436
 
392
437
  create policy "project_members: managers can delete"
393
- on public.project_members for delete
438
+ on selva.project_members for delete
394
439
  to authenticated
395
440
  using (
396
- public.is_instance_admin()
441
+ selva.is_instance_admin()
397
442
  or exists (
398
- select 1 from public.projects p
443
+ select 1 from selva.projects p
399
444
  where p.id = project_id and p.deleted_at is null and p.owner_id = auth.uid()
400
445
  )
401
446
  );
@@ -413,9 +458,9 @@ using (
413
458
  -- not on definitions — different versions can carry different uploaded shapes.
414
459
  -- ============================================================================
415
460
 
416
- create table if not exists public.definitions (
461
+ create table if not exists selva.definitions (
417
462
  guid uuid primary key,
418
- project_id uuid not null references public.projects(id) on delete cascade,
463
+ project_id uuid not null references selva.projects(id) on delete cascade,
419
464
  owner_id uuid not null references auth.users(id) on delete cascade,
420
465
  created_by uuid references auth.users(id) on delete set null,
421
466
  updated_by uuid references auth.users(id) on delete set null,
@@ -436,19 +481,19 @@ create table if not exists public.definitions (
436
481
  );
437
482
 
438
483
  create index if not exists idx_definitions_project
439
- on public.definitions(project_id) where deleted_at is null;
484
+ on selva.definitions(project_id) where deleted_at is null;
440
485
  create index if not exists idx_definitions_status
441
- on public.definitions(status) where deleted_at is null;
486
+ on selva.definitions(status) where deleted_at is null;
442
487
  create index if not exists idx_definitions_pending_updated
443
- on public.definitions(updated_at)
488
+ on selva.definitions(updated_at)
444
489
  where status = 'pending' and deleted_at is null;
445
490
 
446
- create trigger trg_definitions_updated_at before update on public.definitions
447
- for each row execute function public.set_updated_at();
491
+ create trigger trg_definitions_updated_at before update on selva.definitions
492
+ for each row execute function selva.set_updated_at();
448
493
 
449
- create table if not exists public.definition_versions (
494
+ create table if not exists selva.definition_versions (
450
495
  id uuid primary key,
451
- definition_guid uuid not null references public.definitions(guid) on delete cascade,
496
+ definition_guid uuid not null references selva.definitions(guid) on delete cascade,
452
497
  version_number integer not null check (version_number >= 1),
453
498
  file_ext text not null check (file_ext in ('gh', 'ghx')),
454
499
  file_key text not null,
@@ -459,47 +504,47 @@ create table if not exists public.definition_versions (
459
504
  );
460
505
 
461
506
  create index if not exists idx_definition_versions_def
462
- on public.definition_versions(definition_guid, version_number desc);
507
+ on selva.definition_versions(definition_guid, version_number desc);
463
508
 
464
509
  -- Spec §6 deletion protection: cannot delete a version while it's serving
465
510
  -- either channel. Postgres raises 23503; the store maps that to 409.
466
- alter table public.definitions
511
+ alter table selva.definitions
467
512
  add constraint fk_definitions_live_version
468
- foreign key (live_version_id) references public.definition_versions(id)
513
+ foreign key (live_version_id) references selva.definition_versions(id)
469
514
  on delete restrict;
470
515
 
471
- alter table public.definitions
516
+ alter table selva.definitions
472
517
  add constraint fk_definitions_draft_version
473
- foreign key (draft_version_id) references public.definition_versions(id)
518
+ foreign key (draft_version_id) references selva.definition_versions(id)
474
519
  on delete restrict;
475
520
 
476
521
  -- Atomic run-count increment. Called after each successful solve. No-op on
477
522
  -- missing or soft-deleted rows.
478
- create or replace function public.increment_run_count(g uuid)
523
+ create or replace function selva.increment_run_count(g uuid)
479
524
  returns void
480
525
  language sql security definer set search_path = public
481
526
  as $$
482
- update public.definitions
527
+ update selva.definitions
483
528
  set run_count = run_count + 1
484
529
  where guid = g and deleted_at is null;
485
530
  $$;
486
- grant execute on function public.increment_run_count(uuid) to authenticated, service_role;
531
+ grant execute on function selva.increment_run_count(uuid) to authenticated, service_role;
487
532
 
488
- alter table public.definitions enable row level security;
533
+ alter table selva.definitions enable row level security;
489
534
 
490
535
  create policy "definitions: visible via project"
491
- on public.definitions for select
536
+ on selva.definitions for select
492
537
  to authenticated
493
- using (public.visible_project(project_id));
538
+ using (selva.visible_project(project_id));
494
539
 
495
540
  create policy "definitions: editors can insert"
496
- on public.definitions for insert
541
+ on selva.definitions for insert
497
542
  to authenticated
498
543
  with check (
499
- public.is_instance_admin()
544
+ selva.is_instance_admin()
500
545
  -- Container mode: project editor/owner required.
501
546
  or exists (
502
- select 1 from public.project_members m
547
+ select 1 from selva.project_members m
503
548
  where m.project_id = definitions.project_id
504
549
  and m.user_id = auth.uid()
505
550
  and m.deleted_at is null
@@ -508,7 +553,7 @@ with check (
508
553
  -- Commons mode: any authenticated user may create on a public + commons
509
554
  -- project; they become its owner_id.
510
555
  or exists (
511
- select 1 from public.projects p
556
+ select 1 from selva.projects p
512
557
  where p.id = definitions.project_id
513
558
  and p.deleted_at is null
514
559
  and p.visibility = 'public'
@@ -518,19 +563,19 @@ with check (
518
563
  );
519
564
 
520
565
  create policy "definitions: editors can update"
521
- on public.definitions for update
566
+ on selva.definitions for update
522
567
  to authenticated
523
568
  using (
524
- public.is_instance_admin()
569
+ selva.is_instance_admin()
525
570
  or exists (
526
- select 1 from public.project_members m
571
+ select 1 from selva.project_members m
527
572
  where m.project_id = definitions.project_id
528
573
  and m.user_id = auth.uid()
529
574
  and m.deleted_at is null
530
575
  and m.role in ('owner', 'editor')
531
576
  )
532
577
  or exists (
533
- select 1 from public.projects p
578
+ select 1 from selva.projects p
534
579
  where p.id = definitions.project_id
535
580
  and p.deleted_at is null
536
581
  and p.auto_join_on_upload = true
@@ -538,16 +583,16 @@ using (
538
583
  )
539
584
  )
540
585
  with check (
541
- public.is_instance_admin()
586
+ selva.is_instance_admin()
542
587
  or exists (
543
- select 1 from public.project_members m
588
+ select 1 from selva.project_members m
544
589
  where m.project_id = definitions.project_id
545
590
  and m.user_id = auth.uid()
546
591
  and m.deleted_at is null
547
592
  and m.role in ('owner', 'editor')
548
593
  )
549
594
  or exists (
550
- select 1 from public.projects p
595
+ select 1 from selva.projects p
551
596
  where p.id = definitions.project_id
552
597
  and p.deleted_at is null
553
598
  and p.auto_join_on_upload = true
@@ -556,19 +601,19 @@ with check (
556
601
  );
557
602
 
558
603
  create policy "definitions: editors can delete"
559
- on public.definitions for delete
604
+ on selva.definitions for delete
560
605
  to authenticated
561
606
  using (
562
- public.is_instance_admin()
607
+ selva.is_instance_admin()
563
608
  or exists (
564
- select 1 from public.project_members m
609
+ select 1 from selva.project_members m
565
610
  where m.project_id = definitions.project_id
566
611
  and m.user_id = auth.uid()
567
612
  and m.deleted_at is null
568
613
  and m.role in ('owner', 'editor')
569
614
  )
570
615
  or exists (
571
- select 1 from public.projects p
616
+ select 1 from selva.projects p
572
617
  where p.id = definitions.project_id
573
618
  and p.deleted_at is null
574
619
  and p.auto_join_on_upload = true
@@ -576,31 +621,31 @@ using (
576
621
  )
577
622
  );
578
623
 
579
- alter table public.definition_versions enable row level security;
624
+ alter table selva.definition_versions enable row level security;
580
625
 
581
626
  -- Versions inherit visibility from the parent definition (which inherits
582
627
  -- from the parent project). Versions are immutable — no UPDATE policy.
583
628
  create policy "definition_versions: visible via parent"
584
- on public.definition_versions for select
629
+ on selva.definition_versions for select
585
630
  to authenticated
586
631
  using (
587
632
  exists (
588
- select 1 from public.definitions d
633
+ select 1 from selva.definitions d
589
634
  where d.guid = definition_versions.definition_guid
590
635
  and d.deleted_at is null
591
- and public.visible_project(d.project_id)
636
+ and selva.visible_project(d.project_id)
592
637
  )
593
638
  );
594
639
 
595
640
  create policy "definition_versions: editors can insert"
596
- on public.definition_versions for insert
641
+ on selva.definition_versions for insert
597
642
  to authenticated
598
643
  with check (
599
- public.is_instance_admin()
644
+ selva.is_instance_admin()
600
645
  or exists (
601
646
  select 1
602
- from public.definitions d
603
- join public.project_members m on m.project_id = d.project_id
647
+ from selva.definitions d
648
+ join selva.project_members m on m.project_id = d.project_id
604
649
  where d.guid = definition_guid
605
650
  and d.deleted_at is null
606
651
  and m.user_id = auth.uid()
@@ -609,8 +654,8 @@ with check (
609
654
  )
610
655
  or exists (
611
656
  select 1
612
- from public.definitions d
613
- join public.projects p on p.id = d.project_id
657
+ from selva.definitions d
658
+ join selva.projects p on p.id = d.project_id
614
659
  where d.guid = definition_guid
615
660
  and d.deleted_at is null
616
661
  and p.deleted_at is null
@@ -626,14 +671,14 @@ with check (
626
671
  -- `definitions.live_version_id` / `draft_version_id` never gets a chance to
627
672
  -- raise the 23503 the store maps to a 409. Same authority as INSERT.
628
673
  create policy "definition_versions: editors can delete"
629
- on public.definition_versions for delete
674
+ on selva.definition_versions for delete
630
675
  to authenticated
631
676
  using (
632
- public.is_instance_admin()
677
+ selva.is_instance_admin()
633
678
  or exists (
634
679
  select 1
635
- from public.definitions d
636
- join public.project_members m on m.project_id = d.project_id
680
+ from selva.definitions d
681
+ join selva.project_members m on m.project_id = d.project_id
637
682
  where d.guid = definition_versions.definition_guid
638
683
  and d.deleted_at is null
639
684
  and m.user_id = auth.uid()
@@ -642,8 +687,8 @@ using (
642
687
  )
643
688
  or exists (
644
689
  select 1
645
- from public.definitions d
646
- join public.projects p on p.id = d.project_id
690
+ from selva.definitions d
691
+ join selva.projects p on p.id = d.project_id
647
692
  where d.guid = definition_versions.definition_guid
648
693
  and d.deleted_at is null
649
694
  and p.deleted_at is null
@@ -652,6 +697,41 @@ using (
652
697
  )
653
698
  );
654
699
 
700
+ -- Without an explicit UPDATE policy, RLS silently affects 0 rows on every
701
+ -- `update definition_versions` — `SupabaseDefinitionStore.setVersionSchema`
702
+ -- (which caches the compute-extracted UI schema, migration 0002) returns
703
+ -- success without persisting anything for a user-scoped caller. Same authority
704
+ -- as INSERT/DELETE: project owner/editor, or instance admin.
705
+ create policy "definition_versions: editors can update"
706
+ on selva.definition_versions for update
707
+ to authenticated
708
+ using (
709
+ selva.is_instance_admin()
710
+ or exists (
711
+ select 1
712
+ from selva.definitions d
713
+ join selva.project_members m on m.project_id = d.project_id
714
+ where d.guid = definition_versions.definition_guid
715
+ and d.deleted_at is null
716
+ and m.user_id = auth.uid()
717
+ and m.deleted_at is null
718
+ and m.role in ('owner', 'editor')
719
+ )
720
+ )
721
+ with check (
722
+ selva.is_instance_admin()
723
+ or exists (
724
+ select 1
725
+ from selva.definitions d
726
+ join selva.project_members m on m.project_id = d.project_id
727
+ where d.guid = definition_versions.definition_guid
728
+ and d.deleted_at is null
729
+ and m.user_id = auth.uid()
730
+ and m.deleted_at is null
731
+ and m.role in ('owner', 'editor')
732
+ )
733
+ );
734
+
655
735
 
656
736
  -- ============================================================================
657
737
  -- 8. invites
@@ -666,11 +746,11 @@ using (
666
746
  -- token is shown to the admin once and never persisted. A DB-only leak
667
747
  -- therefore can't be replayed without the instance's INVITE_TOKEN_SECRET.
668
748
  -- Mirrors the share-link design (`share_links.token_hash`).
669
- create table if not exists public.invites (
749
+ create table if not exists selva.invites (
670
750
  id uuid primary key,
671
751
  token_hash text not null unique,
672
752
  email text not null,
673
- org_id uuid not null references public.orgs(id) on delete cascade,
753
+ org_id uuid not null references selva.orgs(id) on delete cascade,
674
754
  org_role text not null check (org_role in ('owner', 'admin', 'member')),
675
755
  org_permissions text[] not null default '{}',
676
756
  invited_by uuid not null references auth.users(id) on delete cascade,
@@ -680,47 +760,47 @@ create table if not exists public.invites (
680
760
  accepted_by_user_id uuid references auth.users(id) on delete set null
681
761
  );
682
762
 
683
- create index if not exists idx_invites_org on public.invites(org_id, created_at desc);
763
+ create index if not exists idx_invites_org on selva.invites(org_id, created_at desc);
684
764
 
685
- alter table public.invites enable row level security;
765
+ alter table selva.invites enable row level security;
686
766
 
687
767
  create policy "invites: manage_org_members can read org invites"
688
- on public.invites for select
768
+ on selva.invites for select
689
769
  to authenticated
690
- using (public.has_org_permission(org_id, 'manage_org_members'));
770
+ using (selva.has_org_permission(org_id, 'manage_org_members'));
691
771
 
692
772
  create policy "invites: manage_org_members can insert"
693
- on public.invites for insert
773
+ on selva.invites for insert
694
774
  to authenticated
695
- with check (public.has_org_permission(org_id, 'manage_org_members'));
775
+ with check (selva.has_org_permission(org_id, 'manage_org_members'));
696
776
 
697
777
  create policy "invites: manage_org_members can update"
698
- on public.invites for update
778
+ on selva.invites for update
699
779
  to authenticated
700
- using (public.has_org_permission(org_id, 'manage_org_members'))
701
- with check (public.has_org_permission(org_id, 'manage_org_members'));
780
+ using (selva.has_org_permission(org_id, 'manage_org_members'))
781
+ with check (selva.has_org_permission(org_id, 'manage_org_members'));
702
782
 
703
783
  create policy "invites: manage_org_members can delete"
704
- on public.invites for delete
784
+ on selva.invites for delete
705
785
  to authenticated
706
- using (public.has_org_permission(org_id, 'manage_org_members'));
786
+ using (selva.has_org_permission(org_id, 'manage_org_members'));
707
787
 
708
788
  -- Hash-gated read via SECURITY DEFINER so the token itself is the capability.
709
789
  -- Caller hashes the raw URL token at the route layer and passes the digest;
710
790
  -- the function just looks up the row. Returns SETOF so a missing match
711
791
  -- becomes an empty array (not a composite of nulls).
712
- create or replace function public.get_invite_by_token_hash(h text)
713
- returns setof public.invites
792
+ create or replace function selva.get_invite_by_token_hash(h text)
793
+ returns setof selva.invites
714
794
  language sql stable security definer set search_path = public
715
795
  as $$
716
796
  select *
717
- from public.invites
797
+ from selva.invites
718
798
  where token_hash = h
719
799
  and accepted_at is null
720
800
  and expires_at > now()
721
801
  limit 1;
722
802
  $$;
723
- grant execute on function public.get_invite_by_token_hash(text) to anon, authenticated, service_role;
803
+ grant execute on function selva.get_invite_by_token_hash(text) to anon, authenticated, service_role;
724
804
 
725
805
 
726
806
  -- ============================================================================
@@ -759,10 +839,10 @@ grant execute on function public.get_invite_by_token_hash(text) to anon, authent
759
839
  -- `owner_org_id` is required and visibility is implicit (only members
760
840
  -- of `owner_org_id` can see it). Gated by the platform flag
761
841
  -- ALLOW_ORG_COMPUTE_OVERRIDE at the TS layer.
762
- create table if not exists public.compute_servers (
842
+ create table if not exists selva.compute_servers (
763
843
  id uuid primary key,
764
844
  scope text not null check (scope in ('platform', 'org')),
765
- owner_org_id uuid references public.orgs(id) on delete cascade,
845
+ owner_org_id uuid references selva.orgs(id) on delete cascade,
766
846
  shared_with_all boolean not null default false,
767
847
  label text not null,
768
848
  server_url text not null,
@@ -776,37 +856,37 @@ create table if not exists public.compute_servers (
776
856
  or (scope = 'org' and owner_org_id is not null and shared_with_all = false)
777
857
  )
778
858
  );
779
- create index if not exists idx_compute_servers_owner_org on public.compute_servers(owner_org_id);
859
+ create index if not exists idx_compute_servers_owner_org on selva.compute_servers(owner_org_id);
780
860
 
781
861
  -- Per-org share allowlist for platform servers. Empty rows = dormant
782
862
  -- platform server (admin-only) unless it's the global default.
783
- create table if not exists public.compute_server_shares (
784
- server_id uuid not null references public.compute_servers(id) on delete cascade,
785
- org_id uuid not null references public.orgs(id) on delete cascade,
863
+ create table if not exists selva.compute_server_shares (
864
+ server_id uuid not null references selva.compute_servers(id) on delete cascade,
865
+ org_id uuid not null references selva.orgs(id) on delete cascade,
786
866
  primary key (server_id, org_id)
787
867
  );
788
- create index if not exists idx_compute_server_shares_org on public.compute_server_shares(org_id);
868
+ create index if not exists idx_compute_server_shares_org on selva.compute_server_shares(org_id);
789
869
 
790
870
  -- Per-org default override (orgDefaults[orgId]).
791
- create table if not exists public.compute_server_org_defaults (
792
- org_id uuid primary key references public.orgs(id) on delete cascade,
793
- default_server_id uuid references public.compute_servers(id) on delete set null
871
+ create table if not exists selva.compute_server_org_defaults (
872
+ org_id uuid primary key references selva.orgs(id) on delete cascade,
873
+ default_server_id uuid references selva.compute_servers(id) on delete set null
794
874
  );
795
875
 
796
876
  -- Single-row sentinel for the global default.
797
- create table if not exists public.compute_server_platform_default (
877
+ create table if not exists selva.compute_server_platform_default (
798
878
  singleton boolean primary key default true,
799
- default_server_id uuid references public.compute_servers(id) on delete set null,
879
+ default_server_id uuid references selva.compute_servers(id) on delete set null,
800
880
  check (singleton)
801
881
  );
802
- insert into public.compute_server_platform_default (singleton, default_server_id)
882
+ insert into selva.compute_server_platform_default (singleton, default_server_id)
803
883
  values (true, null)
804
884
  on conflict (singleton) do nothing;
805
885
 
806
- alter table public.compute_servers enable row level security;
807
- alter table public.compute_server_shares enable row level security;
808
- alter table public.compute_server_org_defaults enable row level security;
809
- alter table public.compute_server_platform_default enable row level security;
886
+ alter table selva.compute_servers enable row level security;
887
+ alter table selva.compute_server_shares enable row level security;
888
+ alter table selva.compute_server_org_defaults enable row level security;
889
+ alter table selva.compute_server_platform_default enable row level security;
810
890
 
811
891
  -- Read: instance_admin sees everything. Otherwise visibility follows §3:
812
892
  -- * platform server with shared_with_all = true → all authenticated users
@@ -815,70 +895,70 @@ alter table public.compute_server_platform_default enable row level security;
815
895
  -- * platform server that is the current global default → all (floor)
816
896
  -- * org server → only members of owner_org_id
817
897
  create policy "compute_servers: visibility-scoped read"
818
- on public.compute_servers for select
898
+ on selva.compute_servers for select
819
899
  to authenticated
820
900
  using (
821
- public.is_instance_admin()
901
+ selva.is_instance_admin()
822
902
  or (scope = 'platform' and shared_with_all)
823
903
  or (scope = 'platform' and id = (
824
- select default_server_id from public.compute_server_platform_default where singleton
904
+ select default_server_id from selva.compute_server_platform_default where singleton
825
905
  ))
826
906
  or (scope = 'platform' and exists (
827
- select 1 from public.compute_server_shares s
828
- where s.server_id = compute_servers.id and public.is_org_member(s.org_id)
907
+ select 1 from selva.compute_server_shares s
908
+ where s.server_id = compute_servers.id and selva.is_org_member(s.org_id)
829
909
  ))
830
- or (scope = 'org' and public.is_org_member(owner_org_id))
910
+ or (scope = 'org' and selva.is_org_member(owner_org_id))
831
911
  );
832
912
 
833
913
  -- Writes:
834
914
  -- * scope = 'platform' → instance_admin only.
835
915
  -- * scope = 'org' → manage_org_compute on owner_org_id.
836
916
  create policy "compute_servers: scoped write"
837
- on public.compute_servers for all
917
+ on selva.compute_servers for all
838
918
  to authenticated
839
919
  using (
840
- public.is_instance_admin()
920
+ selva.is_instance_admin()
841
921
  or (scope = 'org' and owner_org_id is not null
842
- and public.has_org_permission(owner_org_id, 'manage_org_compute'))
922
+ and selva.has_org_permission(owner_org_id, 'manage_org_compute'))
843
923
  )
844
924
  with check (
845
- public.is_instance_admin()
925
+ selva.is_instance_admin()
846
926
  or (scope = 'org' and owner_org_id is not null
847
- and public.has_org_permission(owner_org_id, 'manage_org_compute'))
927
+ and selva.has_org_permission(owner_org_id, 'manage_org_compute'))
848
928
  );
849
929
 
850
930
  create policy "compute_server_shares: read"
851
- on public.compute_server_shares for select
931
+ on selva.compute_server_shares for select
852
932
  to authenticated
853
- using (public.is_instance_admin() or public.is_org_member(org_id));
933
+ using (selva.is_instance_admin() or selva.is_org_member(org_id));
854
934
 
855
935
  create policy "compute_server_shares: admin write"
856
- on public.compute_server_shares for all
936
+ on selva.compute_server_shares for all
857
937
  to authenticated
858
- using (public.is_instance_admin())
859
- with check (public.is_instance_admin());
938
+ using (selva.is_instance_admin())
939
+ with check (selva.is_instance_admin());
860
940
 
861
941
  create policy "compute_server_org_defaults: members can read"
862
- on public.compute_server_org_defaults for select
942
+ on selva.compute_server_org_defaults for select
863
943
  to authenticated
864
- using (public.is_instance_admin() or public.is_org_member(org_id));
944
+ using (selva.is_instance_admin() or selva.is_org_member(org_id));
865
945
 
866
946
  create policy "compute_server_org_defaults: manage_org_compute can write"
867
- on public.compute_server_org_defaults for all
947
+ on selva.compute_server_org_defaults for all
868
948
  to authenticated
869
- using (public.is_instance_admin() or public.has_org_permission(org_id, 'manage_org_compute'))
870
- with check (public.is_instance_admin() or public.has_org_permission(org_id, 'manage_org_compute'));
949
+ using (selva.is_instance_admin() or selva.has_org_permission(org_id, 'manage_org_compute'))
950
+ with check (selva.is_instance_admin() or selva.has_org_permission(org_id, 'manage_org_compute'));
871
951
 
872
952
  create policy "compute_server_platform_default: read all"
873
- on public.compute_server_platform_default for select
953
+ on selva.compute_server_platform_default for select
874
954
  to authenticated
875
955
  using (true);
876
956
 
877
957
  create policy "compute_server_platform_default: admin write"
878
- on public.compute_server_platform_default for all
958
+ on selva.compute_server_platform_default for all
879
959
  to authenticated
880
- using (public.is_instance_admin())
881
- with check (public.is_instance_admin());
960
+ using (selva.is_instance_admin())
961
+ with check (selva.is_instance_admin());
882
962
 
883
963
 
884
964
  -- ============================================================================
@@ -889,9 +969,9 @@ with check (public.is_instance_admin());
889
969
  -- raw token is shown to the minter once at creation.
890
970
  -- ============================================================================
891
971
 
892
- create table if not exists public.share_links (
972
+ create table if not exists selva.share_links (
893
973
  id uuid primary key,
894
- definition_guid uuid not null references public.definitions(guid) on delete cascade,
974
+ definition_guid uuid not null references selva.definitions(guid) on delete cascade,
895
975
  channel text not null check (channel in ('live', 'draft')),
896
976
  token_hash text not null unique,
897
977
  name text,
@@ -905,17 +985,17 @@ create table if not exists public.share_links (
905
985
  );
906
986
 
907
987
  create index if not exists idx_share_links_definition
908
- on public.share_links(definition_guid, created_at desc)
988
+ on selva.share_links(definition_guid, created_at desc)
909
989
  where revoked_at is null;
910
990
 
911
991
  -- Atomic check-and-increment. Returns the new solve_count on success, NULL
912
992
  -- when the cap was reached (no row updated) or the link is revoked /
913
993
  -- expired / missing. Single-statement = no race even under concurrent solves.
914
- create or replace function public.try_increment_share_link_solve_count(link_id uuid)
994
+ create or replace function selva.try_increment_share_link_solve_count(link_id uuid)
915
995
  returns integer
916
996
  language sql security definer set search_path = public
917
997
  as $$
918
- update public.share_links
998
+ update selva.share_links
919
999
  set solve_count = solve_count + 1
920
1000
  where id = link_id
921
1001
  and revoked_at is null
@@ -923,10 +1003,10 @@ as $$
923
1003
  and (max_solves is null or solve_count < max_solves)
924
1004
  returning solve_count;
925
1005
  $$;
926
- grant execute on function public.try_increment_share_link_solve_count(uuid)
1006
+ grant execute on function selva.try_increment_share_link_solve_count(uuid)
927
1007
  to authenticated, anon, service_role;
928
1008
 
929
- alter table public.share_links enable row level security;
1009
+ alter table selva.share_links enable row level security;
930
1010
 
931
1011
  -- Read/insert/revoke: same authority that can edit the parent definition
932
1012
  -- (project owner/editor or commons-mode definition owner). Token resolution
@@ -934,14 +1014,14 @@ alter table public.share_links enable row level security;
934
1014
  -- IS the credential there.
935
1015
 
936
1016
  create policy "share_links: editors can read"
937
- on public.share_links for select
1017
+ on selva.share_links for select
938
1018
  to authenticated
939
1019
  using (
940
- public.is_instance_admin()
1020
+ selva.is_instance_admin()
941
1021
  or exists (
942
1022
  select 1
943
- from public.definitions d
944
- join public.project_members m on m.project_id = d.project_id
1023
+ from selva.definitions d
1024
+ join selva.project_members m on m.project_id = d.project_id
945
1025
  where d.guid = share_links.definition_guid
946
1026
  and d.deleted_at is null
947
1027
  and m.user_id = auth.uid()
@@ -950,8 +1030,8 @@ using (
950
1030
  )
951
1031
  or exists (
952
1032
  select 1
953
- from public.definitions d
954
- join public.projects p on p.id = d.project_id
1033
+ from selva.definitions d
1034
+ join selva.projects p on p.id = d.project_id
955
1035
  where d.guid = share_links.definition_guid
956
1036
  and d.deleted_at is null
957
1037
  and p.deleted_at is null
@@ -961,14 +1041,14 @@ using (
961
1041
  );
962
1042
 
963
1043
  create policy "share_links: editors can insert"
964
- on public.share_links for insert
1044
+ on selva.share_links for insert
965
1045
  to authenticated
966
1046
  with check (
967
- public.is_instance_admin()
1047
+ selva.is_instance_admin()
968
1048
  or exists (
969
1049
  select 1
970
- from public.definitions d
971
- join public.project_members m on m.project_id = d.project_id
1050
+ from selva.definitions d
1051
+ join selva.project_members m on m.project_id = d.project_id
972
1052
  where d.guid = share_links.definition_guid
973
1053
  and d.deleted_at is null
974
1054
  and m.user_id = auth.uid()
@@ -977,8 +1057,8 @@ with check (
977
1057
  )
978
1058
  or exists (
979
1059
  select 1
980
- from public.definitions d
981
- join public.projects p on p.id = d.project_id
1060
+ from selva.definitions d
1061
+ join selva.projects p on p.id = d.project_id
982
1062
  where d.guid = share_links.definition_guid
983
1063
  and d.deleted_at is null
984
1064
  and p.deleted_at is null
@@ -989,14 +1069,14 @@ with check (
989
1069
 
990
1070
  -- UPDATE policy covers `revoke` (set revoked_at). Same authority as insert.
991
1071
  create policy "share_links: editors can revoke"
992
- on public.share_links for update
1072
+ on selva.share_links for update
993
1073
  to authenticated
994
1074
  using (
995
- public.is_instance_admin()
1075
+ selva.is_instance_admin()
996
1076
  or exists (
997
1077
  select 1
998
- from public.definitions d
999
- join public.project_members m on m.project_id = d.project_id
1078
+ from selva.definitions d
1079
+ join selva.project_members m on m.project_id = d.project_id
1000
1080
  where d.guid = share_links.definition_guid
1001
1081
  and d.deleted_at is null
1002
1082
  and m.user_id = auth.uid()
@@ -1005,11 +1085,11 @@ using (
1005
1085
  )
1006
1086
  )
1007
1087
  with check (
1008
- public.is_instance_admin()
1088
+ selva.is_instance_admin()
1009
1089
  or exists (
1010
1090
  select 1
1011
- from public.definitions d
1012
- join public.project_members m on m.project_id = d.project_id
1091
+ from selva.definitions d
1092
+ join selva.project_members m on m.project_id = d.project_id
1013
1093
  where d.guid = share_links.definition_guid
1014
1094
  and d.deleted_at is null
1015
1095
  and m.user_id = auth.uid()
@@ -1036,6 +1116,7 @@ with check (
1036
1116
 
1037
1117
  -- selva-public is served directly from the CDN (cover images, brand assets);
1038
1118
  -- anonymous reads are required. Writes are service-role only.
1119
+ drop policy if exists "selva-public: anyone can read" on storage.objects;
1039
1120
  create policy "selva-public: anyone can read"
1040
1121
  on storage.objects for select
1041
1122
  to anon, authenticated
@@ -1061,7 +1142,7 @@ using (bucket_id = 'selva-public');
1061
1142
  -- exists today so audit data is captured from the moment the system goes live.
1062
1143
  -- ============================================================================
1063
1144
 
1064
- create table if not exists public.audit_events (
1145
+ create table if not exists selva.audit_events (
1065
1146
  id uuid primary key default gen_random_uuid(),
1066
1147
  type text not null,
1067
1148
  actor_id text not null,
@@ -1070,15 +1151,15 @@ create table if not exists public.audit_events (
1070
1151
  );
1071
1152
 
1072
1153
  create index if not exists audit_events_occurred_at_idx
1073
- on public.audit_events (occurred_at desc);
1154
+ on selva.audit_events (occurred_at desc);
1074
1155
 
1075
1156
  create index if not exists audit_events_type_occurred_at_idx
1076
- on public.audit_events (type, occurred_at desc);
1157
+ on selva.audit_events (type, occurred_at desc);
1077
1158
 
1078
1159
  create index if not exists audit_events_actor_occurred_at_idx
1079
- on public.audit_events (actor_id, occurred_at desc);
1160
+ on selva.audit_events (actor_id, occurred_at desc);
1080
1161
 
1081
1162
  -- RLS: writes always go through service-role (the sink uses the service
1082
1163
  -- client). Authenticated users have NO read access today — the audit-log
1083
1164
  -- viewer UI will land later with its own instance_admin-only policy.
1084
- alter table public.audit_events enable row level security;
1165
+ alter table selva.audit_events enable row level security;