@fayz-ai/db 0.8.3 → 0.9.0-next.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.
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
-- 020_fayz_projects.sql — tenant ↔ fayz project association
|
|
2
|
+
-- ----------------------------------------------------------------------------
|
|
3
|
+
-- Almost every tenant owns one or more "fayz projects": deployed sites/apps on
|
|
4
|
+
-- the fayz platform, each addressed by a platform projectId. A tenant's client
|
|
5
|
+
-- site (exposed on the web by fayz) is one such project; an e-commerce client's
|
|
6
|
+
-- site is a project with the storefront module active — i.e. a sales channel.
|
|
7
|
+
--
|
|
8
|
+
-- This table lives in the CLIENT pool (e.g. cluster-ecommerce) and gives the
|
|
9
|
+
-- admin SDK apps a mature link: admin app ↔ tenant ↔ fayz project. It drives the
|
|
10
|
+
-- "Seu site" widget in the sidebar (open preview / open editor), the Loja Online
|
|
11
|
+
-- sales channel (= the storefront project), and Marketing landing-page links.
|
|
12
|
+
--
|
|
13
|
+
-- No platform integration yet: rows are maintained by the admin (manual CRUD),
|
|
14
|
+
-- and the preview/editor URLs are stored explicitly (there is no URL convention
|
|
15
|
+
-- in code and the platform domains are still undecided). A future platform sync
|
|
16
|
+
-- can populate fayz_project_id + URLs automatically.
|
|
17
|
+
--
|
|
18
|
+
-- Additive + idempotent (CREATE TABLE IF NOT EXISTS).
|
|
19
|
+
|
|
20
|
+
CREATE TABLE IF NOT EXISTS public.fayz_projects (
|
|
21
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
22
|
+
tenant_id uuid NOT NULL,
|
|
23
|
+
-- The fayz platform project id (addresses /public/projects/{id}/…). Text
|
|
24
|
+
-- because the platform issues its own ids; nullable until provisioned.
|
|
25
|
+
fayz_project_id text,
|
|
26
|
+
-- App manifest id of the deployed app (e.g. 'artorious-shop'), when known.
|
|
27
|
+
app_id text,
|
|
28
|
+
name text NOT NULL,
|
|
29
|
+
-- site | storefront | landing_page | other
|
|
30
|
+
kind text NOT NULL DEFAULT 'site',
|
|
31
|
+
-- The tenant's default site (the one the "Seu site" widget shows). Partial
|
|
32
|
+
-- unique index below keeps at most one default per tenant.
|
|
33
|
+
is_default boolean NOT NULL DEFAULT false,
|
|
34
|
+
-- Whether the storefront module is active on this site. A storefront-enabled
|
|
35
|
+
-- site is an e-commerce sales channel (the Loja Online channel).
|
|
36
|
+
storefront_enabled boolean NOT NULL DEFAULT false,
|
|
37
|
+
-- Explicit public URLs. preview_url = the live/preview site; editor_url = the
|
|
38
|
+
-- fayz editor (/fayz/editor). Stored, not derived (no convention in code yet).
|
|
39
|
+
preview_url text,
|
|
40
|
+
editor_url text,
|
|
41
|
+
slug text,
|
|
42
|
+
metadata jsonb NOT NULL DEFAULT '{}',
|
|
43
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
44
|
+
updated_at timestamptz NOT NULL DEFAULT now()
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
CREATE INDEX IF NOT EXISTS fayz_projects_tenant_idx ON public.fayz_projects (tenant_id);
|
|
48
|
+
-- At most one default project per tenant.
|
|
49
|
+
CREATE UNIQUE INDEX IF NOT EXISTS fayz_projects_one_default_per_tenant
|
|
50
|
+
ON public.fayz_projects (tenant_id) WHERE is_default;
|
|
51
|
+
|
|
52
|
+
DROP TRIGGER IF EXISTS fayz_projects_updated_at ON public.fayz_projects;
|
|
53
|
+
CREATE TRIGGER fayz_projects_updated_at BEFORE UPDATE ON public.fayz_projects
|
|
54
|
+
FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();
|
|
55
|
+
|
|
56
|
+
ALTER TABLE public.fayz_projects ENABLE ROW LEVEL SECURITY;
|
|
57
|
+
|
|
58
|
+
DROP POLICY IF EXISTS "fayz_projects_member_all" ON public.fayz_projects;
|
|
59
|
+
CREATE POLICY "fayz_projects_member_all" ON public.fayz_projects FOR ALL TO authenticated
|
|
60
|
+
USING (tenant_id IN (SELECT public.user_tenant_ids()))
|
|
61
|
+
WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()));
|
|
62
|
+
|
|
63
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON public.fayz_projects TO authenticated, service_role;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
-- ============================================================================
|
|
2
|
+
-- 021_tenant_roles.sql — custom access profiles, per tenant.
|
|
3
|
+
--
|
|
4
|
+
-- The SDK has always been able to BUILD a custom role (duplicate a system role
|
|
5
|
+
-- in Settings → Permissions, or ask the assistant for one), but the table it
|
|
6
|
+
-- writes to never existed outside one legacy pool: `saas_core.tenant_roles`,
|
|
7
|
+
-- swept into `public` by 0000b and created nowhere else. Everywhere else the
|
|
8
|
+
-- insert threw and the screen swallowed it — a "Criar perfil" button that did
|
|
9
|
+
-- nothing.
|
|
10
|
+
--
|
|
11
|
+
-- Two changes, both required for a custom profile to survive a reload:
|
|
12
|
+
--
|
|
13
|
+
-- 1. public.tenant_roles — the role's IDENTITY (key + name). Its grants live
|
|
14
|
+
-- in tenant_role_overrides, keyed by that same `key`.
|
|
15
|
+
--
|
|
16
|
+
-- 2. tenant_role_overrides.permission_id loses its FK to public.permissions.
|
|
17
|
+
-- That catalog is a legacy of DB-driven RBAC; the feature catalog is now
|
|
18
|
+
-- DECLARED IN CODE by plugins (`declaredFeatures`) and merged at runtime,
|
|
19
|
+
-- so an app can grant `crm.leads.read` on a pool whose permissions table
|
|
20
|
+
-- never heard of plugin-crm. The FK made every such grant fail. The column
|
|
21
|
+
-- stays text in `feature.action` form — the shape agent_guard reads.
|
|
22
|
+
--
|
|
23
|
+
-- Idempotent: safe to re-run, no-ops when already applied.
|
|
24
|
+
-- ============================================================================
|
|
25
|
+
|
|
26
|
+
CREATE TABLE IF NOT EXISTS public.tenant_roles (
|
|
27
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
28
|
+
tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
|
|
29
|
+
-- Stable slug the grants and tenant_members.role point at. Renaming the
|
|
30
|
+
-- profile must never orphan its permissions, so the key is not the name.
|
|
31
|
+
key text NOT NULL,
|
|
32
|
+
name text NOT NULL,
|
|
33
|
+
description text,
|
|
34
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
35
|
+
UNIQUE(tenant_id, key)
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
ALTER TABLE public.tenant_roles ENABLE ROW LEVEL SECURITY;
|
|
39
|
+
|
|
40
|
+
-- Members see their own tenant's roles (the permission screen lists them);
|
|
41
|
+
-- only tenant admins create, rename or delete one.
|
|
42
|
+
DROP POLICY IF EXISTS "tenant_roles_select" ON public.tenant_roles;
|
|
43
|
+
CREATE POLICY "tenant_roles_select" ON public.tenant_roles FOR SELECT
|
|
44
|
+
USING (tenant_id IN (SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid()));
|
|
45
|
+
|
|
46
|
+
DROP POLICY IF EXISTS "tenant_roles_manage" ON public.tenant_roles;
|
|
47
|
+
CREATE POLICY "tenant_roles_manage" ON public.tenant_roles FOR ALL
|
|
48
|
+
USING (public.is_tenant_admin(tenant_id));
|
|
49
|
+
|
|
50
|
+
GRANT ALL ON public.tenant_roles TO authenticated, service_role;
|
|
51
|
+
|
|
52
|
+
-- The FK, dropped by lookup rather than by name: pools created before the
|
|
53
|
+
-- rename carry the constraint under whatever name Postgres minted.
|
|
54
|
+
DO $$
|
|
55
|
+
DECLARE
|
|
56
|
+
c record;
|
|
57
|
+
BEGIN
|
|
58
|
+
IF to_regclass('public.tenant_role_overrides') IS NULL THEN
|
|
59
|
+
RETURN;
|
|
60
|
+
END IF;
|
|
61
|
+
FOR c IN
|
|
62
|
+
SELECT con.conname
|
|
63
|
+
FROM pg_constraint con
|
|
64
|
+
JOIN pg_class rel ON rel.oid = con.conrelid
|
|
65
|
+
JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
|
|
66
|
+
JOIN pg_class frel ON frel.oid = con.confrelid
|
|
67
|
+
WHERE nsp.nspname = 'public'
|
|
68
|
+
AND rel.relname = 'tenant_role_overrides'
|
|
69
|
+
AND con.contype = 'f'
|
|
70
|
+
AND frel.relname = 'permissions'
|
|
71
|
+
LOOP
|
|
72
|
+
EXECUTE format('ALTER TABLE public.tenant_role_overrides DROP CONSTRAINT %I', c.conname);
|
|
73
|
+
END LOOP;
|
|
74
|
+
END $$;
|
package/package.json
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
"fayz": {
|
|
4
4
|
"status": "beta"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.9.0-next.0",
|
|
7
7
|
"description": "Fayz SDK database layer — Drizzle schema primitives, spine references, and migration helpers shared across plugins.",
|
|
8
8
|
"type": "module",
|
|
9
|
+
"sideEffects": false,
|
|
9
10
|
"main": "./dist/index.cjs",
|
|
10
11
|
"module": "./dist/index.js",
|
|
11
12
|
"types": "./dist/index.d.ts",
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
"database",
|
|
38
39
|
"schema"
|
|
39
40
|
],
|
|
41
|
+
"peerDependencies": {},
|
|
40
42
|
"scripts": {
|
|
41
43
|
"build": "tsup && tsc --emitDeclarationOnly --declaration --declarationMap --noEmit false",
|
|
42
44
|
"dev": "tsup --watch",
|