src/lib/dev-login-config.ts — startup assertion: throws if NODE_ENV=production + ENABLE_DEV_LOGIN=true, scoped to runtime (skipped during next build).
Container
scripts/migrate.mjs — runs Drizzle migrations against DATABASE_URL.
deploy/docker-entrypoint.sh — runs migrations then exec node server.js. Skip with RUN_MIGRATIONS=false.
Dockerfile — copies drizzle/, scripts/migrate.mjs, entrypoint into runner stage; ENTRYPOINT now points at the script.
Compose
deploy/compose.yaml — famapp now image: ${FAMAPP_IMAGE:-ghcr.io/ginnoir/famapp:latest} (build still works locally as fallback). Authentik pinned via AUTHENTIK_IMAGE_TAG (default 2024.12.3). New RUN_MIGRATIONS env passed through.
.env.production.example — documents FAMAPP_IMAGE, AUTHENTIK_IMAGE_TAG, RUN_MIGRATIONS.
CI/CD
.github/workflows/ci.yml — push/PR: typecheck + lint + format:check + build.
.github/workflows/release.yml — v* tag: build + push ghcr.io/ginnoir/famapp:vX.Y.Z, :X.Y, :latest to GHCR.
Docs
deploy/README.md — full deploy/rollback/release runbook.
CHANGELOG.md — release log seeded with an Unreleased entry.
docs/tasks/09-pre-deploy-checklist.md — task 09 reframed from one-shot removal to a recurring pre-deploy checklist.
STATUS.md — updated.
Verified: pnpm typecheck, pnpm format, pnpm build, and docker compose config all clean.
96 lines
2.1 KiB
HTML
96 lines
2.1 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<meta name="theme-color" content="#4F46E5" />
|
|
<title>famapp — offline</title>
|
|
<style>
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
box-sizing: border-box;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
:root {
|
|
--indigo: #4f46e5;
|
|
--indigo-light: #e0e7ff;
|
|
}
|
|
|
|
body {
|
|
font-family:
|
|
system-ui,
|
|
-apple-system,
|
|
sans-serif;
|
|
min-height: 100dvh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 1.25rem;
|
|
padding: 2rem;
|
|
background: #f9fafb;
|
|
color: #111827;
|
|
text-align: center;
|
|
}
|
|
|
|
.icon {
|
|
width: 72px;
|
|
height: 72px;
|
|
border-radius: 16px;
|
|
background: var(--indigo);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.icon svg {
|
|
width: 40px;
|
|
height: 40px;
|
|
}
|
|
|
|
h1 {
|
|
font-size: 1.25rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
p {
|
|
font-size: 0.9375rem;
|
|
color: #6b7280;
|
|
max-width: 28ch;
|
|
}
|
|
|
|
button {
|
|
margin-top: 0.5rem;
|
|
padding: 0.625rem 1.5rem;
|
|
background: var(--indigo);
|
|
color: white;
|
|
border: none;
|
|
border-radius: 0.5rem;
|
|
font-size: 0.9375rem;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
}
|
|
|
|
button:active {
|
|
opacity: 0.85;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="icon">
|
|
<!-- House silhouette -->
|
|
<svg viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<polygon points="20,5 34,17 31,17 31,35 9,35 9,17 6,17" fill="white" />
|
|
<rect x="15" y="22" width="10" height="13" rx="1" fill="#4F46E5" />
|
|
</svg>
|
|
</div>
|
|
|
|
<h1>You're offline</h1>
|
|
<p>famapp needs a connection — check your network and try again.</p>
|
|
<button onclick="location.reload()">Retry</button>
|
|
</body>
|
|
</html>
|