# Tasks — add-api-plugin-user ## 1. Scaffold - [ ] 1.1 Create `packages/api/api-plugin-user/` with `src/{plugin,routes,services,schemas,schema,error-codes,otel,types}/` + `tests/{setup,integration}/` - [ ] 1.2 `package.json` v0.1.0. Deps: `@suaveplan/api-plugin` `@suaveplan/api-openapi` `@suaveplan/api-migrations` `@suaveplan/api-plugin-auth` `@suaveplan/error` `@suaveplan/types` `tslib`, `hono` `@hono/zod-openapi` (`catalog:server`), `zod` (`catalog:forms`), `@opentelemetry/api` - [ ] 1.3 10 subpath exports per the proposal - [ ] 1.4 tsconfigs + vite + vitest (100/100/100/100, testTimeout 60000 for integration) - [ ] 1.5 `tests/setup/polyfills.ts` ## 2. Implementation - [ ] 2.1 `src/error-codes.{ts,test.ts,md,index.ts}` — 7 USER.* codes + `UserError` - [ ] 2.2 `src/types/types.{ts,md,index.ts}` — `UserProfile`, `UserPluginOptions`, `UserPluginConfig` - [ ] 2.3 `src/schemas/options.{ts,test.ts,md,index.ts}` — `UserPluginOptionsSchema` - [ ] 2.4 `src/schemas/user-profile.{ts,test.ts,md,index.ts}` — `UserProfileSchema` (extends `PrincipalSchema` from `@suaveplan/api-plugin-auth/schemas/principal`), `UserProfileResponseSchema`, `UpdateUserProfileBodySchema` (strict mode) - [ ] 2.5 `src/otel/instruments.{ts,test.ts,md,index.ts}` — 3 counters - [ ] 2.6 `src/schema/schema.{ts,test.ts,md,index.ts}` — `USER_PROFILE_SCHEMA` template + `applyUserProfileSchema(adapter, profileFields)` helper. Genesis-original DDL using `DEFINE FIELD OVERWRITE` on the `user` table. - [ ] 2.7 `src/services/user-service.{ts,test.ts,md,index.ts}` — `UserService` interface + impl; ServiceRegistry augmentation - [ ] 2.8 `src/routes/build-routes.{ts,test.ts,md,index.ts}` — `buildUserRoutes(authService)` returning 3 `PluginRouteEntry` via `RouteBuilder`; all use `requireAuth()` upstream - [ ] 2.9 `src/plugin/plugin.{ts,test.ts,md,index.ts}` — `createUserPlugin(options)` factory; `dependencies: ["auth"]`; onInit applies schema → registers userService → registers routes - [ ] 2.10 `src/index.ts` — named re-exports only ## 3. Tests - [ ] 3.1 Co-located `*.test.ts` per spec scenario - [ ] 3.2 `src/api-plugin-user.spec-conformance.test.ts` — every USER.* code thrown; `expectTypeOf` on `UserService`; `UpdateUserProfileBodySchema` strict-mode pinned - [ ] 3.3 `tests/integration/full-boot.test.ts` — real `PluginRegistry` + `api-plugin-auth` + this plugin + SurrealDB testcontainer; sign-up → GET /users/me → PATCH → DELETE roundtrip - [ ] 3.4 `tests/integration/openapi-doc.test.ts` — served `/openapi.json` includes 3 `/users/me` routes with Zod-typed schemas - [ ] 3.5 `tests/property.test.ts` — fast-check 200 runs on `UpdateUserProfileBodySchema`: arbitrary keysets including extras → strict-mode rejects when extras present - [ ] 3.6 `tests/dep-graph.test.ts` - [ ] 3.7 All tests via `@suaveplan/testing/runner`, `{ timeout: 5000 }` (60000 for integration) ## 4. Documentation - [ ] 4.1 Sibling `.md` per impl (≥200 words) - [ ] 4.2 `README.md` — install + `defineApp().use(createAuthPlugin(...)).use(createUserPlugin(...))` example; `userService.getById` usage from downstream plugins; profileFields customisation; schema apply notes ## 5. Gates - [ ] 5.1 `bunx turbo lint typecheck test --filter=@suaveplan/api-plugin-user --force` - [ ] 5.2 Coverage 100/100/100/100 - [ ] 5.3 `bun scripts/openspec-conformance.ts @suaveplan/api-plugin-user` exit 0 - [ ] 5.4 Build green - [ ] 5.5 Banned-pattern + no `export *` + no direct runner imports ## 6. Archive - [ ] 6.1 Fold spec → `openspec/specs/api-plugin-user/spec.md` - [ ] 6.2 mv change → `openspec/archive/-add-api-plugin-user/` - [ ] 6.3 DO NOT refresh MANIFEST or STATUS — orchestrator consolidates