fix(documents): tighten aggregation — filter ended memberships + symmetry
Four follow-ups from Task 8 code review: 1. Aggregation now filters companyMemberships to active rows only (isNull(endDate)) on both client→companies and company→clients joins. Previously a rep who left a company 2y ago would still see that company's files in their aggregated view. Brings this service in line with the 8 other call sites in the codebase that already filter on endDate. 2. Move collectRelatedEntities import to the top of documents.service.ts — was wedged mid-file. 3. listInflightWorkflowsAggregatedByEntity now calls assertEntityInPort for symmetry with the files version. Cross- port reads short-circuit early instead of executing N empty port-scoped queries. 4. Add a cross-port leakage regression test for the workflow projection. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { and, arrayContains, desc, eq, inArray, or, sql } from 'drizzle-orm';
|
||||
import { and, arrayContains, desc, eq, inArray, isNull, or, sql } from 'drizzle-orm';
|
||||
|
||||
import { db } from '@/lib/db';
|
||||
import { files, documents } from '@/lib/db/schema/documents';
|
||||
@@ -364,7 +364,7 @@ export async function listFilesAggregatedByEntity(
|
||||
return { groups };
|
||||
}
|
||||
|
||||
async function assertEntityInPort(
|
||||
export async function assertEntityInPort(
|
||||
portId: string,
|
||||
entityType: EntityType,
|
||||
entityId: string,
|
||||
@@ -415,7 +415,9 @@ export async function collectRelatedEntities(
|
||||
companies,
|
||||
and(eq(companies.id, companyMemberships.companyId), eq(companies.portId, portId)),
|
||||
)
|
||||
.where(eq(companyMemberships.clientId, entityId));
|
||||
.where(
|
||||
and(eq(companyMemberships.clientId, entityId), isNull(companyMemberships.endDate)),
|
||||
);
|
||||
|
||||
const directYachts = await db
|
||||
.select({ id: yachts.id, name: yachts.name })
|
||||
@@ -461,7 +463,9 @@ export async function collectRelatedEntities(
|
||||
clients,
|
||||
and(eq(clients.id, companyMemberships.clientId), eq(clients.portId, portId)),
|
||||
)
|
||||
.where(eq(companyMemberships.companyId, entityId));
|
||||
.where(
|
||||
and(eq(companyMemberships.companyId, entityId), isNull(companyMemberships.endDate)),
|
||||
);
|
||||
|
||||
const ownedYachts = await db
|
||||
.select({ id: yachts.id, name: yachts.name })
|
||||
@@ -561,10 +565,7 @@ export async function applyEntityFkFromFolder<
|
||||
if (!payload.folderId) return payload;
|
||||
|
||||
const folder = await db.query.documentFolders.findFirst({
|
||||
where: and(
|
||||
eq(documentFolders.id, payload.folderId),
|
||||
eq(documentFolders.portId, portId),
|
||||
),
|
||||
where: and(eq(documentFolders.id, payload.folderId), eq(documentFolders.portId, portId)),
|
||||
columns: { systemManaged: true, entityType: true, entityId: true },
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user