# Continuity ledger (per-branch)

## Human intent (must not be overwritten)

<!--
Write 1–5 bullets capturing the human goal and motivation.
This section is intentionally stable: do not overwrite it when updating the ledger.
-->

- Move API Publishing key management implementation from SDK packages into Studio app (`apps/studio.giselles.ai/lib/api-keys`), while keeping the existing SDK code in place for now.
- Adjust Studio UI/API as needed to use the new app-side implementation.

## Goal (incl. success criteria)

- Create `apps/studio.giselles.ai/lib/api-keys` with ported API key management logic and integrate it with Studio UI/API, without removing SDK implementations.

## Constraints/Assumptions

- Keep `packages/protocol` and `packages/giselle` API publishing code intact (deprecated but still present).
- Follow existing naming/layout conventions and keep changes minimal.

## Key decisions

- 

## State

- API keys are now stored in Postgres (`api_secret_records`) with scrypt params and metadata; `lib/api-keys` works directly against the DB.
- Team settings API keys page reads/writes real data (create + revoke + show-once token).
- Public run route verifies tokens against the DB-backed records.

## Done

- Added `api_secret_records` Drizzle schema + migration (scrypt params, metadata, indexes, FKs).
- Rebuilt `lib/api-keys` CRUD to use DB-backed records, single-active-per-app revoke, and best-effort `lastUsedAt`.
- Swapped `/api/apps/[appId]/run` token verification to the DB-backed verifier.
- Adjusted `/api/apps/[appId]/run` to return 401 (not 404) when the appId is missing, so unauthenticated requests can't infer app existence (matches pre-change behavior).
- Wired `/settings/team/api-keys` to live data via server actions (app picker, optional label, show-once token, revoke action).
- Refactored `/settings/team/api-keys` mutations to use form-based Server Actions (`useActionState` + `revalidatePath`) and removed manual `router.refresh()` calls.
- Added `api_secret_records.redacted_value` (NOT NULL) storing a pre-redacted token like `<first6>...<last3>` for OpenAI-style identification without exposing the full secret.
- Dropped the `gsk_` token prefix because `ApiKeyId` already carries an `apk_` prefix; token format is now `<apiKeyId>.<secret>`.
- `pnpm tidy` (knip) cleanup: removed unused exports from `apps/studio.giselles.ai/lib/api-keys` (dropped dead barrel exports, made `parseApiToken` internal, removed unused `getCurrentApiSecretRecordForTeam`).

## Now

- Monitor for follow-up coverage/docs for the new DB-backed API key flow.

## Next

- Add unit/API coverage around DB-backed api key create/verify/revoke.
- Document the new show-once UX + token format in Studio docs.

## Open questions (UNCONFIRMED if needed)

- 

## Working set (files/ids/commands)

- `apps/studio.giselles.ai/lib/api-keys/api-secrets.ts`
- `apps/studio.giselles.ai/lib/api-keys/schema.ts`
- `apps/studio.giselles.ai/lib/api-keys/token.ts`
- `apps/studio.giselles.ai/lib/api-keys/index.ts`
- `apps/studio.giselles.ai/app/api/apps/[appId]/run/route.ts`
- `apps/studio.giselles.ai/app/(main)/settings/team/api-keys/*`
- `apps/studio.giselles.ai/db/schema.ts` + `db/migrate/0076_steady_api_secret_records.sql`