fix: block creating or moving a colony into an inactive/missing apiary

Colony.apiaryId was never checked against the target apiary at all -
create() would hit a raw Prisma FK-constraint error for a nonexistent
apiary instead of a clean 404, and both create() and move() would
silently succeed against a deactivated apiary, orphaning the colony
the same way (just from the opposite direction) as the apiary-side gap
fixed in the previous commit.

Adds a shared assertApiaryActive() check, following the same
findUnique-then-status pattern already used for cross-entity checks
elsewhere (e.g. QueensService.assertMotherQueenExists), used by both
create() and move().

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Sonnet 5 committed 2026-09-08 22:32:53 +02:00
1 parent 961a237335
commit 5c5c7b756f
2 files changed
+66

No files matched your search

@@ -51,7 +51,27 @@ export class ColoniesService {
}
}
// Colony.apiaryId is a plain FK with no built-in status check - without
// this, a colony could be created or moved into an apiary that either
// doesn't exist (a raw Prisma FK-constraint error instead of a clean
// 404) or is deactivated (silently orphaning the colony the same way an
// apiary deactivated out from under an existing colony would).
private async assertApiaryActive(apiaryId: string): Promise<void> {
const apiary = await this.prisma.apiary.findUnique({
where: { id: apiaryId },
});
if (!apiary) {
throw new NotFoundException(`Apiary ${apiaryId} not found`);
}
if (apiary.status !== 'ACTIVE') {
throw new ConflictException(
`Apiary ${apiaryId} is not active (status: ${apiary.status})`,
);
}
}
async create(dto: CreateColonyDto, actingUserId: string): Promise<Colony> {
await this.assertApiaryActive(dto.apiaryId);
const colony = await this.prisma.colony.create({ data: { ...dto } });
await this.auditLog.record({
entityType: 'Colony',
@@ -93,6 +113,7 @@ export class ColoniesService {
): Promise<Colony> {
const before = await this.findById(id);
this.assertActive(before);
await this.assertApiaryActive(dto.apiaryId);
const colony = await this.prisma.$transaction(async (tx) => {
const updated = await tx.colony.update({
where: { id },