diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d1ad690 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +node_modules +.next +data/*.db +test-results +*.tsbuildinfo +.git +.env +.codenomad +# e2e harness: @playwright/test is a host-global install, not a project dependency +e2e +playwright.config.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index bc925da..dcd6838 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v0.2.0 — 2026-09-16 18:32 +- Docker deployment: multi-stage `Dockerfile` (node:22-alpine; deps → build → runtime) running `next start` on port 3000; no `output: 'standalone'` — the runtime stage keeps full `node_modules` because `/api/mlworker/[file]` reads maplibre-gl dist files from disk at runtime (and `/api/airports` reads `data/*.csv`) +- `.dockerignore`: node_modules, .next, data/*.db, test-results, *.tsbuildinfo, plus .git/.env/.codenomad and the e2e harness (`@playwright/test` is a host-global install, not a project dependency — Next's build-time type check would fail on it inside the image) +- `docker-compose.yml`: single service `flight`, no published ports, joins external network `dev_net` with Traefik labels routing `Host(flight.dev.kkhost.pl)` → port 3000 (plain HTTP entrypoint `web`; TLS terminated upstream) +- Verified: container builds and runs; router registered in dev_traefik rawdata; `curl -H "Host: flight.dev.kkhost.pl" http://localhost/` → 200, `/api/airports` → 200 GeoJSON (7445 features), mlworker .mjs files served from node_modules inside the container; unit suite 12/12 and e2e suite 2/2 still green + ## v0.1.0 — 2026-09-16 18:24 - Scaffolded Next.js (App Router) + TypeScript project; dev server on port 3000 (`npm run dev`) - Full-viewport MapLibre GL map with OpenFreeMap "liberty" vector basemap (attribution included via style) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..48f0149 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +FROM node:22-alpine AS deps +WORKDIR /app +COPY package.json package-lock.json ./ +RUN npm ci + +FROM node:22-alpine AS build +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . +ENV NEXT_TELEMETRY_DISABLED=1 +RUN npm run build + +# No `output: 'standalone'`: the runtime stage keeps the full node_modules because +# /api/mlworker/[file] reads maplibre-gl dist files from disk at runtime, and +# /api/airports reads data/*.csv — both resolved relative to process.cwd(). +FROM node:22-alpine AS runtime +WORKDIR /app +ENV NODE_ENV=production NEXT_TELEMETRY_DISABLED=1 +COPY --from=build /app ./ +EXPOSE 3000 +CMD ["npm", "run", "start"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f8e80cd --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +services: + flight: + build: . + networks: + - dev_net + labels: + - "traefik.enable=true" + - "traefik.http.routers.flight.rule=Host(`flight.dev.kkhost.pl`)" + - "traefik.http.routers.flight.entrypoints=web" + - "traefik.http.services.flight.loadbalancer.server.port=3000" + +networks: + dev_net: + external: true diff --git a/package.json b/package.json index 68fe7c8..a79fd23 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flight-ops", - "version": "0.1.0", + "version": "0.2.0", "private": true, "scripts": { "dev": "next dev -p 3000",