Skip to platform overview
Features & architecture

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

For fans

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.

Gated

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.

Product rules

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.

How the platform works

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

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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

  1. 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.

  2. 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.

  3. 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.

Source onboarding

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. 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. 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. 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. 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
Operator control
source healthentity reviewfield authorityprotected corrections

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