---
name: connect-to-humand-api
description: >
  Installs the authenticated PostgREST proxy and frontend client to read Humand data (employees, departments, etc.) via the views-cx service. Requires add-login to be installed first.
allowed-tools: Bash Read Write Edit
metadata:
  category: Implementation
---

# connect-to-humand-api

Installs a PostgREST proxy and a typed frontend client so the project can
read Humand data through the `views-cx` service.

## Precondition — verify add-login is installed

Before doing anything, check that `api/auth/_lib.ts` exists:

```bash
ls api/auth/_lib.ts 2>/dev/null && echo "ok" || echo "missing"
```

If the file is missing, stop and tell the user:

> "To connect to Humand's API you need to add a login page first
> Run the `add-login` skill and then run this skill again."

Do not proceed until the precondition is met.

## What this skill does

1. Creates `api/postgrest/[...path].ts` — authenticated proxy that forwards GET requests to PostgREST.
2. Creates `api/postgrest/index.ts` — re-exports the catch-all handler so Vercel resolves `/api/postgrest` (root path) correctly.
3. Creates `src/services/postgrest.ts` — typed frontend client with `get`, `getOne`, and `discover`.
4. Adds required env var to `.env.example`.

## Instructions

### Step 1 — Copy templates and patch env, vite.config.ts, and .gitignore

Run all scripts:

```bash
bun ${CLAUDE_SKILL_DIR}/scripts/install-files.ts
bun ${CLAUDE_SKILL_DIR}/scripts/patch-env.ts
bun ${CLAUDE_SKILL_DIR}/scripts/patch-vite-config.ts
bun ${CLAUDE_SKILL_DIR}/scripts/patch-gitignore.ts
```

If `patch-vite-config.ts` exits with code **2** (`NEEDS_MANUAL_MERGE`), read `vite.config.ts` and manually insert the `/api/postgrest` entry inside the existing `proxy` object. The script output includes the exact snippet to add.

### Step 2 — Report to user

Tell the user:
- Which files were created.
- That they need to add `POSTGREST_BASE_URL` to Vercel for production (`.env.local` was already patched by the script).
- How to use the client:

```ts
import { postgrest } from '../services/postgrest';

// List with pagination
const { data } = await postgrest.get('/employees', { limit: '20' });

// Single record
const employee = await postgrest.getOne('/employees', { id: 'eq.42' });

// Discover available entities
const entities = await postgrest.discover();
```

## How the proxy works

```
Browser → /api/postgrest/<entity>?<filters>
  ↓
api/postgrest/[...path].ts
  → resolveSession() reads cookies from the request
  → if no valid session → 401
  → forwards GET to POSTGREST_BASE_URL/<entity>
    with Authorization: Bearer <access_token>
  → returns response (including Content-Range header for pagination)
```

The proxy:
- Only allows GET requests.
- Validates the path (no `..` traversal).
- Silently renews expired tokens and forwards new cookies to the browser.
- Forwards query params (filters, ordering, etc.) to PostgREST verbatim.

## Frontend client API

| Function | Returns | Use for |
|---|---|---|
| `postgrest.get<T>(path, params?)` | `{ data: T[], contentRange: string \| null }` | Paginated lists |
| `postgrest.getOne<T>(path, params?)` | `T` | Single record by primary key |
| `postgrest.discover()` | `EntityMeta[]` | Introspect available entities and their fields |

## Environment variables

| Variable | Side | Purpose |
|---|---|---|
| `POSTGREST_BASE_URL` | Server | Base URL of the Humand PostgREST service |
