@baruk/core 0.1.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/README.md +6 -0
- package/dist/audit/audit.d.ts +22 -0
- package/dist/audit/audit.d.ts.map +1 -0
- package/dist/audit/audit.js +28 -0
- package/dist/audit/audit.js.map +1 -0
- package/dist/audit/repository.d.ts +22 -0
- package/dist/audit/repository.d.ts.map +1 -0
- package/dist/audit/repository.js +29 -0
- package/dist/audit/repository.js.map +1 -0
- package/dist/auth/password-reset.d.ts +20 -0
- package/dist/auth/password-reset.d.ts.map +1 -0
- package/dist/auth/password-reset.js +56 -0
- package/dist/auth/password-reset.js.map +1 -0
- package/dist/auth/password.d.ts +21 -0
- package/dist/auth/password.d.ts.map +1 -0
- package/dist/auth/password.js +67 -0
- package/dist/auth/password.js.map +1 -0
- package/dist/auth/service.d.ts +82 -0
- package/dist/auth/service.d.ts.map +1 -0
- package/dist/auth/service.js +214 -0
- package/dist/auth/service.js.map +1 -0
- package/dist/auth/session-token.d.ts +8 -0
- package/dist/auth/session-token.d.ts.map +1 -0
- package/dist/auth/session-token.js +19 -0
- package/dist/auth/session-token.js.map +1 -0
- package/dist/clients/repository.d.ts +53 -0
- package/dist/clients/repository.d.ts.map +1 -0
- package/dist/clients/repository.js +113 -0
- package/dist/clients/repository.js.map +1 -0
- package/dist/dashboard/repository.d.ts +19 -0
- package/dist/dashboard/repository.d.ts.map +1 -0
- package/dist/dashboard/repository.js +36 -0
- package/dist/dashboard/repository.js.map +1 -0
- package/dist/db/client.d.ts +19 -0
- package/dist/db/client.d.ts.map +1 -0
- package/dist/db/client.js +21 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/context.d.ts +27 -0
- package/dist/db/context.d.ts.map +1 -0
- package/dist/db/context.js +36 -0
- package/dist/db/context.js.map +1 -0
- package/dist/db/load-env.d.ts +8 -0
- package/dist/db/load-env.d.ts.map +1 -0
- package/dist/db/load-env.js +44 -0
- package/dist/db/load-env.js.map +1 -0
- package/dist/db/migrate.d.ts +2 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +139 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/seed.d.ts +2 -0
- package/dist/db/seed.d.ts.map +1 -0
- package/dist/db/seed.js +64 -0
- package/dist/db/seed.js.map +1 -0
- package/dist/import/clients-import.d.ts +39 -0
- package/dist/import/clients-import.d.ts.map +1 -0
- package/dist/import/clients-import.js +142 -0
- package/dist/import/clients-import.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/mail/resend.d.ts +13 -0
- package/dist/mail/resend.d.ts.map +1 -0
- package/dist/mail/resend.js +16 -0
- package/dist/mail/resend.js.map +1 -0
- package/dist/notifications/repository.d.ts +23 -0
- package/dist/notifications/repository.d.ts.map +1 -0
- package/dist/notifications/repository.js +43 -0
- package/dist/notifications/repository.js.map +1 -0
- package/dist/portal/repository.d.ts +11 -0
- package/dist/portal/repository.d.ts.map +1 -0
- package/dist/portal/repository.js +32 -0
- package/dist/portal/repository.js.map +1 -0
- package/dist/products/catalog.d.ts +14 -0
- package/dist/products/catalog.d.ts.map +1 -0
- package/dist/products/catalog.js +7 -0
- package/dist/products/catalog.js.map +1 -0
- package/dist/products/repository.d.ts +22 -0
- package/dist/products/repository.d.ts.map +1 -0
- package/dist/products/repository.js +56 -0
- package/dist/products/repository.js.map +1 -0
- package/dist/rbac/authorize.d.ts +18 -0
- package/dist/rbac/authorize.d.ts.map +1 -0
- package/dist/rbac/authorize.js +35 -0
- package/dist/rbac/authorize.js.map +1 -0
- package/dist/rbac/catalog.d.ts +21 -0
- package/dist/rbac/catalog.d.ts.map +1 -0
- package/dist/rbac/catalog.js +59 -0
- package/dist/rbac/catalog.js.map +1 -0
- package/dist/requests/repository.d.ts +66 -0
- package/dist/requests/repository.d.ts.map +1 -0
- package/dist/requests/repository.js +106 -0
- package/dist/requests/repository.js.map +1 -0
- package/dist/tenancy/provisioning.d.ts +25 -0
- package/dist/tenancy/provisioning.d.ts.map +1 -0
- package/dist/tenancy/provisioning.js +119 -0
- package/dist/tenancy/provisioning.js.map +1 -0
- package/dist/users/repository.d.ts +19 -0
- package/dist/users/repository.d.ts.map +1 -0
- package/dist/users/repository.js +78 -0
- package/dist/users/repository.js.map +1 -0
- package/package.json +41 -0
- package/src/db/migrations/0001_extensions.sql +5 -0
- package/src/db/migrations/0002_core_identity.sql +78 -0
- package/src/db/migrations/0003_rbac.sql +68 -0
- package/src/db/migrations/0004_directory.sql +35 -0
- package/src/db/migrations/0005_audit.sql +35 -0
- package/src/db/migrations/0006_rls_policies.sql +69 -0
- package/src/db/migrations/0007_requests_notifications_portal.sql +103 -0
- package/src/db/migrations/0008_client_deleted_by.sql +5 -0
- package/src/db/migrations/0009_client_scope_rls.sql +50 -0
- package/src/db/migrations/0010_product_entitlements.sql +43 -0
- package/src/db/migrations/0011_password_reset.sql +18 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { uuidv7 } from '@baruk/shared';
|
|
2
|
+
import { withContext } from '../db/context.js';
|
|
3
|
+
import { PRODUCTS } from './catalog.js';
|
|
4
|
+
/**
|
|
5
|
+
* Produtos acessíveis ao usuário: cruza suas memberships ativas com os
|
|
6
|
+
* entitlements (tenant_product) ativos. Rode dentro de `withContext({ userId })`
|
|
7
|
+
* — é assim que o Hub sabe a que produtos a pessoa tem direito. Sem entitlement
|
|
8
|
+
* = sem acesso (bloqueio no Hub).
|
|
9
|
+
*/
|
|
10
|
+
export async function listProductsForUser(tx, userId) {
|
|
11
|
+
const rows = await tx `
|
|
12
|
+
SELECT DISTINCT t.id AS tenant_id, t.display_name AS tenant_name, t.code AS tenant_code,
|
|
13
|
+
p.key AS product_key, p.name AS product_name, p.kind, p.base_url
|
|
14
|
+
FROM membership m
|
|
15
|
+
JOIN tenant t ON t.id = m.tenant_id
|
|
16
|
+
JOIN tenant_product tp ON tp.tenant_id = m.tenant_id AND tp.status = 'active'
|
|
17
|
+
JOIN product p ON p.id = tp.product_id AND p.is_active
|
|
18
|
+
WHERE m.user_id = ${userId} AND m.status = 'active' AND m.deleted_at IS NULL
|
|
19
|
+
ORDER BY t.display_name, p.name
|
|
20
|
+
`;
|
|
21
|
+
return rows.map((r) => ({
|
|
22
|
+
tenantId: r.tenant_id,
|
|
23
|
+
tenantName: r.tenant_name,
|
|
24
|
+
tenantCode: r.tenant_code,
|
|
25
|
+
productKey: r.product_key,
|
|
26
|
+
productName: r.product_name,
|
|
27
|
+
kind: r.kind,
|
|
28
|
+
baseUrl: r.base_url,
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
/** Materializa o catálogo global de produtos (idempotente). */
|
|
32
|
+
export async function ensureProductCatalog(db) {
|
|
33
|
+
for (const p of PRODUCTS) {
|
|
34
|
+
await db `
|
|
35
|
+
INSERT INTO product (id, key, name, kind, base_url, is_active)
|
|
36
|
+
VALUES (${uuidv7()}, ${p.key}, ${p.name}, ${p.kind}, ${p.baseUrl ?? null}, ${p.isActive ?? true})
|
|
37
|
+
ON CONFLICT (key) DO UPDATE
|
|
38
|
+
SET name = EXCLUDED.name, kind = EXCLUDED.kind,
|
|
39
|
+
base_url = EXCLUDED.base_url, is_active = EXCLUDED.is_active
|
|
40
|
+
`;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Concede (ou reativa) um produto a um tenant. */
|
|
44
|
+
export async function ensureTenantProduct(db, tenantId, productKey) {
|
|
45
|
+
await withContext(db, { tenantId }, async (tx) => {
|
|
46
|
+
const prod = await tx `SELECT id FROM product WHERE key = ${productKey}`;
|
|
47
|
+
if (!prod[0])
|
|
48
|
+
throw new Error(`Produto desconhecido: ${productKey}`);
|
|
49
|
+
await tx `
|
|
50
|
+
INSERT INTO tenant_product (id, tenant_id, product_id, status)
|
|
51
|
+
VALUES (${uuidv7()}, current_setting('app.current_tenant')::uuid, ${prod[0].id}, 'active')
|
|
52
|
+
ON CONFLICT (tenant_id, product_id) DO UPDATE SET status = 'active'
|
|
53
|
+
`;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/products/repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAYxC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,EAAM,EAAE,MAAc;IAC9D,MAAM,IAAI,GAAG,MAAM,EAAE,CAUpB;;;;;;;wBAOqB,MAAM;;GAE3B,CAAC;IACF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtB,QAAQ,EAAE,CAAC,CAAC,SAAS;QACrB,UAAU,EAAE,CAAC,CAAC,WAAW;QACzB,UAAU,EAAE,CAAC,CAAC,WAAW;QACzB,UAAU,EAAE,CAAC,CAAC,WAAW;QACzB,WAAW,EAAE,CAAC,CAAC,YAAY;QAC3B,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,CAAC,CAAC,QAAQ;KACpB,CAAC,CAAC,CAAC;AACN,CAAC;AAED,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,EAAM;IAC/C,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,EAAE,CAAA;;gBAEI,MAAM,EAAE,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,IAAI,IAAI,KAAK,CAAC,CAAC,QAAQ,IAAI,IAAI;;;;KAIhG,CAAC;IACJ,CAAC;AACH,CAAC;AAED,mDAAmD;AACnD,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,EAAM,EAAE,QAAgB,EAAE,UAAkB;IACpF,MAAM,WAAW,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QAC/C,MAAM,IAAI,GAAG,MAAM,EAAE,CAAkB,sCAAsC,UAAU,EAAE,CAAC;QAC1F,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,UAAU,EAAE,CAAC,CAAC;QACrE,MAAM,EAAE,CAAA;;gBAEI,MAAM,EAAE,kDAAkD,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;;KAE/E,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Tx } from '../db/client.js';
|
|
2
|
+
/**
|
|
3
|
+
* Avaliação de permissão (04-rbac §6) — CONVERGIDO sobre @baruk/identity
|
|
4
|
+
* (RFC-IDENTITY-003 §3.4). Decisão sempre no backend; a RLS no banco é a última
|
|
5
|
+
* linha de defesa. `canDo` delega ao avaliador canônico (aceita `Iterable`, logo
|
|
6
|
+
* `ReadonlySet`); `assertPermission` PRESERVA o `ForbiddenError` do domínio — o
|
|
7
|
+
* contrato de erro/HTTP fica intacto (o canônico lançaria um `Error` genérico).
|
|
8
|
+
*/
|
|
9
|
+
export declare function canDo(permissions: ReadonlySet<string>, required: string): boolean;
|
|
10
|
+
export declare function assertPermission(permissions: ReadonlySet<string>, required: string): void;
|
|
11
|
+
/**
|
|
12
|
+
* Carrega as permissões efetivas de um usuário DENTRO do tenant corrente.
|
|
13
|
+
* Permanece no core: é I/O de domínio (RLS/tenant), não primitiva canônica.
|
|
14
|
+
* Deve rodar dentro de `withContext({ tenantId, userId })` — a RLS de
|
|
15
|
+
* `user_role`/`role_permission` já restringe as linhas ao tenant ativo.
|
|
16
|
+
*/
|
|
17
|
+
export declare function loadUserPermissions(tx: Tx, userId: string): Promise<Set<string>>;
|
|
18
|
+
//# sourceMappingURL=authorize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../src/rbac/authorize.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAE1C;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEjF;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAIzF;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAUtF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ForbiddenError } from '@baruk/shared';
|
|
2
|
+
import { canDo as canonicalCanDo } from '@baruk/identity';
|
|
3
|
+
/**
|
|
4
|
+
* Avaliação de permissão (04-rbac §6) — CONVERGIDO sobre @baruk/identity
|
|
5
|
+
* (RFC-IDENTITY-003 §3.4). Decisão sempre no backend; a RLS no banco é a última
|
|
6
|
+
* linha de defesa. `canDo` delega ao avaliador canônico (aceita `Iterable`, logo
|
|
7
|
+
* `ReadonlySet`); `assertPermission` PRESERVA o `ForbiddenError` do domínio — o
|
|
8
|
+
* contrato de erro/HTTP fica intacto (o canônico lançaria um `Error` genérico).
|
|
9
|
+
*/
|
|
10
|
+
export function canDo(permissions, required) {
|
|
11
|
+
return canonicalCanDo(permissions, required);
|
|
12
|
+
}
|
|
13
|
+
export function assertPermission(permissions, required) {
|
|
14
|
+
if (!canDo(permissions, required)) {
|
|
15
|
+
throw new ForbiddenError(`Permissão necessária: ${required}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Carrega as permissões efetivas de um usuário DENTRO do tenant corrente.
|
|
20
|
+
* Permanece no core: é I/O de domínio (RLS/tenant), não primitiva canônica.
|
|
21
|
+
* Deve rodar dentro de `withContext({ tenantId, userId })` — a RLS de
|
|
22
|
+
* `user_role`/`role_permission` já restringe as linhas ao tenant ativo.
|
|
23
|
+
*/
|
|
24
|
+
export async function loadUserPermissions(tx, userId) {
|
|
25
|
+
const rows = await tx `
|
|
26
|
+
SELECT DISTINCT p.key
|
|
27
|
+
FROM user_role ur
|
|
28
|
+
JOIN role_permission rp ON rp.role_id = ur.role_id
|
|
29
|
+
JOIN permission p ON p.id = rp.permission_id
|
|
30
|
+
WHERE ur.user_id = ${userId}
|
|
31
|
+
AND ur.deleted_at IS NULL
|
|
32
|
+
`;
|
|
33
|
+
return new Set(rows.map((r) => r.key));
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=authorize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorize.js","sourceRoot":"","sources":["../../src/rbac/authorize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,KAAK,IAAI,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAG1D;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CAAC,WAAgC,EAAE,QAAgB;IACtE,OAAO,cAAc,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,WAAgC,EAAE,QAAgB;IACjF,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,cAAc,CAAC,yBAAyB,QAAQ,EAAE,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,EAAM,EAAE,MAAc;IAC9D,MAAM,IAAI,GAAG,MAAM,EAAE,CAAmB;;;;;yBAKjB,MAAM;;GAE5B,CAAC;IACF,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catálogo de permissões e papéis de sistema (04-rbac-permissions.md).
|
|
3
|
+
* É a fonte que o seed materializa no banco. A vertical registra permissões
|
|
4
|
+
* adicionais via seu próprio seed — sem alterar o Core.
|
|
5
|
+
*/
|
|
6
|
+
export interface PermissionDef {
|
|
7
|
+
key: string;
|
|
8
|
+
resource: string;
|
|
9
|
+
action: string;
|
|
10
|
+
description: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const PERMISSIONS: readonly PermissionDef[];
|
|
13
|
+
export declare const ALL_PERMISSION_KEYS: readonly string[];
|
|
14
|
+
export interface RoleDef {
|
|
15
|
+
key: string;
|
|
16
|
+
name: string;
|
|
17
|
+
permissions: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
/** Papéis de sistema (seed, imutáveis). São templates globais (tenant_id NULL). */
|
|
20
|
+
export declare const SYSTEM_ROLES: readonly RoleDef[];
|
|
21
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/rbac/catalog.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,WAAW,EAAE,SAAS,aAAa,EAmB/C,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAAkC,CAAC;AAEpF,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC;AAID,mFAAmF;AACnF,eAAO,MAAM,YAAY,EAAE,SAAS,OAAO,EA6B1C,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catálogo de permissões e papéis de sistema (04-rbac-permissions.md).
|
|
3
|
+
* É a fonte que o seed materializa no banco. A vertical registra permissões
|
|
4
|
+
* adicionais via seu próprio seed — sem alterar o Core.
|
|
5
|
+
*/
|
|
6
|
+
export const PERMISSIONS = [
|
|
7
|
+
{ key: 'client.read', resource: 'client', action: 'read', description: 'Ver clientes' },
|
|
8
|
+
{ key: 'client.write', resource: 'client', action: 'write', description: 'Criar/editar clientes' },
|
|
9
|
+
{ key: 'client.delete', resource: 'client', action: 'delete', description: 'Remover clientes' },
|
|
10
|
+
{ key: 'client.import', resource: 'client', action: 'manage', description: 'Importar clientes (CSV)' },
|
|
11
|
+
{ key: 'request.read', resource: 'request', action: 'read', description: 'Ver solicitações' },
|
|
12
|
+
{ key: 'request.create', resource: 'request', action: 'write', description: 'Criar solicitações' },
|
|
13
|
+
{ key: 'request.comment', resource: 'request', action: 'write', description: 'Comentar solicitações' },
|
|
14
|
+
{ key: 'request.status.update', resource: 'request', action: 'manage', description: 'Alterar status de solicitações' },
|
|
15
|
+
{ key: 'user.manage', resource: 'user', action: 'manage', description: 'Gerenciar usuários e memberships' },
|
|
16
|
+
{ key: 'document.read', resource: 'document', action: 'read', description: 'Ver documentos' },
|
|
17
|
+
{ key: 'document.write', resource: 'document', action: 'write', description: 'Enviar documentos' },
|
|
18
|
+
{ key: 'finance.charge.create', resource: 'finance', action: 'write', description: 'Emitir cobranças' },
|
|
19
|
+
{ key: 'vault.credential.decrypt', resource: 'vault', action: 'manage', description: 'Descriptografar credencial do cofre' },
|
|
20
|
+
{ key: 'communication.send', resource: 'communication', action: 'write', description: 'Enviar comunicações' },
|
|
21
|
+
{ key: 'audit.read', resource: 'audit', action: 'read', description: 'Ler trilha de auditoria' },
|
|
22
|
+
{ key: 'tenant.settings.update', resource: 'tenant', action: 'manage', description: 'Alterar configurações do tenant' },
|
|
23
|
+
{ key: 'rbac.role.update', resource: 'rbac', action: 'manage', description: 'Gerenciar papéis e permissões' },
|
|
24
|
+
{ key: 'user.invite', resource: 'user', action: 'manage', description: 'Convidar usuários' },
|
|
25
|
+
];
|
|
26
|
+
export const ALL_PERMISSION_KEYS = PERMISSIONS.map((p) => p.key);
|
|
27
|
+
const ALL = ALL_PERMISSION_KEYS;
|
|
28
|
+
/** Papéis de sistema (seed, imutáveis). São templates globais (tenant_id NULL). */
|
|
29
|
+
export const SYSTEM_ROLES = [
|
|
30
|
+
{ key: 'owner', name: 'Owner', permissions: ALL },
|
|
31
|
+
{ key: 'admin', name: 'Administrador', permissions: ALL.filter((p) => p !== 'tenant.settings.update') },
|
|
32
|
+
{
|
|
33
|
+
key: 'accountant',
|
|
34
|
+
name: 'Contador',
|
|
35
|
+
permissions: [
|
|
36
|
+
'client.read', 'client.write', 'client.import', 'document.read', 'document.write',
|
|
37
|
+
'communication.send', 'vault.credential.decrypt',
|
|
38
|
+
'request.read', 'request.create', 'request.comment', 'request.status.update',
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: 'assistant',
|
|
43
|
+
name: 'Assistente',
|
|
44
|
+
permissions: ['client.read', 'document.read', 'document.write', 'request.read', 'request.comment'],
|
|
45
|
+
},
|
|
46
|
+
{ key: 'finance', name: 'Financeiro', permissions: ['client.read', 'finance.charge.create'] },
|
|
47
|
+
{
|
|
48
|
+
key: 'communication',
|
|
49
|
+
name: 'Comunicação',
|
|
50
|
+
permissions: ['client.read', 'communication.send', 'request.read', 'request.comment'],
|
|
51
|
+
},
|
|
52
|
+
{ key: 'readonly', name: 'Somente leitura', permissions: ['client.read', 'document.read', 'request.read'] },
|
|
53
|
+
{
|
|
54
|
+
key: 'client_titular',
|
|
55
|
+
name: 'Cliente — Titular',
|
|
56
|
+
permissions: ['document.read', 'communication.send', 'request.read', 'request.comment'],
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/rbac/catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Tx } from '../db/client.js';
|
|
2
|
+
/**
|
|
3
|
+
* Solicitações (service_request) — o núcleo do ciclo operacional escritório↔cliente.
|
|
4
|
+
* Tenant-scoped por RLS. Endpoints de portal restringem adicionalmente por
|
|
5
|
+
* `clientId` (o cliente só vê as próprias solicitações) — passado como filtro.
|
|
6
|
+
*/
|
|
7
|
+
export type RequestStatus = 'draft' | 'sent' | 'viewed' | 'awaiting_client' | 'answered' | 'in_review' | 'done' | 'canceled' | 'overdue';
|
|
8
|
+
export type RequestPriority = 'low' | 'medium' | 'high' | 'urgent';
|
|
9
|
+
export interface ServiceRequestRecord {
|
|
10
|
+
id: string;
|
|
11
|
+
tenantId: string;
|
|
12
|
+
clientId: string;
|
|
13
|
+
title: string;
|
|
14
|
+
description: string | null;
|
|
15
|
+
category: string;
|
|
16
|
+
competenceLabel: string | null;
|
|
17
|
+
priority: RequestPriority;
|
|
18
|
+
status: RequestStatus;
|
|
19
|
+
dueDate: string | null;
|
|
20
|
+
responsibleUserId: string | null;
|
|
21
|
+
createdBy: string | null;
|
|
22
|
+
createdAt: string;
|
|
23
|
+
updatedAt: string;
|
|
24
|
+
}
|
|
25
|
+
export interface CreateRequestInput {
|
|
26
|
+
clientId: string;
|
|
27
|
+
title: string;
|
|
28
|
+
description?: string | null;
|
|
29
|
+
category?: string;
|
|
30
|
+
competenceLabel?: string | null;
|
|
31
|
+
priority?: RequestPriority;
|
|
32
|
+
dueDate?: string | null;
|
|
33
|
+
responsibleUserId?: string | null;
|
|
34
|
+
status?: RequestStatus;
|
|
35
|
+
createdBy?: string | null;
|
|
36
|
+
}
|
|
37
|
+
export declare function createRequest(tx: Tx, input: CreateRequestInput): Promise<ServiceRequestRecord>;
|
|
38
|
+
export interface ListRequestFilter {
|
|
39
|
+
clientId?: string;
|
|
40
|
+
status?: RequestStatus;
|
|
41
|
+
search?: string;
|
|
42
|
+
limit?: number;
|
|
43
|
+
offset?: number;
|
|
44
|
+
}
|
|
45
|
+
export declare function listRequests(tx: Tx, filter?: ListRequestFilter): Promise<{
|
|
46
|
+
items: ServiceRequestRecord[];
|
|
47
|
+
total: number;
|
|
48
|
+
}>;
|
|
49
|
+
export declare function getRequest(tx: Tx, id: string, clientId?: string): Promise<ServiceRequestRecord>;
|
|
50
|
+
export declare function updateRequestStatus(tx: Tx, id: string, status: RequestStatus, clientId?: string): Promise<number>;
|
|
51
|
+
export interface CommentRecord {
|
|
52
|
+
id: string;
|
|
53
|
+
requestId: string;
|
|
54
|
+
authorUserId: string | null;
|
|
55
|
+
authorKind: 'staff' | 'client' | 'system';
|
|
56
|
+
body: string;
|
|
57
|
+
createdAt: string;
|
|
58
|
+
}
|
|
59
|
+
export declare function addComment(tx: Tx, input: {
|
|
60
|
+
requestId: string;
|
|
61
|
+
body: string;
|
|
62
|
+
authorUserId?: string | null;
|
|
63
|
+
authorKind?: 'staff' | 'client' | 'system';
|
|
64
|
+
}): Promise<CommentRecord>;
|
|
65
|
+
export declare function listComments(tx: Tx, requestId: string): Promise<CommentRecord[]>;
|
|
66
|
+
//# sourceMappingURL=repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/requests/repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { NotFoundError, uuidv7 } from '@baruk/shared';
|
|
2
|
+
function mapRow(r) {
|
|
3
|
+
return {
|
|
4
|
+
id: r.id,
|
|
5
|
+
tenantId: r.tenant_id,
|
|
6
|
+
clientId: r.client_id,
|
|
7
|
+
title: r.title,
|
|
8
|
+
description: r.description,
|
|
9
|
+
category: r.category,
|
|
10
|
+
competenceLabel: r.competence_label,
|
|
11
|
+
priority: r.priority,
|
|
12
|
+
status: r.status,
|
|
13
|
+
dueDate: r.due_date ? r.due_date.toISOString().slice(0, 10) : null,
|
|
14
|
+
responsibleUserId: r.responsible_user_id,
|
|
15
|
+
createdBy: r.created_by,
|
|
16
|
+
createdAt: r.created_at.toISOString(),
|
|
17
|
+
updatedAt: r.updated_at.toISOString(),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export async function createRequest(tx, input) {
|
|
21
|
+
const rows = await tx `
|
|
22
|
+
INSERT INTO service_request (
|
|
23
|
+
id, tenant_id, client_id, title, description, category, competence_label,
|
|
24
|
+
priority, status, due_date, responsible_user_id, created_by
|
|
25
|
+
) VALUES (
|
|
26
|
+
${uuidv7()}, current_setting('app.current_tenant')::uuid, ${input.clientId},
|
|
27
|
+
${input.title}, ${input.description ?? null}, ${input.category ?? 'geral'},
|
|
28
|
+
${input.competenceLabel ?? null}, ${input.priority ?? 'medium'},
|
|
29
|
+
${input.status ?? 'sent'}, ${input.dueDate ?? null},
|
|
30
|
+
${input.responsibleUserId ?? null}, ${input.createdBy ?? null}
|
|
31
|
+
)
|
|
32
|
+
RETURNING *
|
|
33
|
+
`;
|
|
34
|
+
return mapRow(rows[0]);
|
|
35
|
+
}
|
|
36
|
+
export async function listRequests(tx, filter = {}) {
|
|
37
|
+
const limit = Math.min(filter.limit ?? 20, 100);
|
|
38
|
+
const offset = filter.offset ?? 0;
|
|
39
|
+
const like = filter.search ? `%${filter.search}%` : null;
|
|
40
|
+
const rows = await tx `
|
|
41
|
+
SELECT sr.*, count(*) OVER() AS total
|
|
42
|
+
FROM service_request sr
|
|
43
|
+
WHERE sr.deleted_at IS NULL
|
|
44
|
+
AND (${filter.clientId ?? null}::uuid IS NULL OR sr.client_id = ${filter.clientId ?? null})
|
|
45
|
+
AND (${filter.status ?? null}::text IS NULL OR sr.status = ${filter.status ?? null})
|
|
46
|
+
AND (${like}::text IS NULL OR sr.title ILIKE ${like} OR sr.description ILIKE ${like})
|
|
47
|
+
ORDER BY sr.created_at DESC
|
|
48
|
+
LIMIT ${limit} OFFSET ${offset}
|
|
49
|
+
`;
|
|
50
|
+
const total = rows[0] ? Number(rows[0].total) : 0;
|
|
51
|
+
return { items: rows.map(mapRow), total };
|
|
52
|
+
}
|
|
53
|
+
export async function getRequest(tx, id, clientId) {
|
|
54
|
+
const rows = await tx `
|
|
55
|
+
SELECT * FROM service_request
|
|
56
|
+
WHERE id = ${id} AND deleted_at IS NULL
|
|
57
|
+
AND (${clientId ?? null}::uuid IS NULL OR client_id = ${clientId ?? null})
|
|
58
|
+
`;
|
|
59
|
+
if (!rows[0])
|
|
60
|
+
throw new NotFoundError('Solicitação não encontrada');
|
|
61
|
+
return mapRow(rows[0]);
|
|
62
|
+
}
|
|
63
|
+
export async function updateRequestStatus(tx, id, status, clientId) {
|
|
64
|
+
const rows = await tx `
|
|
65
|
+
UPDATE service_request
|
|
66
|
+
SET status = ${status}, updated_at = now(), version = version + 1
|
|
67
|
+
WHERE id = ${id} AND deleted_at IS NULL
|
|
68
|
+
AND (${clientId ?? null}::uuid IS NULL OR client_id = ${clientId ?? null})
|
|
69
|
+
RETURNING id
|
|
70
|
+
`;
|
|
71
|
+
return rows.count;
|
|
72
|
+
}
|
|
73
|
+
export async function addComment(tx, input) {
|
|
74
|
+
const rows = await tx `
|
|
75
|
+
INSERT INTO request_comment (id, tenant_id, request_id, author_user_id, author_kind, body)
|
|
76
|
+
VALUES (
|
|
77
|
+
${uuidv7()}, current_setting('app.current_tenant')::uuid, ${input.requestId},
|
|
78
|
+
${input.authorUserId ?? null}, ${input.authorKind ?? 'staff'}, ${input.body}
|
|
79
|
+
)
|
|
80
|
+
RETURNING id, request_id, author_user_id, author_kind, body, created_at
|
|
81
|
+
`;
|
|
82
|
+
const r = rows[0];
|
|
83
|
+
return {
|
|
84
|
+
id: r.id,
|
|
85
|
+
requestId: r.request_id,
|
|
86
|
+
authorUserId: r.author_user_id,
|
|
87
|
+
authorKind: r.author_kind,
|
|
88
|
+
body: r.body,
|
|
89
|
+
createdAt: r.created_at.toISOString(),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
export async function listComments(tx, requestId) {
|
|
93
|
+
const rows = await tx `
|
|
94
|
+
SELECT id, request_id, author_user_id, author_kind, body, created_at
|
|
95
|
+
FROM request_comment WHERE request_id = ${requestId} ORDER BY created_at ASC
|
|
96
|
+
`;
|
|
97
|
+
return rows.map((r) => ({
|
|
98
|
+
id: r.id,
|
|
99
|
+
requestId: r.request_id,
|
|
100
|
+
authorUserId: r.author_user_id,
|
|
101
|
+
authorKind: r.author_kind,
|
|
102
|
+
body: r.body,
|
|
103
|
+
createdAt: r.created_at.toISOString(),
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/requests/repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type TenantStatus } from '@baruk/shared';
|
|
2
|
+
import type { Db } from '../db/client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Provisionamento de tenancy (01-multi-tenancy §5 — founding pattern). Todas as
|
|
5
|
+
* funções são IDEMPOTENTES: rodar o seed duas vezes não duplica nada. As
|
|
6
|
+
* inserções tenant-scoped derivam `tenant_id` da GUC, satisfazendo a RLS.
|
|
7
|
+
*/
|
|
8
|
+
/** Materializa o catálogo global de permissões e os papéis de sistema (templates). */
|
|
9
|
+
export declare function ensureRbacCatalog(db: Db): Promise<void>;
|
|
10
|
+
export interface EnsureTenantInput {
|
|
11
|
+
code: string;
|
|
12
|
+
displayName: string;
|
|
13
|
+
legalName?: string | null;
|
|
14
|
+
status?: TenantStatus;
|
|
15
|
+
primaryProduct?: string;
|
|
16
|
+
}
|
|
17
|
+
/** Cria (ou retorna) o tenant pelo `code`. */
|
|
18
|
+
export declare function ensureTenant(db: Db, input: EnsureTenantInput): Promise<string>;
|
|
19
|
+
/** Cria (ou retorna) a organização/unidade default de um tenant. */
|
|
20
|
+
export declare function ensureOrganization(db: Db, tenantId: string, name: string): Promise<string>;
|
|
21
|
+
/** Vincula um usuário a um tenant (membership ativa). */
|
|
22
|
+
export declare function ensureMembership(db: Db, tenantId: string, userId: string): Promise<string>;
|
|
23
|
+
/** Atribui um papel de sistema (por key) a um usuário dentro de um tenant. */
|
|
24
|
+
export declare function assignSystemRole(db: Db, tenantId: string, userId: string, roleKey: string): Promise<void>;
|
|
25
|
+
//# sourceMappingURL=provisioning.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provisioning.d.ts","sourceRoot":"","sources":["../../src/tenancy/provisioning.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAI1C;;;;GAIG;AAEH,sFAAsF;AACtF,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC7D;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,8CAA8C;AAC9C,wBAAsB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAcpF;AAED,oEAAoE;AACpE,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CAejB;AAED,yDAAyD;AACzD,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBhG;AAED,8EAA8E;AAC9E,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAkBf"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { uuidv7 } from '@baruk/shared';
|
|
2
|
+
import { withContext } from '../db/context.js';
|
|
3
|
+
import { PERMISSIONS, SYSTEM_ROLES } from '../rbac/catalog.js';
|
|
4
|
+
/**
|
|
5
|
+
* Provisionamento de tenancy (01-multi-tenancy §5 — founding pattern). Todas as
|
|
6
|
+
* funções são IDEMPOTENTES: rodar o seed duas vezes não duplica nada. As
|
|
7
|
+
* inserções tenant-scoped derivam `tenant_id` da GUC, satisfazendo a RLS.
|
|
8
|
+
*/
|
|
9
|
+
/** Materializa o catálogo global de permissões e os papéis de sistema (templates). */
|
|
10
|
+
export async function ensureRbacCatalog(db) {
|
|
11
|
+
for (const p of PERMISSIONS) {
|
|
12
|
+
await db `
|
|
13
|
+
INSERT INTO permission (id, key, resource, action, description)
|
|
14
|
+
VALUES (${uuidv7()}, ${p.key}, ${p.resource}, ${p.action}, ${p.description})
|
|
15
|
+
ON CONFLICT (key) DO NOTHING
|
|
16
|
+
`;
|
|
17
|
+
}
|
|
18
|
+
for (const role of SYSTEM_ROLES) {
|
|
19
|
+
const existing = await db `
|
|
20
|
+
SELECT id FROM role WHERE key = ${role.key} AND tenant_id IS NULL
|
|
21
|
+
`;
|
|
22
|
+
let roleId = existing[0]?.id;
|
|
23
|
+
if (!roleId) {
|
|
24
|
+
const inserted = await db `
|
|
25
|
+
INSERT INTO role (id, tenant_id, key, name, is_system)
|
|
26
|
+
VALUES (${uuidv7()}, NULL, ${role.key}, ${role.name}, true)
|
|
27
|
+
RETURNING id
|
|
28
|
+
`;
|
|
29
|
+
roleId = inserted[0].id;
|
|
30
|
+
}
|
|
31
|
+
for (const permKey of role.permissions) {
|
|
32
|
+
const perm = await db `SELECT id FROM permission WHERE key = ${permKey}`;
|
|
33
|
+
if (!perm[0])
|
|
34
|
+
continue;
|
|
35
|
+
await db `
|
|
36
|
+
INSERT INTO role_permission (role_id, permission_id, tenant_id)
|
|
37
|
+
VALUES (${roleId}, ${perm[0].id}, NULL)
|
|
38
|
+
ON CONFLICT (role_id, permission_id) DO NOTHING
|
|
39
|
+
`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Cria (ou retorna) o tenant pelo `code`. */
|
|
44
|
+
export async function ensureTenant(db, input) {
|
|
45
|
+
const existing = await db `
|
|
46
|
+
SELECT id FROM tenant WHERE lower(code) = lower(${input.code}) AND deleted_at IS NULL
|
|
47
|
+
`;
|
|
48
|
+
if (existing[0])
|
|
49
|
+
return existing[0].id;
|
|
50
|
+
const rows = await db `
|
|
51
|
+
INSERT INTO tenant (id, code, legal_name, display_name, status, primary_product)
|
|
52
|
+
VALUES (
|
|
53
|
+
${uuidv7()}, ${input.code}, ${input.legalName ?? null}, ${input.displayName},
|
|
54
|
+
${input.status ?? 'active'}, ${input.primaryProduct ?? 'contabil'}
|
|
55
|
+
)
|
|
56
|
+
RETURNING id
|
|
57
|
+
`;
|
|
58
|
+
return rows[0].id;
|
|
59
|
+
}
|
|
60
|
+
/** Cria (ou retorna) a organização/unidade default de um tenant. */
|
|
61
|
+
export async function ensureOrganization(db, tenantId, name) {
|
|
62
|
+
return withContext(db, { tenantId }, async (tx) => {
|
|
63
|
+
const existing = await tx `
|
|
64
|
+
SELECT id FROM organization
|
|
65
|
+
WHERE tenant_id = current_setting('app.current_tenant')::uuid
|
|
66
|
+
AND name = ${name} AND deleted_at IS NULL
|
|
67
|
+
`;
|
|
68
|
+
if (existing[0])
|
|
69
|
+
return existing[0].id;
|
|
70
|
+
const rows = await tx `
|
|
71
|
+
INSERT INTO organization (id, tenant_id, name, type)
|
|
72
|
+
VALUES (${uuidv7()}, current_setting('app.current_tenant')::uuid, ${name}, 'headquarters')
|
|
73
|
+
RETURNING id
|
|
74
|
+
`;
|
|
75
|
+
return rows[0].id;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/** Vincula um usuário a um tenant (membership ativa). */
|
|
79
|
+
export async function ensureMembership(db, tenantId, userId) {
|
|
80
|
+
return withContext(db, { tenantId, userId }, async (tx) => {
|
|
81
|
+
const existing = await tx `
|
|
82
|
+
SELECT id FROM membership
|
|
83
|
+
WHERE user_id = ${userId}
|
|
84
|
+
AND tenant_id = current_setting('app.current_tenant')::uuid
|
|
85
|
+
AND deleted_at IS NULL
|
|
86
|
+
`;
|
|
87
|
+
if (existing[0])
|
|
88
|
+
return existing[0].id;
|
|
89
|
+
const rows = await tx `
|
|
90
|
+
INSERT INTO membership (id, tenant_id, user_id, status)
|
|
91
|
+
VALUES (${uuidv7()}, current_setting('app.current_tenant')::uuid, ${userId}, 'active')
|
|
92
|
+
RETURNING id
|
|
93
|
+
`;
|
|
94
|
+
return rows[0].id;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/** Atribui um papel de sistema (por key) a um usuário dentro de um tenant. */
|
|
98
|
+
export async function assignSystemRole(db, tenantId, userId, roleKey) {
|
|
99
|
+
await withContext(db, { tenantId, userId }, async (tx) => {
|
|
100
|
+
const role = await tx `
|
|
101
|
+
SELECT id FROM role WHERE key = ${roleKey} AND tenant_id IS NULL
|
|
102
|
+
`;
|
|
103
|
+
if (!role[0])
|
|
104
|
+
throw new Error(`Papel de sistema desconhecido: ${roleKey}`);
|
|
105
|
+
const existing = await tx `
|
|
106
|
+
SELECT id FROM user_role
|
|
107
|
+
WHERE user_id = ${userId} AND role_id = ${role[0].id}
|
|
108
|
+
AND tenant_id = current_setting('app.current_tenant')::uuid
|
|
109
|
+
AND deleted_at IS NULL AND organization_id IS NULL AND client_id IS NULL
|
|
110
|
+
`;
|
|
111
|
+
if (existing[0])
|
|
112
|
+
return;
|
|
113
|
+
await tx `
|
|
114
|
+
INSERT INTO user_role (id, tenant_id, user_id, role_id)
|
|
115
|
+
VALUES (${uuidv7()}, current_setting('app.current_tenant')::uuid, ${userId}, ${role[0].id})
|
|
116
|
+
`;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=provisioning.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provisioning.js","sourceRoot":"","sources":["../../src/tenancy/provisioning.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Tx } from '../db/client.js';
|
|
2
|
+
/**
|
|
3
|
+
* Gestão de usuários e memberships DENTRO do tenant corrente (RLS garante o
|
|
4
|
+
* escopo). Inclui a proteção contra remoção/rebaixamento do último administrador.
|
|
5
|
+
*/
|
|
6
|
+
export interface TenantMember {
|
|
7
|
+
userId: string;
|
|
8
|
+
email: string;
|
|
9
|
+
fullName: string;
|
|
10
|
+
userType: string;
|
|
11
|
+
membershipStatus: string;
|
|
12
|
+
roles: string[];
|
|
13
|
+
}
|
|
14
|
+
export declare function listTenantMembers(tx: Tx): Promise<TenantMember[]>;
|
|
15
|
+
/** Substitui o(s) papel(is) do usuário no tenant por um único papel (por key). */
|
|
16
|
+
export declare function setUserRole(tx: Tx, userId: string, roleKey: string): Promise<void>;
|
|
17
|
+
/** Ativa/desativa (ou revoga) a membership. Bloqueia desativar o último admin. */
|
|
18
|
+
export declare function setMembershipStatus(tx: Tx, userId: string, status: 'active' | 'invited' | 'revoked'): Promise<number>;
|
|
19
|
+
//# sourceMappingURL=repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/users/repository.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAE1C;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAID,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAuBvE;AAeD,kFAAkF;AAClF,wBAAsB,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBxF;AAWD,kFAAkF;AAClF,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,GACvC,OAAO,CAAC,MAAM,CAAC,CAWjB"}
|