- api/cloud_session.py: new module — JWT validation (Directus HS256), Heimdall provision+tier-resolve, CloudUser+SessionFeatures dataclasses, compute_features() tier→feature-flag mapping, require_tier() dependency factory, get_session() FastAPI dependency (local-mode transparent passthrough) - api/main.py: remove _DB_PATH singleton; all endpoints receive session via Depends(get_session); shared_store (sellers/comps) and user_store (listings/ saved_searches) created per-request from session.shared_db / session.user_db; pages capped to features.max_pages; saved_searches limit enforced for free tier; /api/session endpoint exposes tier+features to frontend; _trigger_scraper_enrichment receives shared_db Path (background thread creates its own Store) - app/platforms/ebay/adapter.py, scraper.py: rename store→shared_store parameter (adapters only touch sellers+comps, never listings — naming reflects this) - app/trust/__init__.py: rename store→shared_store (TrustScorer reads sellers+comps from shared DB; listing staging fields come from caller) - app/db/store.py: refresh_seller_categories gains listing_store param for split-DB mode (reads listings from user_store, writes categories to self) - web/src/stores/session.ts: new Pinia store — bootstrap() fetches /api/session, exposes tier+features reactively; falls back to full-access local defaults - web/src/App.vue: call session.bootstrap() on mount - web/src/views/SearchView.vue: import session store; pages buttons disabled+greyed above features.max_pages with upgrade tooltip - compose.cloud.yml: add CLOUD_MODE=true + CLOUD_DATA_ROOT env; fix volume mount - docker/web/nginx.cloud.conf: forward X-CF-Session header from Caddy to API - .env.example: document cloud env vars (CLOUD_MODE, DIRECTUS_JWT_SECRET, etc.)
51 lines
1.9 KiB
YAML
51 lines
1.9 KiB
YAML
# Snipe — cloud managed instance
|
|
# Project: snipe-cloud (docker compose -f compose.cloud.yml -p snipe-cloud ...)
|
|
# Web: http://127.0.0.1:8514 → menagerie.circuitforge.tech/snipe (via Caddy basicauth)
|
|
# API: internal only on snipe-cloud-net (no host port — only reachable via nginx)
|
|
#
|
|
# Usage: ./manage.sh cloud-start | cloud-stop | cloud-restart | cloud-status | cloud-logs | cloud-build
|
|
|
|
services:
|
|
api:
|
|
build:
|
|
context: ..
|
|
dockerfile: snipe/Dockerfile
|
|
restart: unless-stopped
|
|
env_file: .env
|
|
environment:
|
|
# Cloud mode — enables per-user DB isolation and Heimdall tier resolution.
|
|
# All values may be overridden by setting them in .env (env_file takes precedence
|
|
# over environment: only when the same key appears in both — Docker merges them,
|
|
# env_file wins for duplicates).
|
|
CLOUD_MODE: "true"
|
|
CLOUD_DATA_ROOT: /devl/snipe-cloud-data
|
|
# DIRECTUS_JWT_SECRET, HEIMDALL_URL, HEIMDALL_ADMIN_TOKEN — set in .env (never commit)
|
|
# No network_mode: host — isolated on snipe-cloud-net; nginx reaches it via 'api:8510'
|
|
volumes:
|
|
- /devl/snipe-cloud-data:/devl/snipe-cloud-data
|
|
networks:
|
|
- snipe-cloud-net
|
|
|
|
web:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/web/Dockerfile
|
|
args:
|
|
# Vite bakes these at image build time — changing them requires cloud-build.
|
|
# VITE_BASE_URL: app served under /snipe → asset URLs become /snipe/assets/...
|
|
# VITE_API_BASE: prepended to all /api/* fetch calls → /snipe/api/search
|
|
VITE_BASE_URL: /snipe
|
|
VITE_API_BASE: /snipe
|
|
restart: unless-stopped
|
|
ports:
|
|
- "8514:80" # Caddy (caddy-proxy container) reaches via host.docker.internal:8514
|
|
volumes:
|
|
- ./docker/web/nginx.cloud.conf:/etc/nginx/conf.d/default.conf:ro
|
|
networks:
|
|
- snipe-cloud-net
|
|
depends_on:
|
|
- api
|
|
|
|
networks:
|
|
snipe-cloud-net:
|
|
driver: bridge
|