Devlog: 2026-03-16 — Nginx Proxy, Hostnames, and Project Rules
What Happened
Continuation of the kickoff session. After importing the chat history from the PowerSeller 80 legacy analysis project, we addressed three areas: local container architecture, ecosystem hostname conventions, and project governance rules.
Problem
The PowerSeller X project already runs 14 containers across 16 host port mappings. Adding 5–7 PSSaaS containers with their own ports would push past 20 port mappings across the two projects. Remembering which port maps to which service becomes a usability problem for the development team.
Decisions
1. Nginx Reverse Proxy with Docker Compose Profiles
Added an Nginx reverse proxy (pssaas-proxy) as the single entry point, with path-based routing to all backend services. Formalized as ADR-016.
Organized Docker Compose services into profiles:
- Default: proxy + docs (what's useful today)
dev: API + frontend + cache (when application code exists)full: identity + message bus + mail (supporting infrastructure)
2. Ecosystem Hostname Convention
Adopted the *.powerseller.local namespace with per-project loopback IPs instead of localhost:PORT. Formalized as ADR-017.
127.0.0.1 pssaas.powerseller.local— PSSaaS (this project)127.0.0.2 psx.powerseller.local— PSX
Both projects bind to port 80 on their respective IPs. No port numbers in URLs.
3. Project Governance Rules
Adopted the same .cursorrules / CLAUDE.md / .cursor/rules/ pattern used by the PowerSeller X project, adapted for PSSaaS:
.cursorrules— specs first, ADRs, conventional commits, PO governance, C#/.NET code quality standards, tenant isolation, Docker Compose profilesCLAUDE.md— lean session context auto-loaded by Cursor.cursor/rules/markdown-formatting.mdc— markdown lint rules (loaded when editing.mdfiles)
What Was Built
| File | Action |
|---|---|
proxy/nginx.conf | Created — path-based reverse proxy with WebSocket support, Docker DNS runtime resolution, server_name pssaas.powerseller.local |
proxy/Dockerfile | Created — nginx:alpine with config copy |
docker-compose.yml | Rewritten — proxy on 127.0.0.1:80, profiles, 8 service definitions |
docs-site/docusaurus.config.ts | Updated — baseUrl: '/docs/', url: 'http://pssaas.powerseller.local' |
docs-site/docs/arc42/07-deployment-view.md | Updated — section 7.3 rewritten for proxy + profiles + hostname |
docs-site/docs/adr/adr-016-nginx-proxy-profiles.md | Created — proxy and profiles decision |
docs-site/docs/adr/adr-017-ecosystem-hostnames.md | Created — hostname convention decision |
docs-site/docs/arc42/09-architecture-decisions.md | Updated — ADR index includes 016 and 017 |
.cursorrules | Created — project governance rules |
CLAUDE.md | Created — lean AI agent context |
.cursor/rules/markdown-formatting.mdc | Created — markdown lint rules |
README.md | Updated — hostname, hosts file instructions |
Technical Notes
- Nginx uses
resolver 127.0.0.11(Docker internal DNS) with variable-basedproxy_passfor optional services. Unavailable routes return HTTP 502 instead of crashing Nginx. - The
docslocation block uses a directproxy_pass(not variable-based) because docs are always available in the default profile. - The proxy binds to
127.0.0.1:80specifically (not0.0.0.0:80), leaving127.0.0.2:80available for the PowerSeller X project. - The entire
127.0.0.0/8range is loopback on Windows, so each project can independently bind port 80 on a different loopback address.
Known Technical Debt
- The initial commit (
660992c) does not use conventional commit format. Per our own rules, we cannot amend it. All future commits must use thefeat:,fix:,chore:,docs:format.
Verification
docker compose upstarts proxy + docs (2 containers)http://pssaas.powerseller.local/docs/serves Docusaurus (HTTP 200)- Deep links through proxy (arc42, ADRs, legacy docs) all resolve correctly
/api/and/return HTTP 502 gracefully (services not yet running)
What's Next
From the agreed roadmap:
- Connect to SQL MI and pull real schema
- Write the BestEx specification
- Scaffold the .NET solution structure