@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
package/dist/db/seed.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seed do tenant fundador — SC Organização Contábil (tenant 0001).
|
|
3
|
+
*
|
|
4
|
+
* Princípio inegociável (01-multi-tenancy §6): a SC nasce como um tenant COMUM,
|
|
5
|
+
* SEM hardcode estrutural. Este script apenas materializa dados; nenhum `if
|
|
6
|
+
* (tenant === 'SC')` existe no código de produção.
|
|
7
|
+
*
|
|
8
|
+
* Dados legais não confirmados (CNPJ, CRC, sócios) permanecem NULOS — nunca
|
|
9
|
+
* inventados. Apenas um usuário administrador de DESENVOLVIMENTO é criado.
|
|
10
|
+
*
|
|
11
|
+
* Idempotente. Uso: `pnpm db:seed`.
|
|
12
|
+
*/
|
|
13
|
+
import { assignSystemRole, createDb, ensureMembership, ensureOrganization, ensureProductCatalog, ensureRbacCatalog, ensureTenant, ensureTenantProduct, loadEnv, upsertUserWithPassword, } from '../index.js';
|
|
14
|
+
async function main() {
|
|
15
|
+
loadEnv();
|
|
16
|
+
const ownerUrl = process.env.DATABASE_URL;
|
|
17
|
+
if (!ownerUrl)
|
|
18
|
+
throw new Error('DATABASE_URL (papel owner) não definida.');
|
|
19
|
+
const adminPassword = process.env.SEED_ADMIN_PASSWORD;
|
|
20
|
+
if (!adminPassword)
|
|
21
|
+
throw new Error('SEED_ADMIN_PASSWORD não definida.');
|
|
22
|
+
const db = createDb(ownerUrl, { role: 'owner', max: 1 });
|
|
23
|
+
try {
|
|
24
|
+
// 1) Catálogos globais: RBAC + produtos do ecossistema.
|
|
25
|
+
await ensureRbacCatalog(db);
|
|
26
|
+
await ensureProductCatalog(db);
|
|
27
|
+
console.log('✓ Catálogos garantidos (RBAC + produtos do ecossistema).');
|
|
28
|
+
// 2) Tenant fundador SC — dados legais não confirmados ficam NULOS.
|
|
29
|
+
const tenantId = await ensureTenant(db, {
|
|
30
|
+
code: 'sc',
|
|
31
|
+
displayName: 'SC Organização Contábil',
|
|
32
|
+
legalName: null, // Razão social/CNPJ não confirmados — jamais inventar.
|
|
33
|
+
status: 'active',
|
|
34
|
+
primaryProduct: 'contabil',
|
|
35
|
+
});
|
|
36
|
+
console.log(`✓ Tenant SC garantido: ${tenantId}`);
|
|
37
|
+
// 3) Organização/unidade default + entitlement do produto Contábil.
|
|
38
|
+
await ensureOrganization(db, tenantId, 'Matriz');
|
|
39
|
+
await ensureTenantProduct(db, tenantId, 'contabil');
|
|
40
|
+
console.log('✓ Entitlement do produto Baruk Contábil concedido à SC.');
|
|
41
|
+
// 4) Usuário administrador de DESENVOLVIMENTO (não é dado real de sócio).
|
|
42
|
+
const adminEmail = 'admin@sc.baruk.dev';
|
|
43
|
+
const admin = await upsertUserWithPassword(db, {
|
|
44
|
+
email: adminEmail,
|
|
45
|
+
fullName: 'Administrador SC (dev)',
|
|
46
|
+
password: adminPassword,
|
|
47
|
+
userType: 'staff',
|
|
48
|
+
});
|
|
49
|
+
console.log(`✓ Usuário admin (dev) garantido: ${admin.email}`);
|
|
50
|
+
// 5) Vínculo + papel Owner.
|
|
51
|
+
await ensureMembership(db, tenantId, admin.id);
|
|
52
|
+
await assignSystemRole(db, tenantId, admin.id, 'owner');
|
|
53
|
+
console.log('✓ Membership + papel Owner atribuídos ao admin no tenant SC.');
|
|
54
|
+
console.log('\n✓ Seed concluído. Login dev: admin@sc.baruk.dev / (SEED_ADMIN_PASSWORD)');
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
await db.end({ timeout: 5 });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
main().catch((err) => {
|
|
61
|
+
console.error('✗ Falha no seed:', err instanceof Error ? err.message : err);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
});
|
|
64
|
+
//# sourceMappingURL=seed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed.js","sourceRoot":"","sources":["../../src/db/seed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,OAAO,EACP,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,KAAK,UAAU,IAAI;IACjB,OAAO,EAAE,CAAC;IACV,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAC1C,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC3E,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IACtD,IAAI,CAAC,aAAa;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAEzE,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IACzD,IAAI,CAAC;QACH,wDAAwD;QACxD,MAAM,iBAAiB,CAAC,EAAE,CAAC,CAAC;QAC5B,MAAM,oBAAoB,CAAC,EAAE,CAAC,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC;QAExE,oEAAoE;QACpE,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,EAAE,EAAE;YACtC,IAAI,EAAE,IAAI;YACV,WAAW,EAAE,yBAAyB;YACtC,SAAS,EAAE,IAAI,EAAE,uDAAuD;YACxE,MAAM,EAAE,QAAQ;YAChB,cAAc,EAAE,UAAU;SAC3B,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC;QAElD,oEAAoE;QACpE,MAAM,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACjD,MAAM,mBAAmB,CAAC,EAAE,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;QAEvE,0EAA0E;QAC1E,MAAM,UAAU,GAAG,oBAAoB,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,sBAAsB,CAAC,EAAE,EAAE;YAC7C,KAAK,EAAE,UAAU;YACjB,QAAQ,EAAE,wBAAwB;YAClC,QAAQ,EAAE,aAAa;YACvB,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,oCAAoC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;QAE/D,4BAA4B;QAC5B,MAAM,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;QAC/C,MAAM,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;QAE5E,OAAO,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAC;IAC3F,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC5E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Tx } from '../db/client.js';
|
|
2
|
+
/**
|
|
3
|
+
* Importação de clientes por CSV. Fluxo em duas etapas: `planImport` (dry-run,
|
|
4
|
+
* NÃO persiste) e `commitImport` (persiste apenas os novos, idempotente por
|
|
5
|
+
* documento). Parser mínimo RFC4180 (aspas, vírgulas, CRLF) sem dependência.
|
|
6
|
+
*/
|
|
7
|
+
export interface ParsedClientRow {
|
|
8
|
+
line: number;
|
|
9
|
+
displayName: string;
|
|
10
|
+
documentNumber: string | null;
|
|
11
|
+
clientType: 'pf' | 'pj';
|
|
12
|
+
email: string | null;
|
|
13
|
+
phone: string | null;
|
|
14
|
+
}
|
|
15
|
+
export interface ImportIssue {
|
|
16
|
+
line: number;
|
|
17
|
+
message: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ImportPlan {
|
|
20
|
+
total: number;
|
|
21
|
+
toCreate: ParsedClientRow[];
|
|
22
|
+
duplicates: {
|
|
23
|
+
line: number;
|
|
24
|
+
documentNumber: string;
|
|
25
|
+
}[];
|
|
26
|
+
errors: ImportIssue[];
|
|
27
|
+
}
|
|
28
|
+
export declare function parseClientsCsv(text: string): {
|
|
29
|
+
rows: ParsedClientRow[];
|
|
30
|
+
errors: ImportIssue[];
|
|
31
|
+
};
|
|
32
|
+
export declare function planImport(tx: Tx, text: string): Promise<ImportPlan>;
|
|
33
|
+
export interface ImportResult {
|
|
34
|
+
created: number;
|
|
35
|
+
skipped: number;
|
|
36
|
+
errors: ImportIssue[];
|
|
37
|
+
}
|
|
38
|
+
export declare function commitImport(tx: Tx, text: string, createdBy?: string | null): Promise<ImportResult>;
|
|
39
|
+
//# sourceMappingURL=clients-import.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clients-import.d.ts","sourceRoot":"","sources":["../../src/import/clients-import.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAG1C;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACvD,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAoDD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,eAAe,EAAE,CAAC;IAAC,MAAM,EAAE,WAAW,EAAE,CAAA;CAAE,CA0ChG;AAED,wBAAsB,UAAU,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAsB1E;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,wBAAsB,YAAY,CAChC,EAAE,EAAE,EAAE,EACN,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB,OAAO,CAAC,YAAY,CAAC,CAavB"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { createClient, findClientIdByDocument } from '../clients/repository.js';
|
|
2
|
+
const HEADER_ALIASES = {
|
|
3
|
+
nome: 'displayName',
|
|
4
|
+
display_name: 'displayName',
|
|
5
|
+
razao_social: 'displayName',
|
|
6
|
+
documento: 'documentNumber',
|
|
7
|
+
document_number: 'documentNumber',
|
|
8
|
+
cnpj: 'documentNumber',
|
|
9
|
+
cpf: 'documentNumber',
|
|
10
|
+
tipo: 'clientType',
|
|
11
|
+
client_type: 'clientType',
|
|
12
|
+
email: 'email',
|
|
13
|
+
telefone: 'phone',
|
|
14
|
+
phone: 'phone',
|
|
15
|
+
};
|
|
16
|
+
function parseCsvRaw(text) {
|
|
17
|
+
const rows = [];
|
|
18
|
+
let field = '';
|
|
19
|
+
let row = [];
|
|
20
|
+
let inQuotes = false;
|
|
21
|
+
const s = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
22
|
+
for (let i = 0; i < s.length; i++) {
|
|
23
|
+
const c = s[i];
|
|
24
|
+
if (inQuotes) {
|
|
25
|
+
if (c === '"') {
|
|
26
|
+
if (s[i + 1] === '"') {
|
|
27
|
+
field += '"';
|
|
28
|
+
i++;
|
|
29
|
+
}
|
|
30
|
+
else
|
|
31
|
+
inQuotes = false;
|
|
32
|
+
}
|
|
33
|
+
else
|
|
34
|
+
field += c;
|
|
35
|
+
}
|
|
36
|
+
else if (c === '"')
|
|
37
|
+
inQuotes = true;
|
|
38
|
+
else if (c === ',') {
|
|
39
|
+
row.push(field);
|
|
40
|
+
field = '';
|
|
41
|
+
}
|
|
42
|
+
else if (c === '\n') {
|
|
43
|
+
row.push(field);
|
|
44
|
+
rows.push(row);
|
|
45
|
+
row = [];
|
|
46
|
+
field = '';
|
|
47
|
+
}
|
|
48
|
+
else
|
|
49
|
+
field += c;
|
|
50
|
+
}
|
|
51
|
+
if (field.length > 0 || row.length > 0) {
|
|
52
|
+
row.push(field);
|
|
53
|
+
rows.push(row);
|
|
54
|
+
}
|
|
55
|
+
return rows.filter((r) => r.some((cell) => cell.trim() !== ''));
|
|
56
|
+
}
|
|
57
|
+
const onlyDigits = (v) => v.replace(/\D/g, '');
|
|
58
|
+
export function parseClientsCsv(text) {
|
|
59
|
+
const raw = parseCsvRaw(text);
|
|
60
|
+
const errors = [];
|
|
61
|
+
if (raw.length === 0)
|
|
62
|
+
return { rows: [], errors: [{ line: 0, message: 'CSV vazio' }] };
|
|
63
|
+
const header = raw[0].map((h) => h.trim().toLowerCase());
|
|
64
|
+
const colMap = header.map((h) => HEADER_ALIASES[h]);
|
|
65
|
+
if (!colMap.includes('displayName')) {
|
|
66
|
+
return { rows: [], errors: [{ line: 1, message: 'Cabeçalho sem coluna de nome (nome/display_name)' }] };
|
|
67
|
+
}
|
|
68
|
+
const rows = [];
|
|
69
|
+
for (let i = 1; i < raw.length; i++) {
|
|
70
|
+
const cells = raw[i];
|
|
71
|
+
const rec = { line: i + 1, clientType: 'pj' };
|
|
72
|
+
colMap.forEach((key, idx) => {
|
|
73
|
+
if (!key)
|
|
74
|
+
return;
|
|
75
|
+
const value = (cells[idx] ?? '').trim();
|
|
76
|
+
if (key === 'documentNumber')
|
|
77
|
+
rec.documentNumber = value ? onlyDigits(value) : null;
|
|
78
|
+
else if (key === 'clientType')
|
|
79
|
+
rec.clientType = value.toLowerCase() === 'pf' ? 'pf' : 'pj';
|
|
80
|
+
else if (key === 'email')
|
|
81
|
+
rec.email = value || null;
|
|
82
|
+
else if (key === 'phone')
|
|
83
|
+
rec.phone = value || null;
|
|
84
|
+
else if (key === 'displayName')
|
|
85
|
+
rec.displayName = value;
|
|
86
|
+
});
|
|
87
|
+
if (!rec.displayName) {
|
|
88
|
+
errors.push({ line: i + 1, message: 'Nome obrigatório ausente' });
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (rec.documentNumber && ![11, 14].includes(rec.documentNumber.length)) {
|
|
92
|
+
errors.push({ line: i + 1, message: `Documento inválido (${rec.documentNumber.length} dígitos)` });
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
rows.push({
|
|
96
|
+
line: i + 1,
|
|
97
|
+
displayName: rec.displayName,
|
|
98
|
+
documentNumber: rec.documentNumber ?? null,
|
|
99
|
+
clientType: rec.clientType ?? 'pj',
|
|
100
|
+
email: rec.email ?? null,
|
|
101
|
+
phone: rec.phone ?? null,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return { rows, errors };
|
|
105
|
+
}
|
|
106
|
+
export async function planImport(tx, text) {
|
|
107
|
+
const { rows, errors } = parseClientsCsv(text);
|
|
108
|
+
const toCreate = [];
|
|
109
|
+
const duplicates = [];
|
|
110
|
+
const seen = new Set();
|
|
111
|
+
for (const row of rows) {
|
|
112
|
+
if (row.documentNumber) {
|
|
113
|
+
if (seen.has(row.documentNumber)) {
|
|
114
|
+
duplicates.push({ line: row.line, documentNumber: row.documentNumber });
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
seen.add(row.documentNumber);
|
|
118
|
+
const existing = await findClientIdByDocument(tx, row.documentNumber);
|
|
119
|
+
if (existing) {
|
|
120
|
+
duplicates.push({ line: row.line, documentNumber: row.documentNumber });
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
toCreate.push(row);
|
|
125
|
+
}
|
|
126
|
+
return { total: rows.length, toCreate, duplicates, errors };
|
|
127
|
+
}
|
|
128
|
+
export async function commitImport(tx, text, createdBy) {
|
|
129
|
+
const plan = await planImport(tx, text);
|
|
130
|
+
let created = 0;
|
|
131
|
+
for (const row of plan.toCreate) {
|
|
132
|
+
await createClient(tx, {
|
|
133
|
+
displayName: row.displayName,
|
|
134
|
+
clientType: row.clientType,
|
|
135
|
+
documentNumber: row.documentNumber,
|
|
136
|
+
createdBy: createdBy ?? null,
|
|
137
|
+
});
|
|
138
|
+
created++;
|
|
139
|
+
}
|
|
140
|
+
return { created, skipped: plan.duplicates.length, errors: plan.errors };
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=clients-import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clients-import.js","sourceRoot":"","sources":["../../src/import/clients-import.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export { createDb } from './db/client.js';
|
|
2
|
+
export type { Db, Tx, Queryable, DbOptions } from './db/client.js';
|
|
3
|
+
export { withContext, withTenant } from './db/context.js';
|
|
4
|
+
export type { DbContext } from './db/context.js';
|
|
5
|
+
export { loadEnv } from './db/load-env.js';
|
|
6
|
+
export { ensureRbacCatalog, ensureTenant, ensureOrganization, ensureMembership, assignSystemRole, } from './tenancy/provisioning.js';
|
|
7
|
+
export type { EnsureTenantInput } from './tenancy/provisioning.js';
|
|
8
|
+
export { PERMISSIONS, SYSTEM_ROLES, ALL_PERMISSION_KEYS } from './rbac/catalog.js';
|
|
9
|
+
export type { PermissionDef, RoleDef } from './rbac/catalog.js';
|
|
10
|
+
export { canDo, assertPermission, loadUserPermissions } from './rbac/authorize.js';
|
|
11
|
+
export { login, logout, authenticate, selectTenant, listMemberships, sessionMemberships, sessionProducts, upsertUserWithPassword, } from './auth/service.js';
|
|
12
|
+
export { listProductsForUser, ensureProductCatalog, ensureTenantProduct, } from './products/repository.js';
|
|
13
|
+
export type { ProductAccess } from './products/repository.js';
|
|
14
|
+
export { PRODUCTS } from './products/catalog.js';
|
|
15
|
+
export type { ProductDef } from './products/catalog.js';
|
|
16
|
+
export type { AuthContext, AuthUser, MembershipView, LoginResult } from './auth/service.js';
|
|
17
|
+
export { toPrincipal, toMembership } from './auth/service.js';
|
|
18
|
+
export { hashPassword, verifyPassword, hashPasswordAsync, verifyPasswordAsync } from './auth/password.js';
|
|
19
|
+
export { generateSessionToken, hashToken } from './auth/session-token.js';
|
|
20
|
+
export { requestPasswordReset, resetPassword } from './auth/password-reset.js';
|
|
21
|
+
export { sendEmail } from './mail/resend.js';
|
|
22
|
+
export type { EmailMessage } from './mail/resend.js';
|
|
23
|
+
export { appendAudit } from './audit/audit.js';
|
|
24
|
+
export type { AuditEntry } from './audit/audit.js';
|
|
25
|
+
export { listAudit } from './audit/repository.js';
|
|
26
|
+
export type { AuditRow } from './audit/repository.js';
|
|
27
|
+
export { createClient, listClients, listClientsPaged, getClient, renameClient, updateClient, softDeleteClient, findClientIdByDocument, } from './clients/repository.js';
|
|
28
|
+
export type { ClientRecord, CreateClientInput, UpdateClientInput, ListClientsFilter, } from './clients/repository.js';
|
|
29
|
+
export { createRequest, listRequests, getRequest, updateRequestStatus, addComment, listComments, } from './requests/repository.js';
|
|
30
|
+
export type { ServiceRequestRecord, CreateRequestInput, ListRequestFilter, RequestStatus, RequestPriority, CommentRecord, } from './requests/repository.js';
|
|
31
|
+
export { createNotification, listNotifications, unreadCount, markNotificationRead, } from './notifications/repository.js';
|
|
32
|
+
export type { NotificationRecord } from './notifications/repository.js';
|
|
33
|
+
export { getPortalClientId, ensurePortalAccess, listPortalUserIds } from './portal/repository.js';
|
|
34
|
+
export { listTenantMembers, setUserRole, setMembershipStatus } from './users/repository.js';
|
|
35
|
+
export type { TenantMember } from './users/repository.js';
|
|
36
|
+
export { getCoreStats } from './dashboard/repository.js';
|
|
37
|
+
export type { CoreDashboardStats } from './dashboard/repository.js';
|
|
38
|
+
export { parseClientsCsv, planImport, commitImport } from './import/clients-import.js';
|
|
39
|
+
export type { ImportPlan, ImportResult, ParsedClientRow, ImportIssue } from './import/clients-import.js';
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// @baruk/core — o motor agnóstico da plataforma. NÃO conhece contabilidade.
|
|
2
|
+
// Banco / contexto de tenant (RLS)
|
|
3
|
+
export { createDb } from './db/client.js';
|
|
4
|
+
export { withContext, withTenant } from './db/context.js';
|
|
5
|
+
export { loadEnv } from './db/load-env.js';
|
|
6
|
+
// Tenancy / provisionamento
|
|
7
|
+
export { ensureRbacCatalog, ensureTenant, ensureOrganization, ensureMembership, assignSystemRole, } from './tenancy/provisioning.js';
|
|
8
|
+
// RBAC
|
|
9
|
+
export { PERMISSIONS, SYSTEM_ROLES, ALL_PERMISSION_KEYS } from './rbac/catalog.js';
|
|
10
|
+
export { canDo, assertPermission, loadUserPermissions } from './rbac/authorize.js';
|
|
11
|
+
// Auth
|
|
12
|
+
export { login, logout, authenticate, selectTenant, listMemberships, sessionMemberships, sessionProducts, upsertUserWithPassword, } from './auth/service.js';
|
|
13
|
+
// Produtos / entitlements (IAM multiproduto)
|
|
14
|
+
export { listProductsForUser, ensureProductCatalog, ensureTenantProduct, } from './products/repository.js';
|
|
15
|
+
export { PRODUCTS } from './products/catalog.js';
|
|
16
|
+
// Convergência de contratos (RFC-IDENTITY-003 §3.5) — adaptadores para os canônicos @baruk/identity.
|
|
17
|
+
export { toPrincipal, toMembership } from './auth/service.js';
|
|
18
|
+
// Contrato público SÍNCRONO (compat pré-R1) + variantes async canônicas (RFC-IDENTITY-003 §3.2, aditivo).
|
|
19
|
+
export { hashPassword, verifyPassword, hashPasswordAsync, verifyPasswordAsync } from './auth/password.js';
|
|
20
|
+
export { generateSessionToken, hashToken } from './auth/session-token.js';
|
|
21
|
+
export { requestPasswordReset, resetPassword } from './auth/password-reset.js';
|
|
22
|
+
export { sendEmail } from './mail/resend.js';
|
|
23
|
+
// Auditoria
|
|
24
|
+
export { appendAudit } from './audit/audit.js';
|
|
25
|
+
export { listAudit } from './audit/repository.js';
|
|
26
|
+
// Clientes (entidade de negócio tenant-scoped)
|
|
27
|
+
export { createClient, listClients, listClientsPaged, getClient, renameClient, updateClient, softDeleteClient, findClientIdByDocument, } from './clients/repository.js';
|
|
28
|
+
// Solicitações (ciclo operacional escritório↔cliente)
|
|
29
|
+
export { createRequest, listRequests, getRequest, updateRequestStatus, addComment, listComments, } from './requests/repository.js';
|
|
30
|
+
// Notificações
|
|
31
|
+
export { createNotification, listNotifications, unreadCount, markNotificationRead, } from './notifications/repository.js';
|
|
32
|
+
// Portal do cliente
|
|
33
|
+
export { getPortalClientId, ensurePortalAccess, listPortalUserIds } from './portal/repository.js';
|
|
34
|
+
// Usuários / memberships
|
|
35
|
+
export { listTenantMembers, setUserRole, setMembershipStatus } from './users/repository.js';
|
|
36
|
+
// Dashboard (stats agnósticas)
|
|
37
|
+
export { getCoreStats } from './dashboard/repository.js';
|
|
38
|
+
// Importação de clientes (CSV)
|
|
39
|
+
export { parseClientsCsv, planImport, commitImport } from './import/clients-import.js';
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAE5E,mCAAmC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,4BAA4B;AAC5B,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,2BAA2B,CAAC;AAGnC,OAAO;AACP,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAEnF,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAEnF,OAAO;AACP,OAAO,EACL,KAAK,EACL,MAAM,EACN,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAE3B,6CAA6C;AAC7C,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD,qGAAqG;AACrG,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC9D,0GAA0G;AAC1G,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC1G,OAAO,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG7C,YAAY;AACZ,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD,+CAA+C;AAC/C,OAAO,EACL,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAQjC,sDAAsD;AACtD,OAAO,EACL,aAAa,EACb,YAAY,EACZ,UAAU,EACV,mBAAmB,EACnB,UAAU,EACV,YAAY,GACb,MAAM,0BAA0B,CAAC;AAUlC,eAAe;AACf,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,EACX,oBAAoB,GACrB,MAAM,+BAA+B,CAAC;AAGvC,oBAAoB;AACpB,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAElG,yBAAyB;AACzB,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAG5F,+BAA+B;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,+BAA+B;AAC/B,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Envio de e-mail transacional via Resend (provider-agnostic na borda: a API
|
|
3
|
+
* decide se/como enviar). Best-effort: retorna false sem lançar se indisponível
|
|
4
|
+
* ou domínio não verificado — o fluxo de reset não deve quebrar por causa do e-mail.
|
|
5
|
+
*/
|
|
6
|
+
export interface EmailMessage {
|
|
7
|
+
from: string;
|
|
8
|
+
to: string;
|
|
9
|
+
subject: string;
|
|
10
|
+
html: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function sendEmail(apiKey: string | undefined, msg: EmailMessage): Promise<boolean>;
|
|
13
|
+
//# sourceMappingURL=resend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend.d.ts","sourceRoot":"","sources":["../../src/mail/resend.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAY/F"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export async function sendEmail(apiKey, msg) {
|
|
2
|
+
if (!apiKey)
|
|
3
|
+
return false;
|
|
4
|
+
try {
|
|
5
|
+
const res = await fetch('https://api.resend.com/emails', {
|
|
6
|
+
method: 'POST',
|
|
7
|
+
headers: { authorization: `Bearer ${apiKey}`, 'content-type': 'application/json' },
|
|
8
|
+
body: JSON.stringify(msg),
|
|
9
|
+
});
|
|
10
|
+
return res.ok;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=resend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend.js","sourceRoot":"","sources":["../../src/mail/resend.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,MAA0B,EAAE,GAAiB;IAC3E,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,+BAA+B,EAAE;YACvD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAClF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;SAC1B,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,EAAE,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Tx } from '../db/client.js';
|
|
2
|
+
/** Notificações in-app, tenant-scoped. Base para canais futuros (e-mail/push). */
|
|
3
|
+
export interface NotificationRecord {
|
|
4
|
+
id: string;
|
|
5
|
+
userId: string;
|
|
6
|
+
type: 'info' | 'warning' | 'action_required';
|
|
7
|
+
title: string;
|
|
8
|
+
body: string | null;
|
|
9
|
+
linkRef: unknown;
|
|
10
|
+
readAt: string | null;
|
|
11
|
+
createdAt: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function createNotification(tx: Tx, input: {
|
|
14
|
+
userId: string;
|
|
15
|
+
title: string;
|
|
16
|
+
body?: string | null;
|
|
17
|
+
type?: 'info' | 'warning' | 'action_required';
|
|
18
|
+
linkRef?: unknown;
|
|
19
|
+
}): Promise<void>;
|
|
20
|
+
export declare function listNotifications(tx: Tx, userId: string, limit?: number): Promise<NotificationRecord[]>;
|
|
21
|
+
export declare function unreadCount(tx: Tx, userId: string): Promise<number>;
|
|
22
|
+
export declare function markNotificationRead(tx: Tx, id: string, userId: string): Promise<number>;
|
|
23
|
+
//# sourceMappingURL=repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/notifications/repository.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAE1C,kFAAkF;AAClF,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,iBAAiB,CAAC;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,EAAE,EACN,KAAK,EAAE;IACL,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,iBAAiB,CAAC;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GACA,OAAO,CAAC,IAAI,CAAC,CASf;AAED,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAkBzG;AAED,wBAAsB,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKzE;AAED,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO9F"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { uuidv7 } from '@baruk/shared';
|
|
2
|
+
export async function createNotification(tx, input) {
|
|
3
|
+
await tx `
|
|
4
|
+
INSERT INTO notification (id, tenant_id, user_id, type, title, body, link_ref)
|
|
5
|
+
VALUES (
|
|
6
|
+
${uuidv7()}, current_setting('app.current_tenant')::uuid, ${input.userId},
|
|
7
|
+
${input.type ?? 'info'}, ${input.title}, ${input.body ?? null},
|
|
8
|
+
${input.linkRef === undefined ? null : tx.json(input.linkRef)}
|
|
9
|
+
)
|
|
10
|
+
`;
|
|
11
|
+
}
|
|
12
|
+
export async function listNotifications(tx, userId, limit = 30) {
|
|
13
|
+
const rows = await tx `
|
|
14
|
+
SELECT id, user_id, type, title, body, link_ref, read_at, created_at
|
|
15
|
+
FROM notification WHERE user_id = ${userId}
|
|
16
|
+
ORDER BY created_at DESC LIMIT ${Math.min(limit, 100)}
|
|
17
|
+
`;
|
|
18
|
+
return rows.map((r) => ({
|
|
19
|
+
id: r.id,
|
|
20
|
+
userId: r.user_id,
|
|
21
|
+
type: r.type,
|
|
22
|
+
title: r.title,
|
|
23
|
+
body: r.body,
|
|
24
|
+
linkRef: r.link_ref,
|
|
25
|
+
readAt: r.read_at ? r.read_at.toISOString() : null,
|
|
26
|
+
createdAt: r.created_at.toISOString(),
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
export async function unreadCount(tx, userId) {
|
|
30
|
+
const rows = await tx `
|
|
31
|
+
SELECT count(*)::int AS n FROM notification WHERE user_id = ${userId} AND read_at IS NULL
|
|
32
|
+
`;
|
|
33
|
+
return rows[0]?.n ?? 0;
|
|
34
|
+
}
|
|
35
|
+
export async function markNotificationRead(tx, id, userId) {
|
|
36
|
+
const rows = await tx `
|
|
37
|
+
UPDATE notification SET read_at = now()
|
|
38
|
+
WHERE id = ${id} AND user_id = ${userId} AND read_at IS NULL
|
|
39
|
+
RETURNING id
|
|
40
|
+
`;
|
|
41
|
+
return rows.count;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/notifications/repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAevC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,EAAM,EACN,KAMC;IAED,MAAM,EAAE,CAAA;;;QAGF,MAAM,EAAE,kDAAkD,KAAK,CAAC,MAAM;QACtE,KAAK,CAAC,IAAI,IAAI,MAAM,KAAK,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,IAAI,IAAI;QAC3D,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAgB,CAAC;;GAEzE,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EAAM,EAAE,MAAc,EAAE,KAAK,GAAG,EAAE;IACxE,MAAM,IAAI,GAAG,MAAM,EAAE,CAEpB;;wCAEqC,MAAM;qCACT,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC;GACtD,CAAC;IACF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtB,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,MAAM,EAAE,CAAC,CAAC,OAAO;QACjB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,CAAC,CAAC,QAAQ;QACnB,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI;QAClD,SAAS,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW,EAAE;KACtC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,EAAM,EAAE,MAAc;IACtD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAiB;kEAC0B,MAAM;GACrE,CAAC;IACF,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,EAAM,EAAE,EAAU,EAAE,MAAc;IAC3E,MAAM,IAAI,GAAG,MAAM,EAAE,CAAA;;iBAEN,EAAE,kBAAkB,MAAM;;GAExC,CAAC;IACF,OAAO,IAAI,CAAC,KAAK,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Tx } from '../db/client.js';
|
|
2
|
+
/**
|
|
3
|
+
* Acesso de portal: liga um usuário `client_portal` a um `client` específico.
|
|
4
|
+
* O portal restringe TODA leitura ao `clientId` resolvido aqui — um cliente
|
|
5
|
+
* nunca vê outro cliente do mesmo tenant.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getPortalClientId(tx: Tx, userId: string): Promise<string>;
|
|
8
|
+
/** IDs dos usuários de portal ativos vinculados a um client (fan-out de notificações). */
|
|
9
|
+
export declare function listPortalUserIds(tx: Tx, clientId: string): Promise<string[]>;
|
|
10
|
+
export declare function ensurePortalAccess(tx: Tx, userId: string, clientId: string): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/portal/repository.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAE1C;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ/E;AAED,0FAA0F;AAC1F,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAMnF;AAED,wBAAsB,kBAAkB,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMhG"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ForbiddenError, uuidv7 } from '@baruk/shared';
|
|
2
|
+
/**
|
|
3
|
+
* Acesso de portal: liga um usuário `client_portal` a um `client` específico.
|
|
4
|
+
* O portal restringe TODA leitura ao `clientId` resolvido aqui — um cliente
|
|
5
|
+
* nunca vê outro cliente do mesmo tenant.
|
|
6
|
+
*/
|
|
7
|
+
export async function getPortalClientId(tx, userId) {
|
|
8
|
+
const rows = await tx `
|
|
9
|
+
SELECT client_id FROM client_portal_access
|
|
10
|
+
WHERE user_id = ${userId} AND status = 'active'
|
|
11
|
+
ORDER BY created_at ASC LIMIT 1
|
|
12
|
+
`;
|
|
13
|
+
if (!rows[0])
|
|
14
|
+
throw new ForbiddenError('Usuário de portal sem cliente vinculado');
|
|
15
|
+
return rows[0].client_id;
|
|
16
|
+
}
|
|
17
|
+
/** IDs dos usuários de portal ativos vinculados a um client (fan-out de notificações). */
|
|
18
|
+
export async function listPortalUserIds(tx, clientId) {
|
|
19
|
+
const rows = await tx `
|
|
20
|
+
SELECT user_id FROM client_portal_access
|
|
21
|
+
WHERE client_id = ${clientId} AND status = 'active'
|
|
22
|
+
`;
|
|
23
|
+
return rows.map((r) => r.user_id);
|
|
24
|
+
}
|
|
25
|
+
export async function ensurePortalAccess(tx, userId, clientId) {
|
|
26
|
+
await tx `
|
|
27
|
+
INSERT INTO client_portal_access (id, tenant_id, user_id, client_id)
|
|
28
|
+
VALUES (${uuidv7()}, current_setting('app.current_tenant')::uuid, ${userId}, ${clientId})
|
|
29
|
+
ON CONFLICT (tenant_id, user_id, client_id) DO NOTHING
|
|
30
|
+
`;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/portal/repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAGvD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EAAM,EAAE,MAAc;IAC5D,MAAM,IAAI,GAAG,MAAM,EAAE,CAAyB;;sBAE1B,MAAM;;GAEzB,CAAC;IACF,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,MAAM,IAAI,cAAc,CAAC,yCAAyC,CAAC,CAAC;IAClF,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3B,CAAC;AAED,0FAA0F;AAC1F,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EAAM,EAAE,QAAgB;IAC9D,MAAM,IAAI,GAAG,MAAM,EAAE,CAAuB;;wBAEtB,QAAQ;GAC7B,CAAC;IACF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,EAAM,EAAE,MAAc,EAAE,QAAgB;IAC/E,MAAM,EAAE,CAAA;;cAEI,MAAM,EAAE,kDAAkD,MAAM,KAAK,QAAQ;;GAExF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catálogo de produtos do ecossistema Baruk (ADR 0004/0005). `internal` = vive
|
|
3
|
+
* neste platform (roteado pelo Hub); `external` = sistema separado (ex.: Baruk
|
|
4
|
+
* Rep/Ind = Manga Verde em baruk.app), acessado via `baseUrl`.
|
|
5
|
+
*/
|
|
6
|
+
export interface ProductDef {
|
|
7
|
+
key: string;
|
|
8
|
+
name: string;
|
|
9
|
+
kind: 'internal' | 'external';
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
isActive?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare const PRODUCTS: readonly ProductDef[];
|
|
14
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/products/catalog.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,QAAQ,EAAE,SAAS,UAAU,EAKzC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const PRODUCTS = [
|
|
2
|
+
{ key: 'contabil', name: 'Baruk Contábil', kind: 'internal', isActive: true },
|
|
3
|
+
{ key: 'rep', name: 'Baruk Rep', kind: 'external', baseUrl: 'https://baruk.app', isActive: true },
|
|
4
|
+
{ key: 'ind', name: 'Baruk Ind', kind: 'external', baseUrl: 'https://baruk.app', isActive: true },
|
|
5
|
+
{ key: 'varejo', name: 'Baruk Varejo', kind: 'external', baseUrl: 'https://baruk.app', isActive: false },
|
|
6
|
+
];
|
|
7
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/products/catalog.ts"],"names":[],"mappings":"AAaA,MAAM,CAAC,MAAM,QAAQ,GAA0B;IAC7C,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC7E,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,IAAI,EAAE;IACjG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,IAAI,EAAE;IACjG,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,KAAK,EAAE;CACzG,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Db, Tx } from '../db/client.js';
|
|
2
|
+
export interface ProductAccess {
|
|
3
|
+
tenantId: string;
|
|
4
|
+
tenantName: string;
|
|
5
|
+
tenantCode: string;
|
|
6
|
+
productKey: string;
|
|
7
|
+
productName: string;
|
|
8
|
+
kind: 'internal' | 'external';
|
|
9
|
+
baseUrl: string | null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Produtos acessíveis ao usuário: cruza suas memberships ativas com os
|
|
13
|
+
* entitlements (tenant_product) ativos. Rode dentro de `withContext({ userId })`
|
|
14
|
+
* — é assim que o Hub sabe a que produtos a pessoa tem direito. Sem entitlement
|
|
15
|
+
* = sem acesso (bloqueio no Hub).
|
|
16
|
+
*/
|
|
17
|
+
export declare function listProductsForUser(tx: Tx, userId: string): Promise<ProductAccess[]>;
|
|
18
|
+
/** Materializa o catálogo global de produtos (idempotente). */
|
|
19
|
+
export declare function ensureProductCatalog(db: Db): Promise<void>;
|
|
20
|
+
/** Concede (ou reativa) um produto a um tenant. */
|
|
21
|
+
export declare function ensureTenantProduct(db: Db, tenantId: string, productKey: string): Promise<void>;
|
|
22
|
+
//# sourceMappingURL=repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/products/repository.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAI9C,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CA8B1F;AAED,+DAA+D;AAC/D,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhE;AAED,mDAAmD;AACnD,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUrG"}
|