feat(platform): harden access scoping and delivery baseline
This commit is contained in:
@@ -27,6 +27,32 @@ type ResourceGraphMeta = {
|
||||
};
|
||||
};
|
||||
|
||||
type ResourceGraphDetail = {
|
||||
resource: { id: string; eid: string; displayName: string };
|
||||
availableDomains: string[];
|
||||
requestedDomain: string | null;
|
||||
totalNodeCount: number;
|
||||
totalLinkCount: number;
|
||||
selectedNodeCount: number;
|
||||
selectedLinkCount: number;
|
||||
nodes: Array<{ id: string; domain: string }>;
|
||||
};
|
||||
|
||||
type ProjectGraphDetail = {
|
||||
project: { id: string; shortCode: string; name: string };
|
||||
availableDomains: string[];
|
||||
requestedDomain: string | null;
|
||||
totalNodeCount: number;
|
||||
selectedNodeCount: number;
|
||||
selectedLinkCount: number;
|
||||
nodes: Array<{ id: string; domain: string }>;
|
||||
links?: Array<{ source: string; target: string }>;
|
||||
meta: {
|
||||
projectName: string;
|
||||
projectCode: string;
|
||||
};
|
||||
};
|
||||
|
||||
function createControllerCaller(db: Record<string, unknown>) {
|
||||
return createCaller({
|
||||
session: {
|
||||
@@ -99,6 +125,47 @@ function buildResource(overrides: Record<string, unknown> = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
function createProjectDb(projectFindImpl: ReturnType<typeof vi.fn>) {
|
||||
return {
|
||||
project: {
|
||||
findUniqueOrThrow: projectFindImpl,
|
||||
},
|
||||
estimate: {
|
||||
findFirst: vi.fn().mockResolvedValue(null),
|
||||
},
|
||||
assignment: {
|
||||
findMany: vi.fn().mockResolvedValue([
|
||||
{
|
||||
status: "CONFIRMED",
|
||||
dailyCostCents: 4_000,
|
||||
startDate: new Date("2026-01-05T00:00:00.000Z"),
|
||||
endDate: new Date("2026-01-30T00:00:00.000Z"),
|
||||
hoursPerDay: 4,
|
||||
},
|
||||
]),
|
||||
},
|
||||
effortRule: {
|
||||
count: vi.fn().mockResolvedValue(0),
|
||||
},
|
||||
experienceMultiplierRule: {
|
||||
count: vi.fn().mockResolvedValue(0),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function buildProject(overrides: Record<string, unknown> = {}) {
|
||||
return {
|
||||
id: "project_1",
|
||||
name: "Gelddruckmaschine",
|
||||
shortCode: "GDM",
|
||||
budgetCents: 100_000,
|
||||
winProbability: 75,
|
||||
startDate: new Date("2026-01-05T00:00:00.000Z"),
|
||||
endDate: new Date("2026-02-28T00:00:00.000Z"),
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("computation graph router", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
@@ -192,4 +259,60 @@ describe("computation graph router", () => {
|
||||
expect.objectContaining({ name: "Heilige Drei Könige", date: "2026-01-06" }),
|
||||
]));
|
||||
});
|
||||
|
||||
it("returns a filtered resource detail graph with canonical selection metadata", async () => {
|
||||
const db = createDb(vi.fn().mockResolvedValue(buildResource({
|
||||
id: "resource_augsburg",
|
||||
metroCityId: "city_augsburg",
|
||||
metroCity: { id: "city_augsburg", name: "Augsburg" },
|
||||
})));
|
||||
|
||||
const caller = createControllerCaller(db);
|
||||
const result = await caller.getResourceDataDetail({
|
||||
resourceId: "resource_augsburg",
|
||||
month: "2026-08",
|
||||
domain: "SAH",
|
||||
}) as ResourceGraphDetail;
|
||||
|
||||
expect(result.resource).toEqual({
|
||||
id: "resource_augsburg",
|
||||
eid: "bruce.banner",
|
||||
displayName: "Bruce Banner",
|
||||
});
|
||||
expect(result.availableDomains).toEqual(expect.arrayContaining(["INPUT", "SAH", "ALLOCATION", "CHARGEABILITY"]));
|
||||
expect(result.requestedDomain).toBe("SAH");
|
||||
expect(result.totalNodeCount).toBeGreaterThan(result.selectedNodeCount);
|
||||
expect(result.totalLinkCount).toBeGreaterThan(0);
|
||||
expect(result.selectedNodeCount).toBeGreaterThan(0);
|
||||
expect(result.selectedLinkCount).toBe(0);
|
||||
expect(result.nodes.every((node) => node.domain === "SAH")).toBe(true);
|
||||
});
|
||||
|
||||
it("returns a filtered project detail graph with canonical project identity", async () => {
|
||||
const db = createProjectDb(vi.fn().mockResolvedValue(buildProject()));
|
||||
|
||||
const caller = createControllerCaller(db);
|
||||
const result = await caller.getProjectDataDetail({
|
||||
projectId: "project_1",
|
||||
domain: "BUDGET",
|
||||
includeLinks: true,
|
||||
}) as ProjectGraphDetail;
|
||||
|
||||
expect(result.project).toEqual({
|
||||
id: "project_1",
|
||||
shortCode: "GDM",
|
||||
name: "Gelddruckmaschine",
|
||||
});
|
||||
expect(result.meta).toEqual({
|
||||
projectName: "Gelddruckmaschine",
|
||||
projectCode: "GDM",
|
||||
});
|
||||
expect(result.availableDomains).toEqual(expect.arrayContaining(["INPUT", "BUDGET"]));
|
||||
expect(result.requestedDomain).toBe("BUDGET");
|
||||
expect(result.totalNodeCount).toBeGreaterThan(result.selectedNodeCount);
|
||||
expect(result.selectedNodeCount).toBeGreaterThan(0);
|
||||
expect(result.selectedLinkCount).toBeGreaterThan(0);
|
||||
expect(result.nodes.every((node) => node.domain === "BUDGET")).toBe(true);
|
||||
expect(result.links?.length).toBe(result.selectedLinkCount);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user