Feature: Zeit-pro-Projekt-Auswertung im Projekt-Detail

time_entry erfasst bezugKind='project'+bezugId, aber niemand sah je, wie viel
Zeit ein Projekt frisst. Neue Query time.byProject (Gesamtsumme + pro Person);
neue "Getrackte Zeit"-Sektion im Projekt-Detail (blendet sich aus, wenn nichts
getrackt wurde).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Raffael SheikhandClaude Opus 4.8 committed 2026-06-07 12:15:05 +02:00
1 parent 2eef94afce
commit 7dd1f2fb20
2 files changed
+68

No files matched your search

+34
View File
@@ -420,4 +420,38 @@ export const timeRouter = router({
return { date, lanes };
}),
/**
* Getrackte Zeit auf ein Projekt (time_entry mit bezugKind='project'):
* Gesamtsumme + Aufschlüsselung pro Person. bezugId wurde bislang erfasst,
* aber nirgends ausgewertet — das speist die „Getrackte Zeit"-Sektion im
* Projekt-Detail.
*/
byProject: protectedProcedure
.input(z.object({ projectId: z.string().uuid() }))
.query(async ({ ctx, input }) => {
const rows = await ctx.db
.select({
userId: timeEntry.userId,
seconds: sql<number>`COALESCE(SUM(${timeEntry.durationSeconds}), 0)`,
})
.from(timeEntry)
.where(and(eq(timeEntry.bezugKind, 'project'), eq(timeEntry.bezugId, input.projectId)))
.groupBy(timeEntry.userId);
const userRows = await ctx.db.select({ id: user.id, name: user.name }).from(user);
const nameById = new Map(userRows.map((u) => [u.id, u.name]));
const perUser = rows
.map((r) => ({
userId: r.userId,
name: nameById.get(r.userId) ?? '—',
seconds: Number(r.seconds),
}))
.filter((r) => r.seconds > 0)
.sort((a, b) => b.seconds - a.seconds);
const totalSeconds = perUser.reduce((sum, r) => sum + r.seconds, 0);
return { totalSeconds, perUser };
}),
});