Initial commit: everythingbutwork MVP
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:
commit
4f33509a0f
131 files changed
+34339
No files matched your search
@@ -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',
|
||||
};
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user