Skip to content

Architecture

The pool has a Python background worker, a static browser client, and a separate documentation site. Storage connects the worker and the client; they do not call each other directly.

Resources and trust boundaries

flowchart TB
    subgraph Delivery[GitLab]
        Repo[Repository] --> Checks[Tests, lint, SBOMs, security]
        Checks --> WebDeploy[Static Web Apps deployment]
        Checks --> FunctionDeploy[Function ZIP deployment]
        Checks --> DocsDeploy[Pages publication]
    end
    subgraph Azure[Azure application resources]
        Timer[Hourly timer] --> Function[Python Function]
        ESPN[ESPN API] --> Function
        Function <--> State[Private pool-state container]
        Function --> Public[Public results in Blob Storage]
        Function --> ACS[Communication Services Email]
        WebDeploy --> SWA[Static Web Apps]
        FunctionDeploy --> Function
    end
    SWA --> Browser[Visitor browser]
    Public --> Browser
    Browser --> Sentry[Sentry browser error reporting]
    ACS --> Inbox[Recipient inbox]
    DocsDeploy --> Pages[Documentation on GitLab Pages]
ComponentResponsibilitySource
Timer entry pointRegisters check_pool and invokes the schedulerfunction_app.py
SchedulerActive-season checks, kickoff cache, processing, delivery claimsapp/scheduler.py
ESPN clientSchedule and final-score retrieval with bounded requestsapp/espn.py
Pool rulesSquare ownership and per-week digit assignmentsapp/pool.py
Report builderPublic snapshot, winner lookup, summary contentapp/service.py
State storeConditional writes to private season stateapp/state.py
PublisherLatest and UTC-day JSON snapshotsapp/storage_publish.py
Email and templatesACS submission, HTML/plain-text renderingapp/emailer.py, app/templates/
Browser clientPlayer selector, schedule, board, resultspublic/
Browser monitoringJavaScript errors, environment, and deployed releasepublic/sentry.js, ci/swa/configure-sentry.cjs
DocumentationSearchable maintenance guides and Mermaid diagramsdocs/, ci/docs/astro.config.mjs

Storage has two roles

Function host storage supports the Azure Functions runtime and timer coordination. Azure configures it through AzureWebJobsStorage.

Results storage is selected by RESULTS_STORAGE_CONNECTION_STRING and holds:

PathAccessContents
$web/results.jsonPublic read for the websiteLatest public pool snapshot
$web/history/YYYY-MM-DD.jsonPublic readMost recent snapshot written on that UTC day
pool-state/<season>.jsonPrivateSchedule cache, results, publication and email markers

These roles may use the same storage account, but they are separate settings. The application creates pool-state when needed and rejects public access to that container. It does not create the $web container for you.

The daily history path is overwritten when another publication occurs on the same UTC day. It is not an append-only audit log or a backup of private state.

Public data boundary

The public snapshot includes player IDs, display names, squares, digit assignments, verified game results, and earned-prize totals. It excludes email addresses and notification flags. Private season state contains processing and delivery markers and must not be copied into the public container or documentation output.

The documentation build reads docs/ only. It does not include the roster PDF, private state, player contact records, or local environment files.

Independent release paths

  • Changing public/ deploys the browser client to Static Web Apps.
  • Changing Function source or runtime dependencies deploys the Python ZIP.
  • Updating pool/player configuration requires a Function deployment; the next active-season invocation publishes changed public data.
  • The documentation is built into docs-site/ and published to GitLab Pages.

See the pipeline guide for exact jobs and deployment triggers.