From 4eed701419e28a65b7a7dc05483a77cb6c9c0f04 Mon Sep 17 00:00:00 2001 From: lilleman Date: Sun, 14 Jun 2026 11:45:30 +0200 Subject: [PATCH] Scaffold Docker-only Node 24 + TypeScript EJS web backend --- .dockerignore | 6 + .gitignore | 4 + .npmrc | 2 + AGENTS.md | 38 ++ Dockerfile | 16 + README.md | 66 +++ compose.override.yml | 10 + compose.yml | 10 + html-css-foundation/App Shell.html | 735 +++++++++++++++++++++++++++++ html-css-foundation/Auth.html | 216 +++++++++ html-css-foundation/auth.css | 232 +++++++++ html-css-foundation/styles.css | 639 +++++++++++++++++++++++++ package-lock.json | 141 ++++++ package.json | 23 + public/css/style.css | 75 +++ public/favicon.svg | 4 + public/robots.txt | 2 + src/app.test.ts | 43 ++ src/app.ts | 49 ++ src/server.ts | 7 + src/static.ts | 55 +++ tsconfig.json | 28 ++ views/404.ejs | 16 + views/index.ejs | 20 + views/partials/header.ejs | 6 + 25 files changed, 2443 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 AGENTS.md create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 compose.override.yml create mode 100644 compose.yml create mode 100644 html-css-foundation/App Shell.html create mode 100644 html-css-foundation/Auth.html create mode 100644 html-css-foundation/auth.css create mode 100644 html-css-foundation/styles.css create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/css/style.css create mode 100644 public/favicon.svg create mode 100644 public/robots.txt create mode 100644 src/app.test.ts create mode 100644 src/app.ts create mode 100644 src/server.ts create mode 100644 src/static.ts create mode 100644 tsconfig.json create mode 100644 views/404.ejs create mode 100644 views/index.ejs create mode 100644 views/partials/header.ejs diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3a7b2df --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +.git +node_modules +npm-debug.log +*.log +.DS_Store +html-css-foundation diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5742681 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.claude +.DS_Store +*.log +node_modules diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..0410e11 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +; Pin exact versions on install — `npm install ` saves "1.2.3", not "^1.2.3". +save-exact=true diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..784e6ad --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,38 @@ +# AGENTS.md + +Guidance for AI agents and contributors working in this repo. Read `README.md` for +commands and layout. + +## Project priorities (do not erode) + +1. **Simplicity** — prefer the smallest, most readable solution. +2. **Few dependencies** — the only runtime dep is `ejs`. Prefer the Node standard + library. Justify any new dependency; do not add frameworks. +3. **Strict TypeScript** — `tsconfig.json` is strict (incl. `noUncheckedIndexedAccess`, + `exactOptionalPropertyTypes`, `verbatimModuleSyntax`). Keep it that way. + +## Docker only — no host tooling + +**Everything** (install, typecheck, test, run, build, deploy) goes through Docker / +Docker Compose. **Never run `node`, `npm`, or `tsc` on the host.** + +```bash +docker compose up # dev server, live reload +docker compose run --rm web npm run typecheck # strict type check +docker compose run --rm web npm test # tests +docker compose -f docker-compose.yml up --build -d # production +``` + +## Rules + +- Node 24 runs `.ts` directly (type stripping). Keep all TypeScript **erasable** + (`erasableSyntaxOnly` is on): no `enum`, `namespace`, parameter properties, or + decorators. Import local modules with their `.ts` extension. +- **No build step** and no compiled artifacts — do not add a bundler or `tsc` emit. +- Before finishing a change, run the typecheck and tests above; both must pass. +- Tests use the built-in `node --test` runner — no test framework dependency. +- English everywhere. Keep code comments short and information-dense. +- Pin all dependencies and Docker images to exact, human-readable **semantic + versions** — never ranges (`^`, `~`) and never digests/hashes. npm deps are kept + exact by `.npmrc` (`save-exact=true`) + `npm ci`; the base image by tag (e.g. + `node:24.16.0-alpine3.24`). diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..569ff00 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +# Node 24 runs TypeScript directly (type stripping) — no build step. +# Pinned to an exact, human-readable version (node / alpine). +FROM node:24.16.0-alpine3.24 + +WORKDIR /app + +# Reproducible install from the committed lockfile. Dev deps (typescript, types) +# are kept so `npm run typecheck` / `npm test` work in the same image. +COPY package.json package-lock.json .npmrc ./ +RUN npm ci + +COPY . . + +ENV PORT=3000 +EXPOSE 3000 +CMD ["node", "src/server.ts"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..3b4249a --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +# Plainpages + +A minimal **Node.js 24 + TypeScript** web backend that serves server-rendered HTML +(via **EJS** templates), CSS, and static files. + +Priorities: **simplicity, few dependencies, strict TypeScript type checking.** +Development and deployment are **entirely Docker / Docker Compose based — no other +tooling is required** (no local Node, npm, or `tsc`). + +The only runtime dependency is `ejs`. Node 24 runs the TypeScript sources directly +(type stripping), so there is **no build step** and no compiled output. + +## Requirements + +- Docker +- Docker Compose + +That's it. Do not install or run Node/npm on the host — use the commands below. + +## Development + +```bash +docker compose up # http://localhost:3000, live reload via `node --watch` +``` + +`docker compose up` merges `compose.override.yml`, which mounts the source +and restarts the server on change. + +## Type check & tests + +```bash +docker compose run --rm web npm run typecheck # strict tsc --noEmit +docker compose run --rm web npm test # node --test +``` + +## Production / deployment + +```bash +docker compose -f compose.yml up --build -d # base config only, no source mount +``` + +## Layout + +``` +src/server.ts Entry point — starts the HTTP server (reads PORT, default 3000) +src/app.ts Request routing + EJS rendering +src/static.ts Static file serving with path-traversal protection +views/ EJS templates (index, 404, partials/) +public/ Static assets served under /public/ (css/, favicon, robots.txt) +``` + +## Extending + +- **New page:** add a route in `src/app.ts` and a template in `views/`. +- **Static asset:** drop it in `public/`; it is served at `/public/`. +- **New dependency:** `docker compose run --rm web npm install ` (updates + `package.json` + `package-lock.json`), then rebuild with `docker compose build`. + Keep dependencies minimal — prefer the Node standard library. + +All versions are pinned to **exact, human-readable semantic versions** (no ranges, +no digests): deps via `.npmrc` (`save-exact=true`) and the committed lockfile +(`npm ci`), and the Node base image by tag in the `Dockerfile` +(e.g. `node:24.16.0-alpine3.24`). + +`html-css-foundation/` holds the raw HTML/CSS design reference; it is not served and +is meant to be converted into EJS templates and `public/` assets over time. diff --git a/compose.override.yml b/compose.override.yml new file mode 100644 index 0000000..8bc9788 --- /dev/null +++ b/compose.override.yml @@ -0,0 +1,10 @@ +# Development overrides, merged automatically by `docker compose up`. +# Mounts the source for live editing and restarts on change via `node --watch`. +services: + web: + command: node --watch src/server.ts + environment: + NODE_ENV: development + volumes: + - .:/app + - /app/node_modules diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..576abb9 --- /dev/null +++ b/compose.yml @@ -0,0 +1,10 @@ +# Base / production config. Run alone with: docker compose -f docker-compose.yml up +# Plain `docker compose up` also merges docker-compose.override.yml for development. +services: + web: + build: . + ports: + - "3000:3000" + environment: + NODE_ENV: production + restart: unless-stopped diff --git a/html-css-foundation/App Shell.html b/html-css-foundation/App Shell.html new file mode 100644 index 0000000..03797d2 --- /dev/null +++ b/html-css-foundation/App Shell.html @@ -0,0 +1,735 @@ + + + + + +App Shell — Template + + + + + + + + + + +
+ + + + + + + + +
+ + +
+ +
+
People
+
+ +
+ + +
+ + +
+ +
+ + +
+ Status +
+ + + +
+
+ + + + + + + + +
+ + + + + +
+ + +
+
+ Tags + +
+ + + + + +
+
+ +
+ +
+ Joined + +
+ + + + + + +
+
+
+ + +
+
+ Applied + Team: Engineering + Tag: On-call + Joined: 2026 + Clear all +
+ +
+ +
+ + +
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
People in the directory
+ + + + + + + + TeamStatus + + Actions
Mara Delgado[email protected]AdminEngineeringActive2 min ago + +
Soren Vance[email protected]MemberDesignIdle3 hours ago + +
Priya Nair[email protected]AdminOperationsActivejust now + +
Eli Brandt[email protected]ViewerSalesSuspended6 days ago + +
Tomas Lindqvist[email protected]MemberEngineeringInvited + +
Hana Osei[email protected]MemberDesignActive21 min ago + +
Rafael Costa[email protected]AdminOperationsIdle1 hour ago + +
Wen Li[email protected]ViewerSalesActive44 min ago + +
Nadia Farouk[email protected]MemberEngineeringSuspended12 days ago + +
Otto Berg[email protected]MemberDesignInvited + +
Greta Holm[email protected]AdminOperationsActive8 min ago + +
Yusuf Demir[email protected]ViewerSalesIdle5 hours ago + +
+
+ + +
+ 1–12 of 1,284 +
+ +
+ +
+
+
+ +
+ +
+
+ + + diff --git a/html-css-foundation/Auth.html b/html-css-foundation/Auth.html new file mode 100644 index 0000000..f4c96a9 --- /dev/null +++ b/html-css-foundation/Auth.html @@ -0,0 +1,216 @@ + + + + + +Sign in — Console + + + + + + + + +
+
+ +
+ + Console +
+ + +
+
+
+

Sign in

+

Welcome back. Enter your details to continue.

+
+ + +
+
    + +
  • +
  • +
  • +
+
or
+
+ +
+
+ +
+ + +
+
+ +
+
+ + Forgot password? +
+
+ + +
+
+ + + + +
+ +

Don't have an account? Create one

+
+
+ + +
+
+
+

Create account

+

Get started — it only takes a minute.

+
+ +
+
    +
  • +
  • +
  • +
+
or
+
+ +
+ +
+
+ + Optional +
+
+ + +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ + +
+ Use 8 or more characters. + +
+ + +
+ +

Already have an account? Sign in

+
+
+ + +
+
+
+ Back to sign in +

Reset password

+

Enter your email and we'll send you a reset link.

+
+ + +
+ +
Check your emailIf an account exists for that address, a reset link is on its way.
+
+ + +
+
+ +
+ + +
+
+ + +
+ +

Remembered it? Sign in

+
+
+ +
+
+ + +
+ Preview +
+ + + +
+ + + +
+
+ + + +
+
+ +
+
+ + + +
+
+
+ + + diff --git a/html-css-foundation/auth.css b/html-css-foundation/auth.css new file mode 100644 index 0000000..3805c1f --- /dev/null +++ b/html-css-foundation/auth.css @@ -0,0 +1,232 @@ +/* ============================================================= + Auth flow — login / register / forgot password + Built on the shared tokens in styles.css. Pure HTML/CSS: + - screens switch via :target (no JS) + - SSO is a config section toggled by a class/checkbox; providers + are a