Files
office365-self-service/AGENTS.md

3.7 KiB

AGENTS.md

Stack And Entry Points

  • Single-package Flask app. Runtime entrypoint is app.py, which exposes app = create_app() for Gunicorn and local runs.
  • App wiring lives in office365_self_service/__init__.py: settings load first, logging is configured, SQLite directories are created if needed, db.create_all() runs during app startup, and blueprints from office365_self_service/routes.py are registered there.
  • Core behavior is split by file: routes.py handles both HTML pages and JSON APIs, services.py contains Office 365 business logic, graph.py wraps Microsoft Graph calls, and models.py defines the SQLite-backed SQLAlchemy models.

Commands

  • Create a local env and install deps with python3 -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt.
  • Run locally with python3 app.py.
  • Run the test suite with python3 -m unittest.
  • Run one test class with python3 -m unittest tests.test_app.AppRouteTests.
  • Run one test method with python3 -m unittest tests.test_app.AppRouteTests.test_redeem_marks_code_used_and_prevents_second_use.
  • Container flow is docker compose up -d --build, with healthcheck hitting http://localhost:8000/api/health.

Verified Repo Conventions

  • There is no configured linter, formatter, typechecker, pytest, or task runner in this repo. Do not invent pytest, ruff, mypy, npm, or make workflows.
  • Tests use the standard library unittest module in tests/test_app.py.
  • The Docker image runs Gunicorn via gunicorn -w 2 -b 0.0.0.0:8000 app:app; local development uses Flask's built-in server from app.py.

Config And Data Gotchas

  • Copy .env.example to .env before running locally or via Docker Compose.
  • Graph readiness is configuration-driven in office365_self_service/settings.py. Missing CLIENT_ID, TENANT_ID, CLIENT_SECRET, or DEFAULT_PASSWORD does not stop app startup, but service calls fail later with configuration errors.
  • WEB_AUTH_ENABLED=true only enables real admin login protection when both ADMIN_USERNAME and ADMIN_PASSWORD are set. Otherwise settings downgrade to effectively unauthenticated admin APIs and emit a warning.
  • Relative SQLite URLs such as sqlite:///redemption.db resolve through Flask into instance/redemption.db.
  • If DATABASE_URL is set to a container path like sqlite:////app/data/redemption.db outside Docker, settings automatically remap it to the matching local repo path and record a warning.
  • App startup creates tables automatically with db.create_all(). There are no migrations in this repo.
  • Logs are written to logs/office365_self_service.log via a rotating file handler during app startup.

API And Behavior Notes

  • Public health/config endpoints are /api/health and /api/config. Admin also has /admin/api/health, /admin/api/session, and authenticated config/data endpoints under /admin/api/*.
  • Redemption is stateful in the database: codes move available -> processing -> used, and failures release codes back to available.
  • Username handling is easy to guess wrong: plain usernames are lowercased and expanded with DEFAULT_DOMAIN; full UPNs are accepted as-is. If DEFAULT_DOMAIN is empty, callers must submit a full email address.
  • License assignment is optional. When DEFAULT_LICENSE_SKU is set and LICENSE_ASSIGNMENT_REQUIRED=true, failed license assignment triggers deletion of the newly created user and surfaces an error instead of a warning.

Editing Guidance

  • Preserve the app-factory shape and the service_factory injection seam in create_app(). Tests rely on injecting fake services there.
  • Keep focused verification lightweight: for most backend changes, run the relevant python3 -m unittest target rather than assuming extra tooling exists.