3.7 KiB
3.7 KiB
AGENTS.md
Stack And Entry Points
- Single-package Flask app. Runtime entrypoint is
app.py, which exposesapp = 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 fromoffice365_self_service/routes.pyare registered there. - Core behavior is split by file:
routes.pyhandles both HTML pages and JSON APIs,services.pycontains Office 365 business logic,graph.pywraps Microsoft Graph calls, andmodels.pydefines 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 hittinghttp://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, ormakeworkflows. - Tests use the standard library
unittestmodule intests/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 fromapp.py.
Config And Data Gotchas
- Copy
.env.exampleto.envbefore running locally or via Docker Compose. - Graph readiness is configuration-driven in
office365_self_service/settings.py. MissingCLIENT_ID,TENANT_ID,CLIENT_SECRET, orDEFAULT_PASSWORDdoes not stop app startup, but service calls fail later with configuration errors. WEB_AUTH_ENABLED=trueonly enables real admin login protection when bothADMIN_USERNAMEandADMIN_PASSWORDare set. Otherwise settings downgrade to effectively unauthenticated admin APIs and emit a warning.- Relative SQLite URLs such as
sqlite:///redemption.dbresolve through Flask intoinstance/redemption.db. - If
DATABASE_URLis set to a container path likesqlite:////app/data/redemption.dboutside 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.logvia a rotating file handler during app startup.
API And Behavior Notes
- Public health/config endpoints are
/api/healthand/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 toavailable. - Username handling is easy to guess wrong: plain usernames are lowercased and expanded with
DEFAULT_DOMAIN; full UPNs are accepted as-is. IfDEFAULT_DOMAINis empty, callers must submit a full email address. - License assignment is optional. When
DEFAULT_LICENSE_SKUis set andLICENSE_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_factoryinjection seam increate_app(). Tests rely on injecting fake services there. - Keep focused verification lightweight: for most backend changes, run the relevant
python3 -m unittesttarget rather than assuming extra tooling exists.