fix(documents): folder service · audit + portId + audit-log placement

Code-review followups on e9251a3:
- Move createAuditLog OUT of the deleteFolderSoftRescue transaction
  callback so a rolled-back transaction can't leave a phantom audit
  row. Pattern matches clients.service.ts, expense-dedup.service.ts.
- Add portId filter to the moveFolder ancestor-walk findFirst —
  defense-in-depth so corrupted parentId pointing at another port
  short-circuits the walk instead of silently traversing it.
- Drop updatedAt bump on rescued documents — folder rescue is an
  administrative storage op, not a content change; bumping made
  every rescued doc appear "recently modified" in list views.
- Add userId param + audit-log emission on renameFolder and
  moveFolder for parity with createFolder + deleteFolderSoftRescue.
  Tests updated to pass TEST_USER_ID as the new 4th arg.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 19:50:51 +02:00
parent 9f3e739c76
commit 4ec0004867
2 changed files with 51 additions and 31 deletions

View File

@@ -116,7 +116,7 @@ describe('document-folders service · renameFolder', () => {
const folder = await createFolder(portId, TEST_USER_ID, { name: 'Old', parentId: null });
const before = folder.updatedAt.getTime();
await new Promise((r) => setTimeout(r, 10));
const renamed = await renameFolder(portId, folder.id, 'New');
const renamed = await renameFolder(portId, folder.id, 'New', TEST_USER_ID);
expect(renamed.name).toBe('New');
expect(renamed.updatedAt.getTime()).toBeGreaterThan(before);
});
@@ -124,13 +124,13 @@ describe('document-folders service · renameFolder', () => {
it('rejects rename to an existing sibling name', async () => {
await createFolder(portId, TEST_USER_ID, { name: 'Existing', parentId: null });
const folder = await createFolder(portId, TEST_USER_ID, { name: 'Mine', parentId: null });
await expect(renameFolder(portId, folder.id, 'Existing')).rejects.toThrow(/already exists/i);
await expect(renameFolder(portId, folder.id, 'Existing', TEST_USER_ID)).rejects.toThrow(/already exists/i);
});
it('throws NotFound when the folder belongs to another port', async () => {
const otherPort = await makePort();
const folder = await createFolder(otherPort.id, TEST_USER_ID, { name: 'X', parentId: null });
await expect(renameFolder(portId, folder.id, 'Y')).rejects.toThrow(/couldn't find/i);
await expect(renameFolder(portId, folder.id, 'Y', TEST_USER_ID)).rejects.toThrow(/couldn't find/i);
});
});
@@ -146,14 +146,14 @@ describe('document-folders service · moveFolder', () => {
it('moves a folder under a new parent', async () => {
const root = await createFolder(portId, TEST_USER_ID, { name: 'Root', parentId: null });
const orphan = await createFolder(portId, TEST_USER_ID, { name: 'Orphan', parentId: null });
const moved = await moveFolder(portId, orphan.id, root.id);
const moved = await moveFolder(portId, orphan.id, root.id, TEST_USER_ID);
expect(moved.parentId).toBe(root.id);
});
it('moves a folder back to root with parentId=null', async () => {
const root = await createFolder(portId, TEST_USER_ID, { name: 'Root', parentId: null });
const child = await createFolder(portId, TEST_USER_ID, { name: 'Child', parentId: root.id });
const moved = await moveFolder(portId, child.id, null);
const moved = await moveFolder(portId, child.id, null, TEST_USER_ID);
expect(moved.parentId).toBeNull();
});
@@ -162,11 +162,11 @@ describe('document-folders service · moveFolder', () => {
const b = await createFolder(portId, TEST_USER_ID, { name: 'B', parentId: a.id });
const c = await createFolder(portId, TEST_USER_ID, { name: 'C', parentId: b.id });
// moving A under C would create A → B → C → A
await expect(moveFolder(portId, a.id, c.id)).rejects.toThrow(/cycle/i);
await expect(moveFolder(portId, a.id, c.id, TEST_USER_ID)).rejects.toThrow(/cycle/i);
});
it('rejects moving a folder under itself', async () => {
const a = await createFolder(portId, TEST_USER_ID, { name: 'A', parentId: null });
await expect(moveFolder(portId, a.id, a.id)).rejects.toThrow(/cycle/i);
await expect(moveFolder(portId, a.id, a.id, TEST_USER_ID)).rejects.toThrow(/cycle/i);
});
});