feat: Königinnen-Abstammungsbaum (Mutterlinie)
Neue Funktion jenseits der Lastenheft-Checkliste, explizit im Text als spätere Erweiterung angedacht (§4.4: "ApiCore SOLL später Abstammungsbäume darstellen können"). Königin.motherQueenId ist eine neue optionale Selbstreferenz (additive Migration), zusätzlich zu den bestehenden freien Textfeldern motherLine/fatherLine – letztere bleiben für Fälle, in denen die Mutter nicht selbst in ApiCore erfasst ist. Die Vaterlinie bleibt bewusst Freitext, da eine Königin mit vielen Drohnen aus unterschiedlichen Völkern begattet wird und es keine einzelne "Vater-Königin" gibt, die referenzierbar wäre. Backend: GET /queens/:id/lineage baut die mütterliche Ahnenkette (rekursiv über motherQueenId, Tiefe 8) sowie den Töchterbaum (rekursiv über die neue daughterQueens-Relation) in einer Antwort; create/update lehnen eine nicht existierende oder auf sich selbst zeigende motherQueenId ab. Frontend: neue "Abstammungsbaum"-Karte auf der Königin-Detailseite zeigt die mütterliche Linie als Liste sowie die Töchter als eingerückten Baum, beide mit Links zu den jeweiligen Königinnen. Anlage- und Bearbeiten-Formular bekommen ein "Mutter"-Auswahlfeld (Bearbeiten schließt die Königin selbst aus der Liste aus). Live in Chrome verifiziert: dreistufige Kette (Großmutter → Mutter → Tochter) korrekt in beide Richtungen dargestellt; dabei einen echten Anzeigefehler gefunden und behoben – das Mutter-Auswahlfeld zeigte nach dem Speichern die rohe Datenbank-ID statt des Königin-Codes an (derselbe SelectValue-ohne-children-Fehler wie zuvor bei der Import-Entitätsauswahl).
This commit is contained in:
1 parent
68f459001a
commit
e458a7cf07
14 files changed
+475
-10
No files matched your search
@@ -21,6 +21,7 @@ describe('Queens (e2e)', () => {
|
||||
let apiaryId: string;
|
||||
let colonyId: string;
|
||||
let queenId: string;
|
||||
let daughterQueenId: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
app = await createTestApp();
|
||||
@@ -63,6 +64,9 @@ describe('Queens (e2e)', () => {
|
||||
data: { currentQueenId: null },
|
||||
});
|
||||
}
|
||||
if (daughterQueenId) {
|
||||
await prisma.queen.delete({ where: { id: daughterQueenId } });
|
||||
}
|
||||
if (queenId) {
|
||||
await prisma.queen.delete({ where: { id: queenId } });
|
||||
}
|
||||
@@ -130,4 +134,53 @@ describe('Queens (e2e)', () => {
|
||||
expect(evaluations).toHaveLength(1);
|
||||
expect(evaluations[0]?.colonyStrength).toBe(4);
|
||||
});
|
||||
|
||||
it('rejects creating a queen with a motherQueenId that does not exist', () => {
|
||||
return request(app.getHttpServer())
|
||||
.post('/api/v1/queens')
|
||||
.set('Authorization', `Bearer ${beekeeperToken}`)
|
||||
.send({ code: `Q-orphan-${Date.now()}`, motherQueenId: 'does-not-exist' })
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it('rejects a queen set as her own mother', () => {
|
||||
return request(app.getHttpServer())
|
||||
.patch(`/api/v1/queens/${queenId}`)
|
||||
.set('Authorization', `Bearer ${beekeeperToken}`)
|
||||
.send({ motherQueenId: queenId })
|
||||
.expect(400);
|
||||
});
|
||||
|
||||
it('creates a daughter queen and returns the ancestor/descendant lineage', async () => {
|
||||
const daughterResponse = await request(app.getHttpServer())
|
||||
.post('/api/v1/queens')
|
||||
.set('Authorization', `Bearer ${beekeeperToken}`)
|
||||
.send({ code: `Q-daughter-${Date.now()}`, motherQueenId: queenId })
|
||||
.expect(201);
|
||||
daughterQueenId = (daughterResponse.body as QueenBody).id;
|
||||
|
||||
const motherLineage = await request(app.getHttpServer())
|
||||
.get(`/api/v1/queens/${queenId}/lineage`)
|
||||
.set('Authorization', `Bearer ${beekeeperToken}`)
|
||||
.expect(200);
|
||||
const motherBody = motherLineage.body as {
|
||||
queen: { id: string; mother: unknown };
|
||||
descendants: { id: string }[];
|
||||
};
|
||||
expect(motherBody.queen.id).toBe(queenId);
|
||||
expect(motherBody.queen.mother).toBeNull();
|
||||
expect(motherBody.descendants).toHaveLength(1);
|
||||
expect(motherBody.descendants[0]?.id).toBe(daughterQueenId);
|
||||
|
||||
const daughterLineage = await request(app.getHttpServer())
|
||||
.get(`/api/v1/queens/${daughterQueenId}/lineage`)
|
||||
.set('Authorization', `Bearer ${beekeeperToken}`)
|
||||
.expect(200);
|
||||
const daughterBody = daughterLineage.body as {
|
||||
queen: { id: string; mother: { id: string } | null };
|
||||
descendants: unknown[];
|
||||
};
|
||||
expect(daughterBody.queen.mother?.id).toBe(queenId);
|
||||
expect(daughterBody.descendants).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user