---
id: 03-workspaces-feature-core
epic: walking-skeleton
title: workspaces feature core — connect, status, list + encrypted credential storage
type: user-story
status: todo
feature: workspaces
depends-on: []
blocks:
  [
    06-runner-provisioner-port,
    07-runner-lifecycle-events-and-realtime,
    10-web-next-wiring,
  ]
created: 2026-07-12T10:24:14Z
---

## Goal

Ship the minimal `workspaces` feature: `connectWorkspace` (name + git URL + PAT, audited), `getWorkspaceStatus`, `listWorkspaces`, and a Workspaces Payload collection whose PAT field is encrypted at rest and write-only — so a signed-in user can connect a repository by git URL + token (PRD user story 1).

## Why

The workspace is the root entity of the entire skeleton: provisioning (story 06), lifecycle events (story 07), and the web-next UX (story 10) all hang off it. Credential handling is the security-critical part and must land with the collection, not be retrofitted: PAT stored encrypted AES-256-GCM with a scrypt-derived key from `VEECT_SECRET`, decrypted only server-side, never returned by the Payload API (PRD Implementation decisions; tech spec §13).

## Done when

- `pnpm turbo gen feature workspaces` scaffold is green.
- `connectWorkspace` (`mutates: true`, `audits: ["workspace-connected"]`), `getWorkspaceStatus`, and `listWorkspaces` are declared in `feature.manifest.ts`, implemented manifest-first with contracts, unit tests (mocks injected directly), DI wiring, and tRPC procedures.
- Workspaces Payload collection stores the PAT encrypted AES-256-GCM (scrypt key derivation from `VEECT_SECRET`); the field is write-only — no API read path returns it.
- Repository contract suite runs against both the mock and the Payload impl, including the write-only credential behavior (PRD Testing decisions).
- No use-case output schema ever includes the credential.
- Coverage bands: template defaults (PRD Implementation decisions — use cases are thin orchestration).
- Boot assertion (`assertFeatureConformance`) green in dev-seed mode.
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass after each task.

## In scope

- Feature scaffold, three use cases, manifest declarations, audit emission for `connectWorkspace`.
- Workspaces Payload collection + real repository + encrypted write-only credential field.
- Repository contract suite (mock + Payload).
- Dev-seed binder (`__seeds__/dev.ts`) so `pnpm dev` boots without Payload.

## Out of scope

- Runner provisioning + lifecycle status events (stories 06–07) — `getWorkspaceStatus` returns persisted state only in this story.
- The manifest's `publishes` / realtime declarations (story 07).
- Connect UX (story 10); org walls, trust prompt, env manager (`workspaces-and-connections`).
- Real GitHub/GitLab connections beyond git URL + PAT.

## Tasks

- [ ] Run `pnpm turbo gen feature workspaces` → green feature scaffold (manifest, contracts, binders, controllers, tests, dev-seed).
- [ ] Add `connectWorkspace` use case — manifest entry (`mutates: true`, `audits: ["workspace-connected"]`), input schema (name + git URL + PAT), output schema (credential never included), red test → green impl, DI wiring with audit emission, tRPC procedure.
- [ ] Add the Workspaces Payload collection + real repository: PAT encrypted AES-256-GCM with a scrypt-derived key from `VEECT_SECRET`, write-only field (Payload API never returns it); repository contract suite covering mock + Payload impls incl. the write-only credential behavior.
- [ ] Add `getWorkspaceStatus` and `listWorkspaces` use cases — manifest entries, contracts, red tests → green impls, DI wiring, tRPC procedures — returning persisted workspace/runner status.
