# the stack under test: the same images and Dockerfiles the dev stack # builds, wired to their own ports and to throwaway state. # # differences from docker/docker-compose.dev.yaml are deliberate: # - no named volumes, so every run starts from an empty database # - no container_name, so this stack coexists with the dev one # - env is inlined and committed; there is nothing secret to protect # - only the services the tests exercise (no changedetection, mariadb, # datagen or grafana) # - no valkey and no object store, so core and auth-realtime fall back # to their built-in equivalents (in-process conversations, no # secondary session storage, images on the container filesystem) — # which is what a production deployment does when those variables # are unset, and therefore the configuration most installs run # # the front door is the dev Caddyfile verbatim: e2e must exercise the # same routing and the same /api/x and /api/internal blocks that ship. # # every image is pinned, as in the dev stack. A run has to fail because # this repository changed, not because something upstream published a # new latest overnight. name: oxynote-e2e-dev services: caddy: image: caddy:2.11.4-alpine volumes: - ../docker/Caddyfile:/etc/caddy/Caddyfile ports: - "18080:8080" depends_on: web: condition: service_healthy core: condition: service_started auth-realtime: condition: service_healthy web: image: ghcr.io/oxynote/web:e2e-dev build: context: ../web dockerfile: Dockerfile.dev environment: - NUXT_PUBLIC_APP_BASE_URL=http://localhost:18080 - NUXT_PUBLIC_AUTH_REALTIME_API_BASE_HTTP_URL=http://localhost:18080/auth-realtime - NUXT_PUBLIC_AUTH_REALTIME_API_BASE_WS_URL=ws://localhost:18080/auth-realtime/hocuspocus - NUXT_PUBLIC_CORE_API_BASE_HTTP_URL=http://localhost:18080/core - NUXT_PUBLIC_CORE_API_BASE_WS_URL=ws://localhost:18080/core # SSR runs inside the container, where the public localhost origin # is unreachable; these send server-side fetches over the compose # network instead. - NUXT_CORE_API_INTERNAL_HTTP_URL=http://core:8080 - NUXT_AUTH_REALTIME_API_INTERNAL_HTTP_URL=http://auth-realtime:8081 healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/login"] interval: 5s timeout: 5s retries: 30 start_period: 20s auth-realtime: image: ghcr.io/oxynote/auth-realtime:e2e-dev build: context: ../server/auth-realtime dockerfile: Dockerfile.dev environment: - OXYNOTE_AUTH_REALTIME_BACKEND_URL=http://core:8080 - OXYNOTE_AUTH_REALTIME_DB_DSN=postgresql://devuser:devpass@postgres/devdb?sslmode=disable - OXYNOTE_AUTH_REALTIME_BETTER_AUTH_BASE_URL=http://localhost:18080/auth-realtime - OXYNOTE_AUTH_REALTIME_BETTER_AUTH_COOKIE_DOMAIN=localhost - OXYNOTE_AUTH_REALTIME_FRONTEND_URL=http://localhost:18080 - OXYNOTE_AUTH_REALTIME_BETTER_AUTH_ORGANIZATION_INVITATION_URL=http://localhost:18080/accept-invite - OXYNOTE_AUTH_REALTIME_TRUSTED_ORIGINS=http://localhost:18080 # must match core's SERVER_MCP_RESOURCE_URL - OXYNOTE_AUTH_REALTIME_MCP_RESOURCE=http://localhost:18080/core/api/mcp - OXYNOTE_AUTH_REALTIME_BETTER_AUTH_SECRET=e2esecret - OXYNOTE_AUTH_REALTIME_MAX_ORGANIZATION_MEMBERS=5 # every test signs up and creates its own workspace, and a stack # left up for a day of iteration would hit the dev default of 50 # and start failing signups with a full-house message. - OXYNOTE_AUTH_REALTIME_MAX_ORGANIZATIONS=100000 # every request in a run arrives from one address, and better-auth # gives sign-in and sign-up three per ten seconds between them, so # the limiter would fail the suite rather than the code under test. - OXYNOTE_AUTH_REALTIME_RATE_LIMIT_DISABLED=true depends_on: postgres: condition: service_healthy healthcheck: test: [ "CMD", "wget", "--spider", "-q", "http://localhost:8081/api/auth-config", ] interval: 5s timeout: 5s retries: 30 core: image: ghcr.io/oxynote/core:e2e-dev environment: - OXYNOTE_CORE_DB_DSN=postgresql://devuser:devpass@postgres/devdb?sslmode=disable - OXYNOTE_CORE_SEARCH_INDEX_PATH=/home/nonroot/search - OXYNOTE_CORE_OBJECT_STORAGE_LOCAL_PATH=/home/nonroot/storage - OXYNOTE_CORE_SERVER_AUTH_BETTER_AUTH_URL=http://auth-realtime:8081/api/auth/get-session # the MCP surface: core validates bearer tokens against auth-realtime # over the compose network, and the resource URL is the public # identity of that surface — it has to match auth-realtime's # MCP_RESOURCE exactly or issued tokens fail their audience check. - OXYNOTE_CORE_SERVER_MCP_SESSION_URL=http://auth-realtime:8081/api/internal/mcp/session - OXYNOTE_CORE_SERVER_MCP_RESOURCE_URL=http://localhost:18080/core/api/mcp - OXYNOTE_CORE_AUTH_REALTIME_URL=http://auth-realtime:8081 - OXYNOTE_CORE_SERVER_PUBLIC_URL=http://localhost:18080/core - OXYNOTE_CORE_BASE_APP_URL=http://localhost:18080 - OXYNOTE_CORE_ORIGINS=http://localhost:18080,localhost:18080 - OXYNOTE_CORE_DB_DATA_SOURCE_CREDENTIALS_KEYS=49i0eQzCx6VZfY7ZSravUYR4CvvsDtkQlG4wPnizm+Y= - OXYNOTE_CORE_EMAIL_SMTP_HOST=mailpit - OXYNOTE_CORE_EMAIL_SMTP_PORT=1025 - OXYNOTE_CORE_EMAIL_SMTP_TLS=none - OXYNOTE_CORE_EMAIL_FROM_ADDRESS=Oxynote depends_on: postgres: condition: service_healthy postgres: image: postgres:18.6-alpine command: ["postgres", "-c", "log_checkpoints=off"] environment: POSTGRES_USER: devuser POSTGRES_PASSWORD: devpass POSTGRES_DB: devdb healthcheck: test: ["CMD-SHELL", "pg_isready -U devuser -d devdb"] interval: 5s timeout: 5s retries: 20 # the tests read verification links out of mailpit's REST API, so its # http port is published rather than proxied through caddy. mailpit: image: axllent/mailpit:v1.31.3 environment: - MP_QUIET=true ports: - "18025:8025"