# abler.io — kids' sports platform

Where the kids' sports live in Iceland: ÍR, Valur, Þróttur, Ármann and most
clubs run registrations, schedules, attendance and payments through Abler.
No public API — ops run inside an agent-browser session against the app's
GraphQL endpoint (`www.abler.io/graphql`), so the session cookies are the
credential.

```bash
ab-plus login abler.io                     # headed window → human logs in
ab-plus run abler.io/me
ab-plus run abler.io/event --input '{"id":"RXZlbnQ6NDQ0MDUwMw=="}'
ab-plus run abler.io/event-players --input '{"eventId":"…","ageGroupId":"…","paymentStatus":"Unpaid"}'
```

## Ops

| Op | Risk | Notes |
|---|---|---|
| `me` | read-only | Profile (name, ssn, email), children, their age groups + groups, your age-group roles. |
| `dashboard` | read-only | Organization view: the age groups/clubs the user manages. |
| `event` | read-only | One event by id: time, location, groups, coaches, attendance stats, your own status. |
| `event-players` | read-only | Per-player attendance + payment rows for an event; filter by `attendanceStatus` / `paymentStatus`, paginate with `first`. |

## Auth

**Handoff** — email sign-on in a headed agent-browser window (`/sign-on/login`),
session persists via `--session ab-abler-io --restore`. Ops POST the GraphQL
operations inside the page context via `eval`, so cookies and device-trust
state ride along; the session is not replayable from cookies alone.

## Gotchas

- **Parent vs coach view**: `me` returns children and their age groups for a
  parent; `dashboard` + `event-players` are the coach/organization surface.
  Member lists on group pages are permission-gated per role.
- **IDs are base64 of `Event:<id>` / `AgeGroup:<id>` / `UserProfile:<id>`** —
  take them from `me`, `dashboard`, or event URLs
  (`/event/<ageGroupId-b64>/<eventId-b64>`).
- **GraphQL introspection is disabled** server-side. If a field drifts, the
  queries are embedded in this recipe — re-capture from the app's client
  bundle (`/assets/client.*.js`) or a HAR of a page load
  (`agent-browser network har start/stop`).
- Status enums seen in the wild: attendance `Going` / `NotGoing` /
  `NotResponded` / `Empty`; `coachStatus` `Empty` for unanswered rows.
- Respect the site: this is a live club app — the reference recipe does one
  query per op, read-only, no mutations.
