# AI-assisted project & design entry — setup

Any signed-in Woodworking Wall user can add a project or design to their own account by describing it to Claude.

- **Claude** connects via OAuth login — no token to generate. Click Connect, log in to Woodworking Wall (or you're already logged in), approve access, done.

Backed by `api/mcp.js` (MCP — one merged connector covering both projects and Designer designs; identity resolved from a Supabase OAuth access token via `resolveUserFromOAuthToken` in `api/_lib/projects.js`), writing through the Supabase service role key. Designer-specific logic (schema, examples, validation, `designs` table CRUD) lives in `api/_lib/designer.js`.

## 1. One-time site setup (you, the site owner)

1. Run the SQL in `supabase_setup.sql` in the Supabase SQL editor.
2. Supabase dashboard → **Settings → API** → copy the **service_role** secret key. This is a full-access key — never put it in client-side code or commit it.
3. Vercel project → **Settings → Environment Variables** → add `SUPABASE_SERVICE_ROLE_KEY` with that value. Redeploy.
4. Supabase dashboard → **Authentication → OAuth Server** → enable OAuth 2.1 Server (public beta, free during beta on all plans). Set the authorization page URL to `https://YOUR-DOMAIN/oauth-consent.html` and turn on dynamic client registration, so Claude.ai (and any future MCP client) can register itself the first time a user connects, with no manual per-client setup on your end. The cloud dashboard's exact field labels may differ slightly from this description since the feature is in beta.

That's the only server secret this feature needs — no per-user configuration on your end.

## 2. Per-user setup (any signed-in user, repeatable, done in-product)

### Claude.ai custom connector

1. Sign in and go to your profile page (`user.html`). Under **Connect Claude**, copy the connector URL (`https://YOUR-DOMAIN/api/mcp`) — it's a fixed URL, no token embedded.
2. claude.ai → **Settings → Connectors → Add custom connector**, paste that URL, save.
3. Claude will redirect you to Woodworking Wall to log in (if you aren't already) and approve access on `oauth-consent.html`. Approve it — Claude.ai then holds a short-lived OAuth token it refreshes on its own; there's nothing to copy or store.
4. In a chat, ask Claude to list its tools — confirm all nine show up:
   - `add_woodworking_project` — add a new project (defaults to private).
   - `list_woodworking_projects` — search/browse your own projects (by text query or year); returns each project's `id`, which `update_woodworking_project` needs.
   - `update_woodworking_project` — change fields on an existing project by `id`. Only the fields you pass are changed; everything else is left alone.
   - `get_schema` — the Designer's authoritative project schema (`spec.yaml`).
   - `list_examples` — known-good example DesignerProject JSON files.
   - `validate_project` — validates a DesignerProject JSON object against the schema.
   - `add_design` — save a new design to your account (validated against the schema; rejected if invalid).
   - `list_designs` — search/browse your own saved designs; returns each design's `id`, which `update_design` needs.
   - `update_design` — change a saved design's title and/or data by `id` (data, if provided, is re-validated).
5. Try a test add, then a list, then an update, for both projects and designs, to confirm everything works end to end.

## Revoking access

- **Claude**: removing the connector from Claude.ai's Settings → Connectors stops it from being used, but doesn't necessarily invalidate a token Claude.ai is still holding server-side. Changing your Woodworking Wall password invalidates existing sessions and should force re-authorization. Supabase's OAuth 2.1 Server may add an end-user-facing "connected apps" revocation view as it comes out of beta — worth checking Supabase's docs if you need a harder guarantee than that.

## Notes

- Projects created this way always land on **your own** wall — the Claude OAuth login resolves to your account server-side, there's no way to specify a different user.
- Every project defaults to **private** unless `isPrivate: false` is explicitly set.
- **`partsUsed` is a structured list, not free text**: `[{ "name": "Walnut board", "cost": 45.99, "quantity": 2 }, ...]`. `cost` is per unit (defaults to 0), `quantity` defaults to 1 - each part contributes `cost * quantity` to the computed total.
- **`costMode` (`"manual"` or `"computed"`) controls whether cost is typed or summed from parts** — it's an explicit, independent choice, not implied by whether `partsUsed` is empty. `"computed"` requires a non-empty `partsUsed` in that same call (on `update_woodworking_project`, that means both fields together, even if only the parts changed). If `costMode` is omitted entirely, the old implicit rule still applies for compatibility: non-empty `partsUsed` defaults to `"computed"`, otherwise `"manual"`.
- **Image upload is experimental.** `add`/`update` both accept optional `imageBase64` (+ `imageMimeType`, defaulting to `image/jpeg`) and will upload it to Supabase Storage if provided. Whether Claude actually populates this from an uploaded photo is unconfirmed — language models generally can't transcribe exact file bytes from an image they've only seen visually, so this may simply never get filled in during normal chat use. If it's absent, `image` is left blank and you add a photo later from the web UI, same as before.
- `update_woodworking_project` can only ever touch a project that belongs to the caller's own account — it's scoped by `id` AND `user_id` together, so a wrong or guessed id just fails with "no project with that id exists on your wall" rather than touching someone else's data.
- There's still no delete tool anywhere — a bad call can add junk or edit a field wrong, but can never remove an existing project or design.
- Designs work the same way, scoped by `id` AND `user_id`. `add_design`/`update_design` validate `data` against the Designer's schema (`spec.yaml`, same as `validate_project`) and reject the call with the schema errors if it doesn't pass, instead of saving something the Designer UI can't load.
- Designs saved this way show up in the Designer's **Saved Builds** panel (`designer/index.html`) for that same signed-in account, and vice versa — designs saved from the Designer UI are reachable via `list_designs`/`update_design`.
