39 lines
3.7 KiB
Markdown
39 lines
3.7 KiB
Markdown
# 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.
|