Resolve the operational/config sprawl (#10-#14 from the review): the app read
NORMOGEN_*/MONGODB_* env vars but every env/compose file set SERVER_*/DATABASE_*,
the ports were all over the place (8080/8000/6500/6800), there were 5
inconsistent Dockerfiles (rust:1.82 vs rust:1.93, missing curl), and an 18 MB
binary was committed.
Env-var names — standardize on what the code reads:
* config/mod.rs: NORMOGEN_PORT default 8080 -> 6500 (avoid the over-common
8000/8080).
* db/mod.rs: create_database() now reads MONGODB_DATABASE (was DATABASE_NAME).
* .env.example, defaults.env, docker-compose.yml, docker-compose.dev.yml,
DEPLOYMENT_GUIDE.md, deployment/README.md, deploy-and-test-solaria.sh,
deploy-local-build.sh: use NORMOGEN_HOST/NORMOGEN_PORT/MONGODB_URI/
MONGODB_DATABASE/APP_ENVIRONMENT; drop the dead SERVER_*/DATABASE_URI/
DATABASE_NAME names.
Ports — canonical container port 6500 everywhere:
* Both Dockerfiles EXPOSE 6500; prod compose maps 6500:6500, dev 6501:6500.
* Bulk-replaced the long tail of solaria:8000/localhost:8000/localhost:8080 in
docs and test scripts -> 6500.
Dockerfiles — 2 canonical, rust:latest, curl + healthcheck:
* backend/Dockerfile (prod): rust:latest builder, debian runtime now installs
curl (so the compose HEALTHCHECK actually works), EXPOSE 6500.
* backend/docker/Dockerfile.dev (dev): rust:latest both stages, EXPOSE 6500.
* Deleted 3 redundant Dockerfiles (Dockerfile.improved x2, docker/Dockerfile).
* Deleted the committed 18 MB binary backend/docker/normogen-backend.
* Deleted 2 stray fix-notes in backend/docker/.
Compose:
* docker-compose.yml: correct env names, 6500:6500, APP_ENVIRONMENT=production,
JWT_SECRET/ENCRYPTION_KEY required via compose interpolation, dropped the
obsolete top-level version: key.
* docker-compose.dev.yml: correct env names, 6501:6500, mongo:7 (was 6.0),
added a working backend healthcheck.
* Deleted docker/docker-compose.improved.yml + backend/deploy-to-solaria-improved.sh
(built around the now-deleted 'improved' Docker files).
Verified: cargo fmt --check clean, build + clippy --all-targets clean, 18 unit
tests pass; grep confirms no SERVER_*/DATABASE_* env names and no rust:1.x tags
remain outside docs/archive and docs/adr (historical).
Address the four P0 security items from the project review:
* token_version validation (#1): the JWT middleware now rejects access tokens
whose token_version claim is stale (e.g. issued before a password change).
A short-TTL (30s) in-memory cache (TokenVersionCache) avoids a Mongo lookup
per request; credential changes invalidate the cache immediately on the
handling instance.
* Fail-fast config (#2): add APP_ENVIRONMENT (development|production). In
production the server refuses to boot unless JWT_SECRET and ENCRYPTION_KEY
are set to non-default values; development keeps the insecure defaults with
a warning.
* Real client IP in audit logs (#4): new client_ip middleware resolves the
originating IP (X-Forwarded-For > X-Real-IP > ConnectInfo socket) and
exposes it via a ClientIp extractor. All five hardcoded "0.0.0.0" audit
calls are replaced, and the missing PasswordChanged audit event is added to
change_password. axum::serve now uses into_make_service_with_connect_info.
* Refresh token persistence (#5): refresh tokens are now stored hashed in
MongoDB (RefreshTokenRepository) instead of an in-memory map lost on restart.
Added /api/auth/refresh (with rotation + token_version check) and
/api/auth/logout routes; register/login return a refresh_token; password
change/recovery revoke all of a user's refresh tokens. JwtService now honors
JwtConfig expiries instead of hardcoding 15min/30d, and the dead in-memory
refresh store is removed.
Also: wire up DatabaseInitializer (was never called), fix the refresh_tokens
index to tokenHash + add an expiresAt TTL index, add sha2 dep.
Rate limiting (#3) is deferred per scope; the stub remains.
Verified: cargo fmt --check clean, cargo build/clippy --all-targets clean,
18 unit tests pass (9 new). Integration tests (tests/*) still need a live
server — fixing them is tracked as P1.
BREAKING CHANGE: AuthResponse now includes a refresh_token field.
- Created Cargo.toml with all required dependencies
- Implemented health/ready endpoints
- Added Docker configuration (production + development)
- Configured docker-compose with resource limits
- Set up MongoDB service with persistence
- Verified build (cargo check passed)
- Prepared monorepo structure for mobile/web/shared
Next: Phase 2.2 (MongoDB connection and models)