Football plans,
grounded in evidence.
Goalaway helps travelling fans discover fixtures and official ticket information, then keeps those facts traceable from source to the app.
Matches People Places A brighter away day
What you can do today
Discover matches
Lists, calendar and map for first-launch leagues — English, Spanish, Italian, German and French top flights, plus UEFA.
Check official tickets
Phase status and a link to the club shop for clubs we actually scrape. Goalaway is not a reseller.
Follow fixtures
Watchlist and match detail with a timeline of appearance, kickoff changes and phase openings — in the app, not by email yet.
Build a trip
An ordered list of selected matches, dates and cities. Flights and hotels stay out of scope.
Detailed ticket phases and newer consumer flows are feature-gated.
Confirmed facts, with a trail
Official sources only
League feeds and club shops we can trace. Not resale listings, not a booking engine, not invented kickoffs.
Evidence before apply
Observations are retained, entities are resolved, then accepted facts land in Neon. Forecasts stay separate from confirmed facts.
Operators keep the keys
Source health, ambiguous clubs and venues, field authority and protected corrections stay in the admin console.
Official sources in, confirmed facts out
Collection is scheduled. Apps read through the BFF. Both lanes land in the same ledger.
Data ingestion
scheduled collection
Official sources
League feeds + club shops
Each source has a cadence and an adapter. We fetch the official schedule or ticket page — or the API that page actually uses — not a third-party feed.
Orchestrator
NestJS + scheduled dispatch
A minute cron finds due sources and enqueues work. The orchestrator owns dispatch only; it never parses HTML or writes fixtures.
Job queues
Redis + BullMQ
scrape-jobs for API and HTML, scrape-jobs-headless for Playwright, and a dead-letter queue after retries. The same idempotency key retries the same command.
Python workers
API / HTML / Playwright
Deterministic adapters fetch, then parse. No model in the live worker, no database writes from parse, and no invented kickoffs or sold-out guesses.
Evidence → resolution → apply
Retain observations • resolve entities
Raw captures and observations are stored first. External club and venue refs resolve through a mapping table; unknowns park for operators. Apply SQL writes behind per-field authority.
Application requests
Angular apps
Fan app (SSR) • Admin (CSR)
Shared auth, API client, map and theme. The fan app is server-rendered except map routes; admin is a client-rendered operator console.
nginx + API gateway
Edge routing into the platform
In production, nginx serves the apps and sends /api/v1 to the gateway, which proxies to the BFF. Locally the fan app talks to the BFF on port 4000.
NestJS BFF
Public & operator APIs
Catalog, tickets, watching, inbox, trips and admin-ops. Workers apply canonical facts; operator corrections use that same evidence path.
Neon Postgres
Fixtures • ticket phases • ledger
Current projections plus field provenance, the resolution queue, and the evidence behind every confirmed fact. Rebuilds only touch resolver-owned fields.
Skills write the scraper. MCP checks the ingest.
A Cursor skill turns an official schedule or ticket URL into a Goalaway source: discover, generate a deterministic adapter, then prove it. An internal MCP server wraps existing admin-ops APIs so the same agent can inspect evidence and request an authorized run. It is not a factory, not a live AI parser, and it cannot enable a source or merge identities.
- 1
Discover the official page
A Cursor skill probes the club or league URL, names the real schedule or ticket endpoint, and writes a discovery report before any adapter is generated.
- 2
Reuse a family, then generate
Most shops extend an existing HTML, API or Playwright family. A new Python adapter is the last resort, and parse stays deterministic — no model in the live worker.
- 3
Prove it on retained captures
Parser fixtures replay the captured body. Unknown ticket wording is queued, not guessed. Missing phases do not become sold out.
- 4
Validate through MCP
An internal MCP wraps admin-ops: inspect the source, request an authorized ingest, then read the run, observations, evidence and fixture coverage. A job finishing is not acceptance.
What MCP validates
Parser tests live in the repo. MCP checks the operational path after an authorized ingest.
- Source health, adapter and provenance
- Run outcome, diffs and parked apply
- Observation evidence (body present, not HTTP 200 alone)
- Unresolved identities and unmapped ticket wording
- Fixture coverage for that source, not catalog totals
Delivery
GitHub Actions → GHCR → Docker on Hetzner
Scope
Email / push alerts, forecasts and coefficients are outside the first launch.
Repository overview · 15 Sep 2026 · Implementation does not imply production rollout.
Football brings us further