Public Access
1
0

feat: introduce app-admin authorization and audit logging

- add migrations for owner/member workspace roles and application admins

- centralize /admin access checks with DB-backed admin resolution

- audit admin analytics/billing route access

- update account/admin UI typing and env/docs for ADMIN_EMAILS fallback behavior
This commit is contained in:
pguerrerox
2026-05-25 15:25:59 +00:00
parent 5508e15da1
commit f5e7e966e3
14 changed files with 269 additions and 302 deletions
@@ -0,0 +1,10 @@
update public.workspace_memberships
set role = 'member'
where role = 'admin';
alter table public.workspace_memberships
drop constraint if exists workspace_memberships_role_check;
alter table public.workspace_memberships
add constraint workspace_memberships_role_check
check (role in ('owner', 'member'));
+33
View File
@@ -0,0 +1,33 @@
create table if not exists public.application_admins (
id uuid primary key default gen_random_uuid(),
email text not null,
email_normalized text not null,
status text not null default 'active' check (status in ('active', 'disabled')),
permissions_json jsonb not null default '[]'::jsonb,
created_by_user_id uuid references public.users (id) on delete set null,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create unique index if not exists application_admins_email_normalized_idx on public.application_admins (email_normalized);
drop trigger if exists set_application_admins_updated_at on public.application_admins;
create trigger set_application_admins_updated_at
before update on public.application_admins
for each row
execute function public.set_updated_at();
create table if not exists public.admin_access_audit (
id uuid primary key default gen_random_uuid(),
actor_user_id uuid references public.users (id) on delete set null,
actor_email text,
route text not null,
action text not null,
target_workspace_id uuid references public.workspaces (id) on delete set null,
metadata_json jsonb not null default '{}'::jsonb,
occurred_at timestamptz not null default now()
);
create index if not exists admin_access_audit_occurred_at_idx on public.admin_access_audit (occurred_at desc);
create index if not exists admin_access_audit_actor_user_id_idx on public.admin_access_audit (actor_user_id);
create index if not exists admin_access_audit_target_workspace_id_idx on public.admin_access_audit (target_workspace_id);