- TypeScript 59.9%
- JavaScript 39.5%
- CSS 0.4%
- Dockerfile 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
Some checks failed
CI / ci (push) Has been cancelled
Moves the pinned ops pointer to include puzzles 40 and 41 and the add-an-output-renderer runbook update; all three are on the ops remote. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
| .forgejo | ||
| brand/stickers | ||
| ops@489c249110 | ||
| scripts | ||
| workspaces | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| .gitmodules | ||
| AGENTS.md | ||
| biome.json | ||
| CLAUDE.md | ||
| docker-compose.yml | ||
| LICENSE | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
dailyprog
A daily coding-challenge app. This is a pnpm monorepo housing the web app and its shared UI component library.
Stack
- pnpm workspaces (run via corepack)
- Next.js 16 (App Router, Turbopack) — the app
- Storybook 10 (Vite builder) — UI library development
- React 19 + Tailwind CSS v4
- next-intl for app internationalization (locale routing + message catalogs)
- Biome for linting and formatting
Layout
dailyprog/
├── workspaces/
│ ├── ui/ → @dailyprog/ui shared React component library (Storybook)
│ └── app/ → @dailyprog/app Next.js app, consumes @dailyprog/ui
├── biome.json # lint + format config
├── pnpm-workspace.yaml # workspaces, pinned Node, build allowlist
└── AGENTS.md # contributor/agent guide (conventions, commit rules)
@dailyprog/app depends on @dailyprog/ui via workspace:* and compiles its TypeScript
source directly (transpilePackages).
Prerequisites
- Node (the exact version is pinned in
pnpm-workspace.yamlviauseNodeVersion; pnpm manages it for you). - pnpm through corepack — no global install needed. Either prefix commands with
corepack pnpm …, or runcorepack enableonce to get a barepnpmon your PATH.
Getting started
corepack pnpm install
Common commands
Run from the repo root:
| Task | Command |
|---|---|
| Install dependencies | corepack pnpm install |
| Lint + format (write) | corepack pnpm check |
| Run all tests | corepack pnpm test |
| Build all workspaces | corepack pnpm build |
| Run the app (dev) | corepack pnpm --filter @dailyprog/app dev |
| Build the app | corepack pnpm --filter @dailyprog/app build |
| Develop UI in Storybook | corepack pnpm --filter @dailyprog/ui storybook |
| Build Storybook | corepack pnpm --filter @dailyprog/ui build-storybook |
The app dev server runs at http://localhost:3000; Storybook at http://localhost:6006.
Docker
A docker-compose.yml runs the production app (web) on its own — it's
stateless. The app image is a multi-stage build of Next's standalone output, on a Debian base
so the native isolated-vm addon compiles.
cp .env.example .env # the app has no secrets of its own
docker compose up -d --build
The app serves on http://localhost:3000 (liveness at /api/health). To enable analytics, bring
up Umami (a separate stack — see the ops submodule's infra/umami/), create a website in its UI,
put its script URL + id in NEXT_PUBLIC_UMAMI_SRC / NEXT_PUBLIC_UMAMI_WEBSITE_ID, then rebuild
the app (docker compose build web) — these are inlined at build time. With them empty, the
tracker is disabled.
The web image targets linux/arm64 by default — the deploy VPS is arm64 (netcup; see the ops
submodule) and the isolated-vm prebuild is arch-specific. Set WEB_PLATFORM=linux/amd64 for
an x86 target. The web container is hardened (read-only rootfs + tmpfs, all caps dropped,
no-new-privileges, memory/CPU/pid limits — tunable via WEB_* in .env).
The full deploy runbook and live VPS documentation live in the ops submodule (ops/DEPLOY.md,
ops/infra/README.md) — private operational content, available to maintainers only.
Running with Podman
The stack is Podman-compatible (image names are fully qualified, e.g.
docker.io/library/postgres). A few differences from Docker:
- Use
podman compose(Podman 4.1+, which drives Docker Compose v2 over the Podman socket), not the older Pythonpodman-compose— the latter is unreliable withdepends_on: condition: service_healthygates (e.g. the Umami → Postgres ordering in the ops submodule'sinfra/umami/). - Resource limits need cgroups v2.
mem_limit/cpus/pids_limitare silently ignored under rootless Podman unless controller delegation is configured; run rootful or set up delegation if you need them enforced. The other hardening (read_only,cap_drop,no-new-privileges, tmpfs) works rootless. - Build cache mounts (
--mount=type=cachein the Dockerfile) need a recent Podman/Buildah; on older versions, drop that flag. - Autostart: prefer Quadlet (
.containerunits) orpodman generate systemdover the composerestart:policy for a real server.
Testing
Tests run on Vitest for unit and component layers, and Playwright for end-to-end browser flows. Three layers are set up:
- Unit tests for pure logic in
@dailyprog/app(lib/), in a Node environment. - Component tests for
@dailyprog/uiand@dailyprog/appusing React Testing Library in jsdom. - E2E tests in
@dailyprog/app(e2e/) — real Chromium + WebKit against a production build, exercising the isolated-vm verify path, the CodeMirror editor, and the Web Worker runner.
Run everything with corepack pnpm test, E2E with
corepack pnpm --filter @dailyprog/app test:e2e. See AGENTS.md for
conventions.
Conventions
Code style is enforced by Biome (corepack pnpm check before every change). Styling uses
Tailwind utilities — avoid inline CSS. Icons come from Heroicons (@heroicons/react), not
hand-written SVG. Versions shared across workspaces are centralized in the pnpm catalog:
(pnpm-workspace.yaml) and referenced as "catalog:" in each package. Commits follow
Conventional Commits without a scope. User-facing strings in @dailyprog/ui are passed in as
props with English defaults so the app — which owns i18n via next-intl — can localize them, and
the monospace font (IBM Plex Mono) is reserved for numbers, tags, and identifiers. See
AGENTS.md for the full contributor guide.
Ops submodule
The puzzle catalogue, architecture decision records, infrastructure documentation, and the
deploy runbook live in a private ops repo set up as a git submodule at ops/. The app's
predev/prebuild/pretest scripts run scripts/sync-ops.mjs to copy them into place.
- Maintainers — run
git submodule update --initto pull the ops repo, then build as usual. - Contributors — the sync script falls back to sample puzzles under
workspaces/app/content/sample-puzzles/. The app boots and tests pass without ops access.
License
GNU Affero General Public License v3.0
Copyright (C) 2026 lvmbdv