---
id: w5/m4/t002
title: services.graphql query + codegen; wire home page to live services
worker: worker5
status: todo
estimate: 45m
depends_on: [w5/m4/t001]
---

## Objective

Add a `services` GraphQL query, generate typed operations via codegen, and replace the home page's hardcoded `sampleServices` with live data — computing the stat tiles from the real list. Consume the `Service` type exactly as Render shapes it.

## Context

- Home page: `src/routes/index.tsx` (`sampleServices` at lines ~34-54; stat tiles ~62-72).
- GraphQL codegen: `codegen.ts` introspects bex-api `/graphql` (needs `CODEGEN_SESSION_TOKEN`); output `src/graphql/definitions.ts`. Feature `.graphql` files live under `src/features/<name>/api/` (see `src/features/metrics/api/metrics.graphql`).
- Render `Service` shape (`docs/ADR006-bex-api.md`): string `suspended` enum, not boolean.

## Steps

1. Create `src/features/services/api/services.graphql` with the `services` query selecting the Render-shaped `Service` fields (+ bex extras `phase`/`replicas`/`revision`).
2. Run `yarn codegen` (with `CODEGEN_SESSION_TOKEN`) to regenerate typed operations.
3. Replace `sampleServices` in `src/routes/index.tsx` with a `useQuery` on the generated operation; compute stat tiles from the live result; keep the existing table/tile layout and metrics deep-link.
4. Map the string `suspended` enum through `phaseVariant`/status badge correctly.

## Files

- `src/features/services/api/services.graphql` (new)
- `src/graphql/definitions.ts` (regenerated)
- `src/routes/index.tsx`

## Acceptance criteria

- [ ] No `sampleServices` array remains in the tree.
- [ ] The home page list + stat tiles render from the live `services` query.
- [ ] The `suspended` field is consumed as Render's string enum, not a boolean.
- [ ] `yarn typecheck` passes.

## Out of scope

- Loading/error/empty states (t003), lifecycle actions (t004).
