Initial commit: everythingbutwork MVP
ci / quality (push) Has been cancelled
ci / build (push) Has been cancelled

Internes Project-Management-Tool für ToolCTRL — ergänzend zu Plane (Tickets)
und Outline (Doku). Umfasst Puls-Übersicht, Tagesrhythmus (Lock-in + Reflexion),
Bereichs-Detail-Views (Entwicklung/Vertrieb/Marketing), Pflicht-Minimum-Check
und Blocker-Lifecycle gemäß Projektmanagement-Leitfaden v3.0.

Stack: pnpm-Monorepo · Vite + React 18 + Tailwind · Fastify + tRPC v11 +
Drizzle ORM · Postgres 16 · Authentik OIDC (Phase 2, Dev-Auto-Login aktiv).

Planungs-Artefakte unter _bmad-output/planning-artifacts/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
dejanandClaude Opus 4.7 committed 2026-05-25 22:47:26 +02:00
commit 4f33509a0f
131 files changed
+34339

No files matched your search

+77
View File
@@ -0,0 +1,77 @@
import type { FastifyInstance, FastifyRequest } from 'fastify';
import { loadEnv } from '../env.js';
import { logger } from '../lib/logger.js';
import { getDb } from '../db.js';
import { publishYesterdaysEntries } from '../routers/day-entry.js';
import { previousWerktag, todayIso } from '../lib/werktag.js';
function authorize(req: FastifyRequest): void {
const env = loadEnv();
const header = req.headers.authorization ?? '';
const expected = `Bearer ${env.CRON_BEARER_TOKEN}`;
if (header !== expected) {
throw new Error('Unauthorized cron call.');
}
}
export async function registerCronRoutes(app: FastifyInstance): Promise<void> {
app.post('/internal/cron/publish-day-entries', async (req, reply) => {
try {
authorize(req);
} catch (err) {
reply.code(401);
logger.warn({ err }, 'unauthorized cron call');
return { error: 'unauthorized' };
}
const { db } = getDb();
const today = todayIso();
const yesterday = previousWerktag(today);
const updated = await publishYesterdaysEntries({ db }, yesterday);
logger.info({ updated, date: yesterday }, 'published yesterday entries');
return { ok: true, updated, date: yesterday };
});
app.post('/internal/cron/recompute-streaks', async (req, reply) => {
try {
authorize(req);
} catch {
reply.code(401);
return { error: 'unauthorized' };
}
// Streaks werden lazy in `user.me` berechnet. Dieser Endpoint ist Reserve
// für künftige denormalisierte Caches (NFR-1 Performance, sobald viele User).
return { ok: true, note: 'streaks are computed lazily' };
});
app.post('/internal/cron/recompute-pflicht-minimum-5', async (req, reply) => {
try {
authorize(req);
} catch {
reply.code(401);
return { error: 'unauthorized' };
}
const { db } = getDb();
const { recomputePflichtMinimumStatusActual } = await import('../lib/pflicht-minimum.js');
const res = await recomputePflichtMinimumStatusActual(db);
logger.info(res, 'pflicht-minimum status_aktuell recomputed');
return { ok: true, ...res };
});
app.post('/internal/cron/pg-dump-backup', async (req, reply) => {
try {
authorize(req);
} catch {
reply.code(401);
return { error: 'unauthorized' };
}
// pg_dump läuft als System-Cron *im Postgres-Container* (siehe
// docs/operations.md § Backups). Dieser Endpoint ist der Audit-Trigger:
// wenn er gerufen wird, ist der Backup-Cron lebendig und der Logeintrag
// landet im API-Log (zentrale Beobachtbarkeit).
logger.info('pg-dump-backup heartbeat received');
return {
ok: true,
note: 'pg_dump runs in postgres container; see docs/operations.md',
};
});
}