A Python and Playwright workflow automation for scheduling and reservation style flows. It evaluates the automation boundary, runs safely with a default dry run, selects a slot from configured preferences, and captures evidence for a reliable handoff.
FlowReserve is a deterministic local demo application included in this repository. It is the target used to prove the automation design. It is vendor neutral and is not connected to any real booking service.
- Assessing a multi step workflow and choosing an appropriate automation boundary between a permitted API path and browser automation.
- Building maintainable automation with typed configuration, page objects, a clear selection rule, retries, and a provider neutral notification interface.
- Testing thoroughly across unit, integration, and end to end levels.
- Producing real evidence: screenshots, Playwright traces, and an Allure report.
- Documenting and packaging the result for a professional handoff.
A completed reservation in the FlowReserve demo application:
Availability results with the best matching slot highlighted:
The Allure overview from this project's passing test run:
- Configurable preferences through YAML, with environment overrides for connection details and secrets.
- Safe
dry_runmode enabled by default. The runner plans an action without committing it. - An automation boundary decision model that inspects the target first and prefers a permitted API path when it is available and appropriate.
- An extension seam (
ApiClient) for a real, permitted API behind the same interface the browser path uses. - Resilient
data-testidselectors and explicit waits in the page objects. - Retry handling for transient failures with exponential backoff.
- Structured logging that redacts secrets.
- Screenshots and Playwright traces captured on failure.
- A provider neutral notification interface with console and no-op notifiers.
flowchart TD
A["YAML preferences + environment"] --> B["Configuration and validation"]
B --> C{"Automation boundary"}
C -->|"Permitted API available"| D["API client path"]
C -->|"UI state / fallback"| E["Playwright page objects"]
D --> F["Reservation selection logic"]
E --> F
F --> G{"Dry run?"}
G -->|"yes (default)"| H["Plan only, commit nothing"]
G -->|"no"| I["Create reservation with retry"]
I --> J["Confirmation, screenshots, trace"]
H --> K["Provider-neutral notification"]
J --> K
An SVG and PNG version of this diagram are in docs/assets/architecture.svg and
docs/assets/architecture.png.
The design separates configuration and validation, the automation boundary decision, browser interaction through page objects, the reservation selection rule, the notification interface, artifact and logging support, and the demo application state.
The runner does not hardcode a layer. It decides with three steps:
- Inspect the target for an advertised, permitted capability. Here that is the
FlowReserve
/api/capabilitiesendpoint. - Prefer a stable API path when it is supported and appropriate.
- Use Playwright for the browser workflow when the API is unavailable or unsuitable because of UI state, sessions, or anti-forgery controls.
The mode is configurable (auto, api, browser). In auto the runner records
a readable reason for the path it chose. This model is demonstrated against the
local demo application only. See docs/adr/0001-automation-boundary.md.
- Python 3.11 or newer
- FastAPI and Jinja2 for the FlowReserve demo application
- Playwright for Python for browser automation
- pytest, pytest-playwright, and allure-pytest for tests and reporting
- Pydantic and Pydantic Settings for typed, validated configuration
- Ruff for linting and formatting
- GitHub Actions for CI and Allure on GitHub Pages
src/
flowreserve_demo/ FastAPI demo app: HTML flow, JSON API, templates, CSS
workflow_automation/ Config, decision model, selection, API + browser paths
tests/
unit/ Pure logic: selection, config, retry, notifications
integration/ Live API and runner tests, no browser
e2e/ Playwright tests against the running UI
config/
preferences.yaml Non secret preferences and operational defaults
scripts/ Screenshot and asset capture, scheduling templates
docs/
adr/ Architecture decision record
assets/ Screenshots and diagrams
.github/workflows/ CI and Pages deployment
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
python -m playwright install chromium
cp .env.example .envpython -m flowreserve_demo
# open http://127.0.0.1:8000 (sign in with demo.member / Demo-Pass-123)FlowReserve is deterministic. Availability is derived from a stable hash of the date and time, the venue is closed on Mondays, and party size is limited to 1 through 8. These rules give the automation reliable success, no availability, and validation cases to exercise.
The runner is safe by default. With dry run on it plans without booking.
# Plan only (dry run)
flowreserve-run --config config/preferences.yaml
# Commit a reservation
flowreserve-run --config config/preferences.yaml --execute
# Force a boundary
flowreserve-run --mode api --execute
flowreserve-run --mode browser --executeSet credentials in the environment before executing:
export FLOWRESERVE_USERNAME=demo.member
export FLOWRESERVE_PASSWORD=Demo-Pass-123preferences:
date: "+14d" # absolute YYYY-MM-DD, or a relative offset from today
party_size: 2
window_start: "09:00"
window_end: "12:00"
preferred_time: "10:00" # optional; selection prefers the closest slot
membership: "member" # standard | member | premium
participants:
- "Jordan Casey"
target:
base_url: "http://127.0.0.1:8000"
username: "demo.member"
# password comes from FLOWRESERVE_PASSWORD, never from this file
execution:
dry_run: true # default safe mode
automation_mode: "auto" # auto | api | browser
headless: true
max_attempts: 3
backoff_base_seconds: 0.5Dry run is the default. The runner authenticates, reads availability, and
selects a slot, then reports the slot it would book and stops before committing.
Use --execute (or set dry_run: false) only when you intend to make a real
reservation. This keeps repeated and scheduled runs safe.
# Everything
pytest
# Fast smoke checks
pytest -m smoke
# Broader regression coverage
pytest -m regression
# By level
pytest -m unit
pytest -m integration
pytest -m e2eThe end to end tests start the demo application automatically and drive it with Playwright using the same page objects the automation ships.
Generate Allure results and an HTML report locally:
pytest --alluredir=allure-results
allure generate allure-results -o allure-report --clean
allure open allure-reportA successful end to end run attaches a confirmation screenshot to Allure, so the
completed workflow is visible to nontechnical reviewers, not only failure
evidence. On a browser failure the runner writes a screenshot and a Playwright
trace under artifacts/.
Both options call scripts/run_workflow.sh, which activates the environment and
runs the configured workflow.
macOS launchd:
cp scripts/com.flowreserve.workflow.plist ~/Library/LaunchAgents/
# edit the absolute paths inside the file, then:
launchctl load ~/Library/LaunchAgents/com.flowreserve.workflow.plistcron:
30 7 * * * /ABSOLUTE/PATH/scripts/run_workflow.sh >> /tmp/flowreserve.log 2>&1The GitHub Actions pipeline in .github/workflows/ci.yml:
- installs dependencies and Playwright Chromium,
- runs Ruff linting and the full test suite,
- produces Allure results and an HTML report,
- uploads test artifacts including screenshots and traces,
- publishes the Allure report to GitHub Pages on
mainusing the official Pages actions (configure-pages,upload-pages-artifact,deploy-pages).
A documented automation package, a runnable demo target, a test suite, a CI
pipeline with a published report, configuration examples, and scheduling
templates. See docs/handoff.md for the full guide, including where to extend
the project for a real, permitted target.
- FlowReserve is a local demo target, not a real booking service. The project has not analyzed any external platform.
- The decision model and both automation paths run against the local demo only.
- Demo credentials are seed data for the demo app. Real deployments must source secrets from the environment.
- This project must not be used to automate against a third party service without explicit authorization. It does not bypass access controls or terms.
MIT. See LICENSE.


