26OVOVE7YBYMHM6N6B5FBNCTWMJ5X2TOMNUSZAEIIGXU3V75Z6UAC DP2YHL4SRFFFPXBH52N7WKXQUYNGNXZ5MNNTHMJKR5O7UI5H5SSQC DPBDWBX5WRGDBFQRBEWJOHSV4TIGJS2EIJC257HBOSZFSQ2J2WNQC RNHBTG23XBZEWM6W6ZBQGLDUMGH74NKUORUEATD2Y4AQY4QXXCVAC BO3PVW7G4LAKML2VP4GMSWMUYZ5LWP42OH2QAMHSJAZ7UNUFZ4PQC JSCADX2MSZZRVGE4YG4GE6WFNXJWXTZB42X6OZA2KIKKX2APCXFQC GIKW7G7ZCEUPTGDPUV236VJCPM7UGNKI6LI2T5KMIUWVNB4PICQQC HOERBQLW2OCQ5YLQJ2SJTV77QHUTQZ4YN2PP3D3GGD4SHS5TYRKAC 4H3JU2BIPRWBZZN5BONW7QAWATBTELVTIKSXXIGTVK2TLYWY3NGQC MNAL3YT5ISE3SURBXAWPRFESCHUNBAU3D7S4ND5JZAIMSO3KSHLAC FKGOJEK763FN6TPXDX3MTB663BAMFNHN4WKH54VPX5ZFK3VEY3QAC 4UOJNHVNH7DUAK4AWBQ5VIIDGBLPJCZ7AHN5HLYKTY6GUVSZPDJAC BDJDHEKLGXV3PKHORM3WUX4JXM6WOPDBWMS2IHZTB56PHHYULQLQC TFCV4Q2VF5EV4BVWYJZUJGT757ELJGDCAVUCSESWCIFGTYV3A5WAC OKPCYKFRUVA3KXT6I722VW4EN3QNJWDOM34FKCSW36PZCNPAUDQQC CX6FL5M2UDUHWZUV4AKHC4XAKN7R7MV4EI3NXMTVRTP7O5KI5I5AC ZULYN45RBZOKP5C2IRCMCE3MYQEUMZ5XRJTEVC3HSGATKHOEGJKAC OJPQBDUTTJZEPEDA2PFAXUFQX3LYPJDQEEP63MEF4D3L4PN7RRSQC KASNCQ3VEVIK2DA6RCDSBIDJILP7WLB3RF4R7YLJ4M7D563PCFJQC J6PH2TWHEBJ6U6XRCEHXKSDRVLOPL4PCUEHEIFK5SVR6WZ7Q4GNQC 4E4ZW7DBJQODJZCTPKYJA7QH5YSQ4DMLAGCQEHZ3SSPUFMDA5GXQC VKL4K7RIU44ELZLG3LGWMKODNVJMVZ5GGDITMPE4Z2TTQGXCVJBAC CP6ZVMH6AICKJDFT7W73MGUXH3PSBOTQDJ2FMROKXZHVOPSV3OYAC CFXD45AUEFXQ3YW74DMN52I6CKJTCAIIHJMAWB3XX74KWTJLF4LQC R3V7MVYA7POIZUTAWP63JM73LKHGJR2YPX2OQQC2KI3V6OOQBQCAC ENV PYTHONUNBUFFERED=trueENV PATH="/root/.local/bin:${PATH}"COPY src/ ./src# Run from app source directoryWORKDIR /app/src# Install runtime dependencies (no dev) using uv and the lock if presentRUN uv sync --no-dev --frozen || uv sync --no-dev# Copy application sourceEXPOSE $PORT# Use uv to run the server with the project virtualenvCMD uv run uvicorn server:app --host 0.0.0.0 --port $PORT# Copy only project metadata first for better layer cachingCOPY pyproject.toml ./COPY README.md ./COPY LICENSE ./COPY uv.lock* ./# Install uv and minimal toolingRUN apt-get update -y \&& apt-get install -y --no-install-recommends curl ca-certificates \&& rm -rf /var/lib/apt/lists/* \&& curl -LsSf https://astral.sh/uv/install.sh | shWORKDIR /appFROM python:3.14-slim
services:db:image: mongo:latestrestart: alwaysenvironment:MONGO_INITDB_ROOT_USERNAME: mangoMONGO_INITDB_ROOT_PASSWORD: bangoMONGO_INITDB_DATABASE: beatsprofiles:- devdb_test:image: mongo:latestrestart: alwaysenvironment:MONGO_INITDB_ROOT_USERNAME: mangoMONGO_INITDB_ROOT_PASSWORD: bangoMONGO_INITDB_DATABASE: beats_testports:- "27018:27017"profiles:- testapi:image: ptc:latestbuild:environment:PORT: 80DB_DSN: mongodb://mango:bango@db/?authSource=adminenv_file:ports:volumes:depends_on:- dbprofiles:- devapi_test:image: ptc:latestbuild:context: ..dockerfile: ops/Dockerfileenvironment:PORT: 80DB_DSN: mongodb://mango:bango@db_test/?authSource=adminenv_file:- ../.env.testvolumes:- ../src:/srcdepends_on:- db_testprofiles:- test- ../src:/src- "7999:80"- ../src/.envcontext: ..dockerfile: ops/Dockerfileversion: "3.9"
version: "3.9"services:# MongoDB for developmentdb:image: mongo:8container_name: beats-dbrestart: unless-stoppedenvironment:MONGO_INITDB_ROOT_USERNAME: mangoMONGO_INITDB_ROOT_PASSWORD: bangoMONGO_INITDB_DATABASE: beatsvolumes:- mongo_data:/data/dbports:- "27017:27017"networks:- beats-networkprofiles:- devhealthcheck:test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quietinterval: 10stimeout: 5sretries: 5# MongoDB for testing (separate instance)db_test:image: mongo:8container_name: beats-db-testrestart: unless-stoppedenvironment:MONGO_INITDB_ROOT_USERNAME: mangoMONGO_INITDB_ROOT_PASSWORD: bangoMONGO_INITDB_DATABASE: beats_testports:- "27018:27017"networks:- beats-networkprofiles:- testhealthcheck:test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quietinterval: 10stimeout: 5sretries: 5# API service for developmentapi:image: beats-api:latestcontainer_name: beats-apibuild:context: .dockerfile: Dockerfileargs:- BUILDKIT_INLINE_CACHE=1environment:PORT: 8000DB_DSN: mongodb://mango:bango@db:27017/?authSource=adminDB_NAME: beatsenv_file:- .envports:- "7999:8000"volumes:# Mount source for hot-reloading in development- ./src:/app/src:rodepends_on:db:condition: service_healthynetworks:- beats-networkprofiles:- devrestart: unless-stoppedhealthcheck:test: ["CMD", "curl", "-f", "http://localhost:8000/health"]interval: 30stimeout: 10sretries: 3start_period: 10s# API service for testingapi_test:image: beats-api:latestcontainer_name: beats-api-testbuild:context: .dockerfile: Dockerfileenvironment:PORT: 8000DB_DSN: mongodb://mango:bango@db_test:27017/?authSource=adminDB_NAME: beats_testBEATS_TEST_ENV: "1"env_file:- .env.testvolumes:- ./src:/app/src:rodepends_on:db_test:condition: service_healthynetworks:- beats-networkprofiles:- testrestart: "no"networks:beats-network:driver: bridgename: beats-networkvolumes:mongo_data:name: beats-mongo-data
ops: # use this to install packages, and run system operationsdocker compose -f ops/compose-ops.yml run --rm api bash
test:docker compose --profile test build api_testdocker compose --profile test run --rm api_test uv run --group dev pytest -q
test:docker compose -f ops/docker-compose.yml --profile test build api_testdocker compose -f ops/docker-compose.yml --profile test run --rm api_test uv run --group dev pytest -q
test-cov:docker compose --profile test run --rm api_test uv run --group dev pytest --cov=beats --cov-report=term-missing
FROM python:3.14-slim# Prevents Python from writing pyc files and buffering stdout/stderrENV PYTHONUNBUFFERED=1ENV PYTHONDONTWRITEBYTECODE=1ENV PATH="/root/.local/bin:${PATH}"WORKDIR /app# Install uv package managerRUN apt-get update -y \&& apt-get install -y --no-install-recommends curl ca-certificates \&& rm -rf /var/lib/apt/lists/* \&& curl -LsSf https://astral.sh/uv/install.sh | sh# Copy dependency files first for better layer cachingCOPY pyproject.toml ./COPY README.md ./COPY LICENSE ./# Copy uv.lock if it exists (using wildcard to make it optional)COPY uv.lock* ./# Install runtime dependencies (no dev) using uv# --frozen uses exact versions from lock file, fallback to --no-dev if no lockRUN uv sync --no-dev --frozen 2>/dev/null || uv sync --no-dev# Copy application sourceCOPY src/ ./src/# Set working directory to app root (not src)WORKDIR /app# Default portENV PORT=8000EXPOSE ${PORT}# Health checkHEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \CMD curl -f http://localhost:${PORT}/health || exit 1# Use uv to run the server with the project virtualenvCMD uv run uvicorn server:app --host 0.0.0.0 --port ${PORT} --app-dir src
# Python__pycache__/*.py[cod]*$py.class*.so.Python*.egg-info/dist/build/*.egg# Virtual environments.venv/venv/ENV/env/# IDEs.vscode/.idea/*.swp*.swo*~# Testing.pytest_cache/.coveragehtmlcov/.tox/# Environment files.env.env.local.env.*.local# Git.git/.gitignore.gitattributes# Documentation*.md!README.md# Terraformterraform/# Operations (old directory)ops/# Compose override filescompose.override.ymlcompose.*.ymldocker-compose.override.ymldocker-compose.*.yml# CI/CD.github/# Logs*.loglogs/