mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
## Summary Adds a standalone Docker Compose proof that runs the Fabro Rust API, a Caddy static SPA server, and a Caddy edge proxy as separate services. This demonstrates split web asset serving while keeping `/api/*`, `/auth/*`, and `/health` same-origin with the API server. ## Changes - Adds `docker-compose.split-web.yaml` with private `fabro-api` and `fabro-web` services behind an exposed `edge` proxy on port 8080. - Adds Caddy edge routing that sends `/api/*`, `/auth/*`, and `/health` to Rust, while everything else goes to the static web service. - Adds a static Caddy config for `apps/fabro-web/dist` with SPA fallback, source-map blocking, security headers, immutable asset caching, and `X-Fabro-PoC-Upstream` route-proof headers. - Adds PoC server settings and a README with build, run, and validation commands. ## Verification - `cargo dev docker-build --tag fabro-sh/fabro:split-web-poc` - `docker compose -f docker-compose.split-web.yaml up -d` - `docker compose -f docker-compose.split-web.yaml ps` - `curl` checks for `/runs`, `/assets/app.css`, `/assets/app.css.map`, `/api/v1/health`, `/api/v1/auth/config`, `/auth/login/dev-token`, `/api/v1/auth/me`, and `/api/v1/attach` - Browser login flow via `browser-use`: loaded `/login`, submitted the dev token, and landed on the authenticated Runs screen - `docker compose -f docker-compose.split-web.yaml config` - `caddy validate` for both Caddyfiles - `git diff --check` --- [](https://github.com/EveryInc/compound-engineering-plugin) 🤖 Generated with GPT-5 via [Codex](https://openai.com/codex)
39 lines
1.4 KiB
Text
39 lines
1.4 KiB
Text
:80 {
|
|
root * /srv/web/dist
|
|
encode gzip zstd
|
|
|
|
header {
|
|
X-Content-Type-Options nosniff
|
|
X-Frame-Options DENY
|
|
Referrer-Policy strict-origin-when-cross-origin
|
|
Cross-Origin-Opener-Policy same-origin
|
|
Cross-Origin-Resource-Policy same-origin
|
|
Permissions-Policy "accelerometer=(), autoplay=(), camera=(), display-capture=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), usb=(), web-share=(), xr-spatial-tracking=()"
|
|
Content-Security-Policy "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' https://fonts.googleapis.com 'unsafe-inline'; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: blob: https://avatars.githubusercontent.com; connect-src 'self' ws: wss:; worker-src 'self' blob:; manifest-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'"
|
|
}
|
|
|
|
@sourceMaps path *.map
|
|
handle @sourceMaps {
|
|
respond 404
|
|
}
|
|
|
|
@cacheAssets {
|
|
path /assets/*
|
|
not path *.map
|
|
}
|
|
header @cacheAssets Cache-Control "public, max-age=31536000, immutable"
|
|
|
|
@htmlNavigation {
|
|
header Accept *text/html*
|
|
not path /assets/*
|
|
}
|
|
handle @htmlNavigation {
|
|
try_files {path} /index.html
|
|
header Cache-Control "no-cache"
|
|
file_server
|
|
}
|
|
|
|
handle {
|
|
file_server
|
|
}
|
|
}
|