6e2d794130
- @app/storage med MockStorage + AwsStorage delas mellan API och worker - Workerns readUrl() ger presignerad S3-URL i aws-läge (fixar mock-s3 404) - sync-env-from-ssm.py hämtar /cibello/prod/* och skriver .env; first-deploy.sh kör det i prod - /readyz returnerar 503 om app.aamos.healthCheck() misslyckas - docs/SECRETS.md med rotations- och SSM-regler
45 lines
2.0 KiB
TypeScript
45 lines
2.0 KiB
TypeScript
import type { FastifyInstance } from "fastify";
|
|
import { sql } from "drizzle-orm";
|
|
import { BRAND } from "@app/shared-types";
|
|
|
|
/** Liveness/readiness för lastbalanserare och Docker healthchecks (spec §58). */
|
|
export async function healthRoutes(app: FastifyInstance) {
|
|
app.get("/healthz", { config: { rateLimit: false } }, async () => ({
|
|
ok: true,
|
|
service: `${BRAND.slug}-api`,
|
|
timestamp: new Date().toISOString(),
|
|
}));
|
|
|
|
app.get("/readyz", { config: { rateLimit: false } }, async (_req, reply) => {
|
|
try {
|
|
await app.db.execute(sql`SELECT 1`);
|
|
} catch {
|
|
return reply.status(503).send({ ok: false, reason: "database" });
|
|
}
|
|
const aamosHealth = await app.aamos.healthCheck();
|
|
if (!aamosHealth.ok) {
|
|
return reply.status(503).send({ ok: false, reason: "aamos", detail: aamosHealth.detail });
|
|
}
|
|
return { ok: true };
|
|
});
|
|
|
|
/** Enkel endpointöversikt i stället för tung OpenAPI-generering (se beslutslogg D-011). */
|
|
app.get("/docs", { config: { rateLimit: false } }, async (_req, reply) => {
|
|
const routes = app.routeCatalog
|
|
.filter((r) => !r.url.startsWith("/v1/mock-s3"))
|
|
.sort((a, b) => a.url.localeCompare(b.url) || a.method.localeCompare(b.method));
|
|
const rows = routes
|
|
.map((r) => `<tr><td><code>${r.method}</code></td><td><code>${r.url}</code></td></tr>`)
|
|
.join("\n");
|
|
reply.header("content-type", "text/html; charset=utf-8");
|
|
return `<!doctype html><html lang="sv"><head><meta charset="utf-8"><title>API</title>
|
|
<style>body{font-family:system-ui;margin:2rem auto;max-width:820px;color:#1a202c;padding:0 1rem}
|
|
table{border-collapse:collapse;width:100%}td{padding:.35rem .75rem;border-bottom:1px solid #e2e8f0}
|
|
code{background:#f7fafc;padding:.1rem .3rem;border-radius:4px}</style></head>
|
|
<body><h1>${BRAND.name} API v1</h1>
|
|
<p>${routes.length} endpoints. Auth: <code>Authorization: Bearer <accessToken></code>.
|
|
Fullständig referens: <code>docs/api-referens.md</code> i repot.</p>
|
|
<table>${rows}</table></body></html>`;
|
|
});
|
|
}
|