feat(dev): add compose files and dev-login bypass route

- compose.prod.yml: production stack with registry image, healthcheck,
  migration service
- compose.test.yml: local test stack with source mount and LOCAL=true
- routes/dev-login.ts: fake admin JWT login, only active when LOCAL=true
- routes/_middleware.ts: expose /dev-login as public route

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-26 23:01:59 +02:00
parent 5ba8b8cb68
commit fcc9547a30
4 changed files with 134 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
services:
db:
image: postgres:17-alpine
restart: unless-stopped
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASS}
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_DB: ${POSTGRES_DB:-polympr}
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"]
interval: 5s
timeout: 5s
retries: 10
migrate:
image: registry.docker.polytech.djalim.fr/polympr:latest
command: node_modules/.bin/drizzle-kit migrate
env_file: .env
depends_on:
db:
condition: service_healthy
app:
image: registry.docker.polytech.djalim.fr/polympr:latest
restart: unless-stopped
ports:
- "4430:443"
env_file: .env
depends_on:
migrate:
condition: service_completed_successfully
volumes:
db_data:
+49
View File
@@ -0,0 +1,49 @@
services:
db:
image: postgres:17-alpine
restart: unless-stopped
environment:
POSTGRES_PASSWORD: testpass
POSTGRES_USER: postgres
POSTGRES_DB: polympr_test
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 10
migrate:
image: denoland/deno:alpine
working_dir: /app
volumes:
- .:/app
command: task migrate
environment:
POSTGRES_HOST: db
POSTGRES_PORT: 5432
POSTGRES_USER: postgres
POSTGRES_PASS: testpass
POSTGRES_DB: polympr_test
LOCAL: "true"
depends_on:
db:
condition: service_healthy
app:
image: denoland/deno:alpine
working_dir: /app
volumes:
- .:/app
command: run -A --unstable-ffi main.ts
ports:
- "4430:443"
environment:
POSTGRES_HOST: db
POSTGRES_PORT: 5432
POSTGRES_USER: postgres
POSTGRES_PASS: testpass
POSTGRES_DB: polympr_test
LOCAL: "true"
depends_on:
migrate:
condition: service_completed_successfully
+1
View File
@@ -10,6 +10,7 @@ const PUBLIC_ROUTES = [
"/about",
"/partials/about",
"/contact",
"/dev-login",
];
const jwtKeyCache: Record<string, string> = {};
+48
View File
@@ -0,0 +1,48 @@
import { FreshContext, Handlers } from "$fresh/server.ts";
import { CasContent, LoginJWT, State } from "$root/defaults/interfaces.ts";
import { createJwt } from "@popov/jwt";
import { setCookie } from "$std/http/cookie.ts";
import { getKey } from "$root/routes/_middleware.ts";
const FAKE_ADMIN: CasContent = {
amuCampus: "local",
amuComposante: "local",
amuDateValidation: "",
coGroup: "",
eduPersonPrimaryAffiliation: "employee",
eduPersonPrincipalName: "admin@local",
mail: "admin@local",
displayName: "Admin Local",
givenName: "Admin",
memberOf: [],
sn: "Local",
supannCivilite: "",
supannEntiteAffectation: "",
supannEtuAnneeInscription: "",
supannEtuEtape: "",
uid: "admin-local",
};
export const handler: Handlers<null, State> = {
async GET(_request: Request, _context: FreshContext<State, null>) {
if (Deno.env.get("LOCAL") !== "true") {
return new Response("Not available outside LOCAL mode.", { status: 403 });
}
const now = Math.floor(Date.now() / 1000);
const payload: LoginJWT = {
iss: "PolyMPR",
iat: now,
exp: now + 0xe10,
aud: "PolyMPR",
user: FAKE_ADMIN,
};
const token = await createJwt(payload, getKey(FAKE_ADMIN.uid));
const headers = new Headers();
setCookie(headers, { name: "sessionToken", value: token });
headers.set("Location", "/apps");
return new Response(null, { status: 302, headers });
},
};