feat(housekeeping): unify complete rebuild in gated preview
CI / check (pull_request) Failing after 10s
CI / deploy (pull_request) Skipped
CI / release (pull_request) Skipped

This commit is contained in:
Simo committed 2026-08-31 20:37:51 +02:00
1 parent 4ad007d241
commit 43470ebf82
402 files changed
+78313 -1663

No files matched your search

@@ -0,0 +1,167 @@
import { describe, expect, it, vi } from "vitest";
import { PERMS } from "@/lib/permission-slugs";
import {
anyCapability,
type HousekeepingCapabilityContext,
} from "../contracts";
import type { HousekeepingRegistry } from "../registry";
import {
createHousekeepingRecentWorkService,
RECENT_WORK_POLICY,
} from "./recent-work";
const usersView = anyCapability(PERMS.USERS_VIEW);
const bansView = anyCapability(PERMS.BANS_VIEW);
function registry(routeCount = 2): HousekeepingRegistry {
return {
domains: [
{
id: "people",
labelKey: "people",
descriptionKey: "people.description",
iconId: "users",
canonicalHref: "/ase-next/people",
capability: usersView,
routes: Array.from({ length: routeCount }, (_, index) => ({
id: index === 0 ? "people.users" : `people.route-${index}`,
labelKey:
index === 0 ? "routes.people.users" : `routes.people.${index}`,
href:
index === 0
? "/ase-next/people/users"
: (`/ase-next/people/route-${index}` as const),
capability: index === 1 ? bansView : usersView,
})),
searchProviders: [],
inboxSources: [],
widgets: [],
},
],
};
}
const context: HousekeepingCapabilityContext = {
actor: { id: 42, username: "operator", rank: 7 },
isSuperAdmin: false,
has: (slug) => slug === PERMS.USERS_VIEW,
hasAny: (...slugs) => slugs.includes(PERMS.USERS_VIEW),
hasAll: (...slugs) => slugs.every((slug) => slug === PERMS.USERS_VIEW),
};
describe("housekeeping recent work", () => {
it("derives newest authorized route visits and mutation audits, then deduplicates by route", async () => {
const loadRows = vi.fn().mockResolvedValue([
{
action: "housekeeping.route.visit",
target: "people.users",
domain: "people",
outcome: "success",
createdAt: "2026-08-30T10:01:00.000Z",
},
{
action: "people.user.update",
target: "People",
domain: "people",
outcome: "success",
createdAt: "2026-08-30T10:03:00.000Z",
},
{
action: "housekeeping.route.visit",
target: "people.route-1",
domain: "people",
outcome: "success",
createdAt: "2026-08-30T10:04:00.000Z",
},
{
action: "people.user.delete",
target: "People",
domain: "people",
outcome: "failure",
createdAt: "2026-08-30T10:05:00.000Z",
},
{
action: "people.unknown.update",
target: "People",
domain: "people",
outcome: "success",
createdAt: "2026-08-30T10:06:00.000Z",
},
]);
const service = createHousekeepingRecentWorkService({
registry: registry(),
loadRows,
writeAudit: vi.fn(),
createCorrelationId: () => "recent-1",
});
const result = await service.load(context);
expect(loadRows).toHaveBeenCalledWith(42, RECENT_WORK_POLICY.scanLimit);
expect(result).toEqual({
ok: true,
data: [
{
routeId: "people.users",
canonicalHref: "/ase-next/people/users",
labelKey: "routes.people.users",
occurredAt: "2026-08-30T10:03:00.000Z",
source: "audit",
},
],
correlationId: "recent-1",
});
});
it("caps authorized unique recent routes at twelve", async () => {
const rows = Array.from({ length: 14 }, (_, index) => ({
action: "housekeeping.route.visit",
target: index === 0 ? "people.users" : `people.route-${index + 1}`,
domain: "people",
outcome: "success",
createdAt: new Date(Date.UTC(2026, 7, 30, 12, index)).toISOString(),
}));
const service = createHousekeepingRecentWorkService({
registry: registry(16),
loadRows: vi.fn().mockResolvedValue(rows),
writeAudit: vi.fn(),
});
const result = await service.load(context);
expect(result.ok && result.data).toHaveLength(RECENT_WORK_POLICY.limit);
expect(result.ok && result.data[0]?.occurredAt).toBe(
"2026-08-30T12:13:00.000Z",
);
});
it("records only an authorized canonical route visit for the server actor", async () => {
const writeAudit = vi.fn().mockResolvedValue(undefined);
const service = createHousekeepingRecentWorkService({
registry: registry(),
loadRows: vi.fn(),
writeAudit,
createCorrelationId: () => "visit-1",
});
const allowed = await service.recordVisit("people.users", context);
const denied = await service.recordVisit("people.route-1", context);
expect(allowed).toMatchObject({
ok: true,
data: { routeId: "people.users", canonicalHref: "/ase-next/people/users" },
});
expect(writeAudit).toHaveBeenCalledOnce();
expect(writeAudit).toHaveBeenCalledWith(
expect.objectContaining({
userId: 42,
action: "housekeeping.route.visit",
target: "people.users",
domain: "people",
outcome: "success",
correlationId: "visit-1",
}),
);
expect(denied).toMatchObject({ ok: false, error: { code: "FORBIDDEN" } });
});
});
@@ -0,0 +1,256 @@
import "server-only";
import type { AuditEntry } from "@/lib/services/audit";
import { satisfiesCapability } from "../capability-context";
import {
type CanonicalHousekeepingHref,
fail,
type HousekeepingCapabilityContext,
type HousekeepingDomainManifest,
type HousekeepingResult,
ok,
} from "../contracts";
import { createCorrelationId } from "../correlation";
import type { HousekeepingRegistry } from "../registry";
export const RECENT_WORK_POLICY = Object.freeze({
limit: 12,
scanLimit: 200,
dedupe: "routeId",
} as const);
export interface HousekeepingRecentItem {
readonly routeId: string;
readonly canonicalHref: CanonicalHousekeepingHref;
readonly labelKey: string;
readonly occurredAt: string;
readonly source: "route-visit" | "audit";
}
export interface HousekeepingRecentAuditRow {
readonly action: string;
readonly target: string;
readonly domain: string | null;
readonly outcome: string | null;
readonly createdAt: string;
}
interface RegisteredRoute {
readonly domain: HousekeepingDomainManifest;
readonly route: HousekeepingDomainManifest["routes"][number];
}
export interface HousekeepingRecentWorkDependencies {
readonly registry: HousekeepingRegistry;
readonly loadRows: (
userId: number,
limit: number,
) => Promise<readonly HousekeepingRecentAuditRow[]>;
readonly writeAudit: (entry: AuditEntry) => Promise<void>;
readonly createCorrelationId?: () => string;
}
const completedOutcomes = new Set(["success", "partial"]);
const genericActionTokens = new Set([
"add",
"apply",
"change",
"create",
"delete",
"execute",
"remove",
"runtime",
"save",
"set",
"toggle",
"update",
]);
function registeredRoutes(
registry: HousekeepingRegistry,
): readonly RegisteredRoute[] {
return registry.domains.flatMap((domain) =>
domain.routes.map((route) => ({ domain, route })),
);
}
function normalizedTokens(value: string): readonly string[] {
return value
.toLocaleLowerCase()
.split(/[^a-z0-9]+/)
.filter(Boolean)
.map((token) => {
if (token.endsWith("ies") && token.length > 3) {
return `${token.slice(0, -3)}y`;
}
if (token.endsWith("s") && token.length > 3) return token.slice(0, -1);
return token;
})
.filter((token) => !genericActionTokens.has(token));
}
function authorized(
entry: RegisteredRoute,
context: HousekeepingCapabilityContext,
): boolean {
return (
satisfiesCapability(context, entry.domain.capability) &&
satisfiesCapability(context, entry.route.capability)
);
}
function routeForAudit(
row: HousekeepingRecentAuditRow,
routes: readonly RegisteredRoute[],
context: HousekeepingCapabilityContext,
): RegisteredRoute | undefined {
const domainRoutes = routes.filter(
(entry) => entry.domain.id === row.domain && authorized(entry, context),
);
const exact = domainRoutes.find((entry) => entry.route.id === row.target);
if (exact) return exact;
const actionTokens = new Set(
normalizedTokens(row.action).filter((token) => token !== row.domain),
);
let best: { entry: RegisteredRoute; score: number } | undefined;
for (const entry of domainRoutes) {
const score = normalizedTokens(entry.route.id)
.filter((token) => token !== row.domain)
.reduce((total, token) => total + (actionTokens.has(token) ? 1 : 0), 0);
if (score > 0 && (!best || score > best.score)) best = { entry, score };
}
return best?.entry;
}
function recentItem(
row: HousekeepingRecentAuditRow,
route: RegisteredRoute,
): HousekeepingRecentItem {
return {
routeId: route.route.id,
canonicalHref: route.route.href,
labelKey: route.route.labelKey,
occurredAt: row.createdAt,
source: row.action === "housekeeping.route.visit" ? "route-visit" : "audit",
};
}
export function deriveHousekeepingRecentWork(
rows: readonly HousekeepingRecentAuditRow[],
registry: HousekeepingRegistry,
context: HousekeepingCapabilityContext,
): readonly HousekeepingRecentItem[] {
const routes = registeredRoutes(registry);
const sorted = [...rows].sort(
(left, right) => Date.parse(right.createdAt) - Date.parse(left.createdAt),
);
const seen = new Set<string>();
const items: HousekeepingRecentItem[] = [];
for (const row of sorted) {
if (!completedOutcomes.has(row.outcome ?? "")) continue;
if (!Number.isFinite(Date.parse(row.createdAt))) continue;
const route =
row.action === "housekeeping.route.visit"
? routes.find(
(entry) =>
entry.route.id === row.target && authorized(entry, context),
)
: routeForAudit(row, routes, context);
if (!route || seen.has(route.route.id)) continue;
seen.add(route.route.id);
items.push(recentItem(row, route));
if (items.length === RECENT_WORK_POLICY.limit) break;
}
return items;
}
export function createHousekeepingRecentWorkService({
registry,
loadRows,
writeAudit,
createCorrelationId: correlationIdFactory = createCorrelationId,
}: HousekeepingRecentWorkDependencies) {
return {
async load(
context: HousekeepingCapabilityContext,
): Promise<HousekeepingResult<readonly HousekeepingRecentItem[]>> {
const correlationId = correlationIdFactory();
try {
const rows = await loadRows(
context.actor.id,
RECENT_WORK_POLICY.scanLimit,
);
return ok(
deriveHousekeepingRecentWork(rows, registry, context),
correlationId,
);
} catch {
return fail(
"INTERNAL",
"errors.housekeeping.recent.read",
correlationId,
);
}
},
async recordVisit(
routeId: string,
context: HousekeepingCapabilityContext,
): Promise<HousekeepingResult<HousekeepingRecentItem>> {
const correlationId = correlationIdFactory();
const entry = registeredRoutes(registry).find(
(candidate) => candidate.route.id === routeId,
);
if (!entry) {
return fail(
"NOT_FOUND",
"errors.housekeeping.recent.routeNotFound",
correlationId,
);
}
if (!authorized(entry, context)) {
return fail(
"FORBIDDEN",
"errors.housekeeping.forbidden",
correlationId,
);
}
const occurredAt = new Date().toISOString();
try {
await writeAudit({
userId: context.actor.id,
action: "housekeeping.route.visit",
target: entry.route.id,
after: {
canonicalHref: entry.route.href,
labelKey: entry.route.labelKey,
},
correlationId,
outcome: "success",
domain: entry.domain.id,
});
return ok(
{
routeId: entry.route.id,
canonicalHref: entry.route.href,
labelKey: entry.route.labelKey,
occurredAt,
source: "route-visit",
},
correlationId,
);
} catch {
return fail(
"INTERNAL",
"errors.housekeeping.recent.record",
correlationId,
);
}
},
};
}