feat: T6 wave 1 – compliance schema, permissions, lock order, backup
- Migrations (additive): veterinary medicines with lots and movement ledger, treatment medicine/lot/dose links, label particulars, authority notices, apiary restrictions, compliance settings and acknowledgements; notification category COMPLIANCE, added to non-empty Telegram lists. - Permissions veterinary-medicines:* and compliance:* with role grants. - LOCKABLE_TABLES: Apiary locks before Colony; T6 tables appended. - Backup exports and restores the new tables in FK order; unsealed files skip them and report dropped medicine links; an open TSK draft in the target wins. - describeNullContracts shared helper; Telegram backlog e2e no longer depends on the time of day. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
7a1480138d
commit
8a31c42578
23 files changed
+2028
-84
No files matched your search
@@ -0,0 +1,116 @@
|
||||
import { PERMISSION_CATALOG } from '../src/auth/permissions/permission-catalog';
|
||||
import { PrismaService } from '../src/prisma/prisma.service';
|
||||
|
||||
const NEW_KEYS = [
|
||||
'veterinary-medicines:read',
|
||||
'veterinary-medicines:create',
|
||||
'veterinary-medicines:update',
|
||||
'compliance:read',
|
||||
'compliance:manage',
|
||||
] as const;
|
||||
|
||||
/**
|
||||
* The migrations grant the T6 permissions to the system roles (the boot-time
|
||||
* catalog sync only grants new permissions to ADMIN). Checked against the
|
||||
* migrated test database.
|
||||
*/
|
||||
describe('T6 permissions (e2e)', () => {
|
||||
let prisma: PrismaService;
|
||||
|
||||
beforeAll(() => {
|
||||
prisma = new PrismaService();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
||||
async function newKeysOf(roleKey: string): Promise<string[]> {
|
||||
const grants = await prisma.rolePermission.findMany({
|
||||
where: {
|
||||
role: { key: roleKey },
|
||||
permission: { key: { in: [...NEW_KEYS] } },
|
||||
},
|
||||
include: { permission: { select: { key: true } } },
|
||||
});
|
||||
return grants.map((grant) => grant.permission.key).sort();
|
||||
}
|
||||
|
||||
it('BEEKEEPER holds compliance:manage and veterinary-medicines:update', async () => {
|
||||
const keys = await newKeysOf('BEEKEEPER');
|
||||
|
||||
expect(keys).toEqual([...NEW_KEYS].sort());
|
||||
expect(keys).toContain('compliance:manage');
|
||||
expect(keys).toContain('veterinary-medicines:update');
|
||||
});
|
||||
|
||||
it('ADMIN holds all five', async () => {
|
||||
expect(await newKeysOf('ADMIN')).toEqual([...NEW_KEYS].sort());
|
||||
});
|
||||
|
||||
it('STAFF holds compliance:read and veterinary-medicines:create but not compliance:manage', async () => {
|
||||
const keys = await newKeysOf('STAFF');
|
||||
|
||||
expect(keys).toContain('compliance:read');
|
||||
expect(keys).toContain('veterinary-medicines:create');
|
||||
expect(keys).not.toContain('compliance:manage');
|
||||
expect(keys).toEqual(
|
||||
[
|
||||
'veterinary-medicines:read',
|
||||
'veterinary-medicines:create',
|
||||
'veterinary-medicines:update',
|
||||
'compliance:read',
|
||||
].sort(),
|
||||
);
|
||||
});
|
||||
|
||||
it('READONLY holds the two read permissions only', async () => {
|
||||
expect(await newKeysOf('READONLY')).toEqual(
|
||||
['compliance:read', 'veterinary-medicines:read'].sort(),
|
||||
);
|
||||
});
|
||||
|
||||
it('API_CLIENT holds none of the five new permissions', async () => {
|
||||
expect(await newKeysOf('API_CLIENT')).toEqual([]);
|
||||
});
|
||||
|
||||
it('the database rows carry the catalog labels, groups and sort order', async () => {
|
||||
const rows = await prisma.permission.findMany({
|
||||
where: { key: { in: [...NEW_KEYS] } },
|
||||
});
|
||||
|
||||
expect(rows).toHaveLength(NEW_KEYS.length);
|
||||
for (const row of rows) {
|
||||
const entry = PERMISSION_CATALOG.find((e) => e.key === row.key);
|
||||
expect(entry).toBeDefined();
|
||||
expect({
|
||||
resource: row.resource,
|
||||
action: row.action,
|
||||
labelDe: row.labelDe,
|
||||
groupDe: row.groupDe,
|
||||
sortOrder: row.sortOrder,
|
||||
}).toEqual({
|
||||
resource: entry?.resource,
|
||||
action: entry?.action,
|
||||
labelDe: entry?.labelDe,
|
||||
groupDe: entry?.groupDe,
|
||||
sortOrder: entry?.sortOrder,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('the catalog groups the new permissions at 3700 and 3800', () => {
|
||||
const order = (key: string) =>
|
||||
PERMISSION_CATALOG.find((e) => e.key === key)?.sortOrder;
|
||||
const group = (key: string) =>
|
||||
PERMISSION_CATALOG.find((e) => e.key === key)?.groupDe;
|
||||
|
||||
expect(order('veterinary-medicines:read')).toBe(3700);
|
||||
expect(order('veterinary-medicines:create')).toBe(3701);
|
||||
expect(order('veterinary-medicines:update')).toBe(3702);
|
||||
expect(order('compliance:read')).toBe(3800);
|
||||
expect(order('compliance:manage')).toBe(3801);
|
||||
expect(group('veterinary-medicines:read')).toBe('Tierarzneimittel');
|
||||
expect(group('compliance:manage')).toBe('Prüfbereitschaft & Behörden');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user