# Local development stack: LaDOSE.Api + LaDOSE.WebApp, built from the two Dockerfiles # already in the tree. # # docker compose up --build start both, rebuilding when a Dockerfile changed # docker compose watch same, plus rebuild the service you are editing # docker compose logs -f api follow the API # docker compose down stop # # Then: webapp on http://localhost:8080, API on http://localhost:5000, # Scalar API reference on http://localhost:5000/scalar. # # LaDOSE.DiscordBot is here too, behind the "bot" profile, so it stays out of the way # until you have a Discord token to give it — an unconfigured bot cannot start at all, # it can only crash-loop. # # docker compose --profile bot up --build everything, bot included # docker compose --profile bot up -d bot just the bot # docker compose logs -f bot follow it # # The database is NOT part of this stack — it stays wherever appsettings.json points. # Copy .env.example to .env to change the ports, the connection string or the API keys. name: ladose services: api: build: context: ./LaDOSE.Src dockerfile: Dockerfile args: # Debug, not Release: /openapi/v1.json and /scalar are compiled out of a # Release build. See the comment in LaDOSE.Src/Dockerfile. BUILD_CONFIGURATION: Debug environment: # Startup.cs gates the developer exception page, MapOpenApi() and # MapScalarApiReference() on IsDevelopment(). ASPNETCORE_ENVIRONMENT: Development # Double underscore is the .NET section separator, so this overrides # ConnectionStrings:DbContext from appsettings.json. Left unset in .env, the # default below reproduces what is committed there. ConnectionStrings__DbContext: ${LADOSE_DB_CONNECTION:-Host=kafka.local;Username=tom;Password=tom;Database=ladoseapi} # appsettings.json ships placeholders for these three. Real values belong in # .env, which git ignores. JWTTokenSecret: ${LADOSE_JWT_SECRET:-dev-only-secret-not-for-any-deployed-environment} ApiKey__SmashApiKey: ${LADOSE_SMASH_API_KEY:-} ApiKey__ChallongeApiKey: ${LADOSE_CHALLONGE_API_KEY:-} # Rankings export to Google Sheets. "Disabled" out of the box, so the button # reports "not configured" rather than failing. Set Writer=Logging to see the # payload in `docker compose logs -f api` without touching a spreadsheet. GoogleSheets__Writer: ${LADOSE_SHEETS_WRITER:-Disabled} GoogleSheets__SpreadsheetId: ${LADOSE_SHEETS_SPREADSHEET_ID:-} GoogleSheets__ServiceAccount__CredentialsPath: ${LADOSE_SHEETS_SA_CREDENTIALS_PATH:-} volumes: # Where the service-account key lives, read-only. Compose creates ./secrets if it # is missing, so this is harmless when the export is Disabled or set to Logging. # git ignores the directory; put ladose-sheets-sa.json in it. - ./secrets:/run/secrets:ro ports: # Container side is pinned at 5000: Program.cs reads AllowedHosts/Port straight # from appsettings.json, through a ConfigurationBuilder that ignores env vars. - "${LADOSE_API_PORT:-5000}:5000" extra_hosts: # Lets LADOSE_DB_CONNECTION use Host=host.docker.internal to reach a Postgres # running on the machine hosting the containers. - "host.docker.internal:host-gateway" develop: watch: - action: rebuild path: ./LaDOSE.Src ignore: - LaDOSE.WebApp/ - "**/bin/" - "**/obj/" web: build: context: ./LaDOSE.Src/LaDOSE.WebApp dockerfile: Dockerfile # VITE_API_BASE_URL is deliberately not passed. Vite would inline it at build # time; LADOSE_API_BASE_URL below is read at container start instead, so the # port can change without rebuilding the image. environment: # docker-entrypoint.sh turns this into /config.js. It is resolved by the # *browser*, so it must be a host-visible URL — not http://api:5000. LADOSE_API_BASE_URL: ${LADOSE_API_BASE_URL:-http://localhost:${LADOSE_API_PORT:-5000}} ports: - "${LADOSE_WEB_PORT:-8080}:80" depends_on: # Ordering only. The SPA is served by nginx and talks to the API from the # browser, so it comes up fine on its own; this just avoids a confusing # first-load failure when starting both at once. - api develop: watch: - action: rebuild path: ./LaDOSE.Src/LaDOSE.WebApp ignore: - node_modules/ - build/ - .svelte-kit/ bot: profiles: # Opt-in: `docker compose up` without --profile bot leaves this service alone. # LADOSE_DISCORD_TOKEN has no usable default — without one the bot exits on the # first connection attempt and `restart` below turns that into a loop — so it does # not belong in the default `up` the way the API and the webapp do. - bot build: # Context is LaDOSE.Src, shared with the api service: the bot references # LaDOSE.REST/LaDOSE.DTO and Libraries/ChallongeCSharpDriver.dll, none of which are # reachable from a context rooted at LaDOSE.DiscordBot. context: ./LaDOSE.Src dockerfile: LaDOSE.DiscordBot/Dockerfile # No BUILD_CONFIGURATION override: unlike the API, nothing in this project is # compiled out of a Release build, so the Dockerfile's Release default is right. environment: # Program.cs reads settings.json and never looks at the environment, so # LaDOSE.DiscordBot/docker-entrypoint.sh renders that file from these five values at # container start. Setting LADOSE_DISCORD_TOKEN is what switches the rendering on. LADOSE_DISCORD_TOKEN: ${LADOSE_DISCORD_TOKEN:-} # Same key the api service gets — one bot and one API against the same Challonge # account. LADOSE_CHALLONGE_API_KEY: ${LADOSE_CHALLONGE_API_KEY:-} # Resolved *inside* the container, unlike the webapp's LADOSE_API_BASE_URL, so the # compose service name is the right answer and the host port mapping is irrelevant. LADOSE_BOT_REST_URL: ${LADOSE_BOT_REST_URL:-http://api:5000} # Credentials of the LaDOSE.Api account the bot logs in as (RestService.Connect). LADOSE_BOT_REST_USER: ${LADOSE_BOT_REST_USER:-} LADOSE_BOT_REST_PASSWORD: ${LADOSE_BOT_REST_PASSWORD:-} depends_on: # Ordering only, and only useful for the commands that call the API. The bot's own # startup does not touch it: WebService swallows a failed Connect with "Unable to # contact services", so a late API is recoverable. - api restart: unless-stopped develop: watch: - action: rebuild path: ./LaDOSE.Src ignore: - LaDOSE.WebApp/ - "**/bin/" - "**/obj/"