cd78f72f33
Complete rename of all technical identifiers across the codebase: Package names (11 packages): - @planarchy/* → @capakraken/* in all package.json, tsconfig, imports Import statements: 277 files, 548 occurrences replaced Database & Docker: - PostgreSQL user/db: planarchy → capakraken - Docker volumes: planarchy_pgdata → capakraken_pgdata - Connection strings updated in docker-compose, .env, CI CI/CD: - GitHub Actions workflow: all filter commands updated - Test database credentials updated Infrastructure: - Redis channel: planarchy:sse → capakraken:sse - Logger service name: planarchy-api → capakraken-api - Anonymization seed updated - Start/stop/restart scripts updated Test data: - Seed emails: @planarchy.dev → @capakraken.dev - E2E test credentials: all 11 spec files updated - Email defaults: @planarchy.app → @capakraken.app - localStorage keys: planarchy_* → capakraken_* Documentation: 30+ .md files updated Verification: - pnpm install: workspace resolution works - TypeScript: only pre-existing TS2589 (no new errors) - Engine: 310/310 tests pass - Staffing: 37/37 tests pass Co-Authored-By: claude-flow <ruv@ruv.net>
72 lines
2.0 KiB
TypeScript
72 lines
2.0 KiB
TypeScript
import { prisma } from "@capakraken/db";
|
|
|
|
type PrismaClient = typeof prisma;
|
|
|
|
/**
|
|
* Resolve recipient user IDs for a broadcast target.
|
|
* Deduplicates results and optionally excludes the sender.
|
|
*/
|
|
export async function resolveRecipients(
|
|
targetType: string,
|
|
targetValue: string | null | undefined,
|
|
db: PrismaClient,
|
|
excludeUserId?: string,
|
|
): Promise<string[]> {
|
|
let userIds: string[] = [];
|
|
|
|
switch (targetType) {
|
|
case "user":
|
|
if (targetValue) userIds = [targetValue];
|
|
break;
|
|
|
|
case "role": {
|
|
// Find all users with the given systemRole
|
|
const roleUsers = await db.user.findMany({
|
|
where: { systemRole: targetValue as "ADMIN" | "MANAGER" | "CONTROLLER" | "USER" | "VIEWER" },
|
|
select: { id: true },
|
|
});
|
|
userIds = roleUsers.map((u) => u.id);
|
|
break;
|
|
}
|
|
|
|
case "project": {
|
|
// Find all resources with assignments on this project, then their linked users
|
|
if (!targetValue) break;
|
|
const assignments = await db.assignment.findMany({
|
|
where: { projectId: targetValue, status: { not: "CANCELLED" } },
|
|
select: { resource: { select: { userId: true } } },
|
|
});
|
|
userIds = assignments
|
|
.map((a) => a.resource.userId)
|
|
.filter((id): id is string => !!id);
|
|
break;
|
|
}
|
|
|
|
case "orgUnit": {
|
|
// Find all resources in this orgUnit, then their linked users
|
|
if (!targetValue) break;
|
|
const resources = await db.resource.findMany({
|
|
where: { orgUnitId: targetValue, isActive: true },
|
|
select: { userId: true },
|
|
});
|
|
userIds = resources
|
|
.map((r) => r.userId)
|
|
.filter((id): id is string => !!id);
|
|
break;
|
|
}
|
|
|
|
case "all": {
|
|
// User model has no isActive — get all users
|
|
const allUsers = await db.user.findMany({
|
|
select: { id: true },
|
|
});
|
|
userIds = allUsers.map((u) => u.id);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Deduplicate and exclude sender
|
|
const unique = [...new Set(userIds)];
|
|
return excludeUserId ? unique.filter((id) => id !== excludeUserId) : unique;
|
|
}
|