Files
LudosData/docker-compose.yml
T
ckochandClaude Opus 5 8e136f42f8 Add CSV price guides and PriceCharting alongside eBay
An eBay production keyset needs account verification, which leaves pricing
blocked on someone else's review queue. These are two routes that are not.

CSV price guide, POST /api/prices/import: no account, works immediately.
Column names are matched by alias, so a PriceCharting bulk export
(product-name / console-name / loose-price) and a hand-kept
title,system,loose,cib,new sheet both parse, along with currency symbols,
thousands separators and blank cells. Rows match on title + system, so the
same game on two consoles is priced separately, and rows for games not in
the library are reported rather than silently added.

PriceCharting adapter: paid, but access is immediate with no review, and it
quotes the same three tiers this app stores, so no inference is needed.
Their API docs are not reachable without an account, so the parser follows
the widely-used convention — integer pennies under hyphenated keys — and is
tolerant enough that a naming difference degrades to "no price" instead of
throwing. One method to adjust if it differs.

Providers are now a registry rather than a single service. /api/prices/status
lists each one with what it is configured for, what its numbers actually
mean, and how to enable it; refresh takes an optional provider name and
falls back to the first configured one. With none configured it answers 503
pointing at the CSV route.

Checked against the real library: a five-row guide in PriceCharting's own
column names priced four games and reported the fifth as not owned, with
each effective value following that copy's condition. Demo figures were
cleared afterwards.

135 backend tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 16:46:10 -04:00

77 lines
2.6 KiB
YAML

# LudosData — full stack.
#
# cp .env.example .env # then edit the secrets
# docker compose up --build
#
# The SPA is served by nginx on http://localhost:8080, which also reverse-proxies
# /api and /uploads to the API container. Because everything is same-origin in
# this setup, the browser never issues a cross-origin request and CORS is not in
# play at all — the API's CORS policy only matters for `ng serve` on :4200.
services:
api:
build:
context: ./backend
image: ludosdata-api
restart: unless-stopped
environment:
ASPNETCORE_ENVIRONMENT: Production
# Required. Startup fails loudly if this is missing or under 32 chars.
Jwt__Key: ${JWT_KEY:?JWT_KEY is required — see .env.example}
Jwt__Issuer: ${JWT_ISSUER:-LudosData}
Jwt__Audience: ${JWT_AUDIENCE:-LudosData}
Jwt__LifetimeMinutes: ${JWT_LIFETIME_MINUTES:-720}
# Creates the first account and imports the 105 games from the 2018 dump,
# but only while the database has no users at all.
Seed__Enabled: ${SEED_ENABLED:-true}
Seed__UserName: ${SEED_USERNAME:-}
Seed__Email: ${SEED_EMAIL:-}
Seed__Password: ${SEED_PASSWORD:-}
# Optional market-value lookups. Blank means the pricing endpoints report
# 503 and everything else carries on.
PriceCharting__Token: ${PRICECHARTING_TOKEN:-}
Ebay__ClientId: ${EBAY_CLIENT_ID:-}
Ebay__ClientSecret: ${EBAY_CLIENT_SECRET:-}
Ebay__UseSandbox: ${EBAY_USE_SANDBOX:-false}
# Only consulted when the SPA is served from somewhere other than nginx.
Cors__AllowedOrigins__0: ${CORS_ORIGIN:-http://localhost:8080}
Cors__AllowedOrigins__1: http://localhost:4200
volumes:
# SQLite file and uploaded box art. This is the only stateful thing in the
# stack — back this volume up and you have backed up everything.
- ludos-data:/data
expose:
- "8080"
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/health || exit 1"]
interval: 15s
timeout: 3s
retries: 5
start_period: 20s
web:
build:
context: ./frontend
image: ludosdata-web
restart: unless-stopped
depends_on:
api:
condition: service_healthy
ports:
- "${WEB_PORT:-8080}:8080"
healthcheck:
# 127.0.0.1, not localhost: nginx listens on IPv4 only, and BusyBox wget
# resolves localhost to ::1 first and gets connection-refused.
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:8080/ || exit 1"]
interval: 15s
timeout: 3s
retries: 5
start_period: 10s
volumes:
ludos-data: