The compose deploy was unreachable because frontend code reads its
API base from `import.meta.env.VITE_API_BASE` at build time, but the
shipped image baked in the fallback `/api` and never picked up the
`PUBLIC_API_BASE` env var. The browser then hit
http://localhost:3000/api/...which the Node adapter doesn't serve, so
every request 404'd.
Fix the topology at the right layer: hooks.server.ts proxies /api/*
requests through to the backend container over docker's internal
network. The browser only ever talks to :3000, cookies stay
same-origin, and CORS can stay empty.
- frontend/src/hooks.server.ts: new proxy. Reads BACKEND_URL (defaults
to http://localhost:8080 for ad-hoc node builds). Strips `host` and
`content-length` so the backend sees the real client request and
recomputes the length. Sets `duplex: 'half'` for streamed POST
bodies. GET/HEAD have no body. Non-/api paths fall through to
SvelteKit normally.
- docker-compose.yml: drop the host port mapping on the backend
(browser doesn't reach it directly anymore — use `ports:` instead of
`expose:` if you want curl access). Set BACKEND_URL=http://backend:8080
on the frontend service. Drop PUBLIC_API_BASE which was unused.
- .env.example: replace PUBLIC_API_BASE with BACKEND_URL, with a note
on what it does.
- README: explain the new topology in Quick start, update the bot
curl examples to hit :3000 (since that's the only published port in
the default deploy), and call out that the TLS terminator only needs
one upstream now.
Lockstep version bump to 0.9.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- README rewritten end-to-end: stack, quick start, dev workflow, full
/api/v1 endpoint table, error and pagination envelopes, auth
quick-start (browser + bot bearer), configuration table, deployment
notes, backup/restore pointer. Stale "next features" section dropped
now that all eight feat branches are in.
- .env.example now lists every env var the backend reads, with
inline explanations:
- COOKIE_SECURE / COOKIE_DOMAIN / SESSION_TTL_DAYS (auth)
- CORS_ALLOWED_ORIGINS (same-origin by default)
- MAX_REQUEST_BYTES / MAX_FILE_BYTES (upload caps)
- Postgres + storage + log vars carried over.
- docker-compose.yml forwards all of the above into the backend
service with `${VAR:-default}` so an unset value falls back to the
same default the code uses, and any `.env` override flows through
without a compose edit.
- docs/backup.md: step-by-step backup, restore, and smoke-test drill
for both stateful volumes (postgres-data + storage-data), plus a
list of what's deliberately *not* in the backup (e.g., .env).
- playwright.config.ts: pins the e2e dev server to port 5174 with
`--strictPort` so it neither reuses nor silently bumps off
collision with another vite instance on 5173. Drops the flaky
manual-start workflow the earlier branches needed.
- docker-compose syntax (both prod and dev) validates cleanly against
.env.example with no undefined-variable warnings.
No version bump — this is documentation, config, and tooling.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Set up Mangalord with a Rust/axum backend, SvelteKit frontend, Postgres,
and Docker Compose deployment. Establishes the architecture and TDD
patterns the project will extend:
- Hexagonal-ish backend layering (domain / repo / storage / api) with
a pluggable Storage trait (LocalStorage today, S3 as a future impl).
- Initial migration: users, mangas, chapters, bookmarks.
- Vertical slice for mangas (list, search, create, get) with
#[sqlx::test] integration coverage and storage unit tests.
- SvelteKit frontend using Svelte 5 runes, typed API client, Vitest
unit tests and Playwright e2e with route mocking.
- CLAUDE.md documenting layering, TDD/git/SemVer workflow rules, and
extension points (tags, fulltext search, OCR, S3, auth).
- Project-scoped .claude/settings.json with permission allowlist for
the toolchain (git, cargo, npm/vite, docker, psql, gh, doc fetches).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>