feat: T4 wave 5 - colony end cleanup, withdrawal chain, next steps, inspection takeover UI
- Colony end releases the queen in the same transaction; open suggestions become obsolete and a CLEANUP suggestion lists open tasks and the queen; apply-cleanup validates evidence and blocks reactivated colonies - Withdrawal chain: plausibility warnings on harvest and bottling, conflict notifications also when a treatment is entered or corrected after the harvest (naming bottled lots), withdrawal spans in the calendar and M365 sync, Berlin-day end events - Next 3 steps per colony and the "Heute" endpoint with ranking and an explicit merge table by intent - Inspection-triggered rule suggestions follow the colony's latest inspection (resolve when the finding is gone, refresh when it stays) - Frontend: colony card takeover in the inspection form, feed status as condition, occupied frames 0-40; legacy offline entries keep syncing - Notifications and preferences are deleted with their user Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
02eb16924e
commit
ef33e5549b
122 files changed
+10707
-504
No files matched your search
@@ -9,8 +9,9 @@ import { AuditLogService } from '../audit/audit-log.service';
|
||||
import { WebhooksService } from '../webhooks/webhooks.service';
|
||||
import { DomainEventsService } from '../domain-events/domain-events.service';
|
||||
import { utcDay } from '../domain-events/domain-event-types';
|
||||
import { assertTransactionClient } from '../prisma/db-client';
|
||||
import { lockRowForUpdate, lockRowsForUpdate } from '../prisma/row-lock';
|
||||
import { Queen, QueenStatus } from '../../generated/prisma';
|
||||
import { Prisma, Queen, QueenStatus } from '../../generated/prisma';
|
||||
import { CreateQueenDto } from './dto/create-queen.dto';
|
||||
import { UpdateQueenDto } from './dto/update-queen.dto';
|
||||
import { AssignColonyDto } from './dto/assign-colony.dto';
|
||||
@@ -155,6 +156,60 @@ export class QueensService {
|
||||
return queen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Differs from update(): this is the status alone, on the caller's
|
||||
* transaction, with the audit entry inside it. update() also lets go of
|
||||
* the colony that holds a queen who becomes unavailable (and audits after
|
||||
* its transaction); here that case is a 409, because the clean-up of an
|
||||
* ended colony must never unlink a colony she was re-assigned to.
|
||||
*
|
||||
* Sets the status of a queen on the caller's transaction: locks the queen,
|
||||
* reads it afterwards, audits the change. For a status that takes her out
|
||||
* of use it refuses while a colony still holds her (409) - the colony
|
||||
* side has to let go of her first (releaseQueenIn, assignColony); this
|
||||
* method never touches a colony. The same status again changes nothing.
|
||||
*/
|
||||
async updateStatusIn(
|
||||
tx: Prisma.TransactionClient,
|
||||
id: string,
|
||||
status: QueenStatus,
|
||||
actingUserId: string,
|
||||
): Promise<Queen> {
|
||||
assertTransactionClient(tx, 'QueensService.updateStatusIn');
|
||||
await lockRowForUpdate(tx, 'Queen', id);
|
||||
const before = await tx.queen.findUnique({ where: { id } });
|
||||
if (!before) {
|
||||
throw new NotFoundException('Queen not found');
|
||||
}
|
||||
if (before.status === status) {
|
||||
return before;
|
||||
}
|
||||
if (QUEEN_NO_LONGER_AVAILABLE_STATUSES.includes(status)) {
|
||||
const holder = await tx.colony.findUnique({
|
||||
where: { currentQueenId: id },
|
||||
select: { id: true },
|
||||
});
|
||||
if (holder) {
|
||||
throw new ConflictException(
|
||||
'Die Königin sitzt noch in einem Volk - bitte zuerst dort lösen',
|
||||
);
|
||||
}
|
||||
}
|
||||
const updated = await tx.queen.update({ where: { id }, data: { status } });
|
||||
await this.auditLog.record(
|
||||
{
|
||||
entityType: 'Queen',
|
||||
entityId: id,
|
||||
action: 'UPDATE',
|
||||
userId: actingUserId,
|
||||
beforeData: before,
|
||||
afterData: updated,
|
||||
},
|
||||
tx,
|
||||
);
|
||||
return updated;
|
||||
}
|
||||
|
||||
async assignColony(
|
||||
id: string,
|
||||
dto: AssignColonyDto,
|
||||
|
||||
Reference in new issue
Block a user