build: /spec-feature user-preferences --requirements 'CRUD API for user pref...
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
This commit is contained in:
parent
39d0dd5ae8
commit
b2e88a92a3
@ -22,7 +22,7 @@ artifacts:
|
||||
status: pending
|
||||
path: review.md
|
||||
spec:
|
||||
status: pending
|
||||
status: draft
|
||||
path: spec.md
|
||||
tasks:
|
||||
status: pending
|
||||
|
||||
77
.sdlc/features/user-preferences/spec.md
Normal file
77
.sdlc/features/user-preferences/spec.md
Normal file
@ -0,0 +1,77 @@
|
||||
# Feature: User Preferences API
|
||||
|
||||
## Problem Statement
|
||||
|
||||
Users of the platform need a way to persist and retrieve personal preferences (theme, language, notification settings) so their experience is consistent across sessions and devices. Currently, the `preferences-api` service exists as a scaffold with only example CRUD endpoints and no actual preference management capability.
|
||||
|
||||
## User Stories
|
||||
|
||||
- As an authenticated user, I want to retrieve my preferences so that the UI reflects my saved settings when I log in.
|
||||
- As an authenticated user, I want to update my preferences so that changes to theme, language, or notification settings are persisted.
|
||||
- As a frontend application, I want to fetch preferences for the current user so I can apply theme/language/notification configuration on page load.
|
||||
- As an admin or service, I want to retrieve preferences for a specific user by user ID so I can provide user-specific experiences in server-rendered contexts.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `GET /api/preferences-api/preferences/{user_id}` returns the user's preferences as a key-value map within the standard `{data, meta}` envelope
|
||||
- [ ] `PUT /api/preferences-api/preferences/{user_id}` creates or fully replaces the user's preferences (upsert semantics)
|
||||
- [ ] Both endpoints require authentication via the existing `auth.Middleware()`
|
||||
- [ ] Authenticated users can only access their own preferences (the `{user_id}` in the URL must match the JWT `UserID`/`Subject`)
|
||||
- [ ] Preferences are stored as key-value pairs with string keys and JSON-compatible values
|
||||
- [ ] The following preference keys are supported with validation:
|
||||
- `theme`: must be one of `"light"`, `"dark"`, `"system"`
|
||||
- `language`: must be a valid BCP-47 language tag (e.g., `"en"`, `"fr"`, `"es"`, `"de"`, `"ja"`)
|
||||
- `notifications.email`: must be a boolean
|
||||
- `notifications.push`: must be a boolean
|
||||
- `notifications.digest`: must be one of `"none"`, `"daily"`, `"weekly"`
|
||||
- [ ] `GET` for a user with no saved preferences returns a `200` with default values (not a 404)
|
||||
- [ ] Default preference values: `theme: "system"`, `language: "en"`, `notifications.email: true`, `notifications.push: true`, `notifications.digest: "weekly"`
|
||||
- [ ] `PUT` with unknown preference keys returns `400 Bad Request` with a descriptive error
|
||||
- [ ] `PUT` with invalid preference values returns `400 Bad Request` with per-field validation errors
|
||||
- [ ] Preferences are persisted in PostgreSQL (using the existing `DatabaseConfig`)
|
||||
- [ ] The domain layer contains pure preference models with validation logic, following hexagonal architecture
|
||||
- [ ] A `PreferenceRepository` port interface is defined, with a PostgreSQL adapter implementation
|
||||
- [ ] A `PreferenceService` orchestrates business logic between handler and repository
|
||||
- [ ] OpenAPI spec is updated to document both endpoints with schemas, examples, and error responses
|
||||
- [ ] Unit tests cover domain validation, service logic, and handler request/response mapping
|
||||
- [ ] Integration-style tests verify handler behavior using the in-memory repository adapter
|
||||
- [ ] The existing example CRUD scaffolding is removed and replaced with preference endpoints
|
||||
|
||||
## Technical Constraints
|
||||
|
||||
- **Architecture**: Must follow the established hexagonal architecture pattern (domain -> service -> port -> adapter) already present in `services/preferences-api/`
|
||||
- **URL parameters**: Must use brace syntax `{user_id}` (not `:user_id`) per chi router requirements
|
||||
- **Request binding**: Must use `app.Bind()` / `app.BindAndValidate()` -- never raw `json.NewDecoder`
|
||||
- **Error handling**: Handlers return `error`, wrapped with `app.Wrap()`. Use `httperror.BadRequest`, `httperror.NotFound`, `httperror.Forbidden` etc.
|
||||
- **Response format**: All responses use the `{data, meta}` envelope via `httpresponse.OK`, `httpresponse.Created`, etc.
|
||||
- **Auth identity**: User identity is extracted from JWT via `auth.GetUser(ctx)` which returns `*auth.User` with an `ID` field
|
||||
- **Database**: PostgreSQL, connection details via `config.DatabaseConfig` (environment variable `DATABASE_URL`)
|
||||
- **Port**: The service runs on port 8001 (default)
|
||||
- **Route prefix**: All routes must be under `/api/preferences-api/` to match ingress routing
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `pkg/auth` -- JWT middleware and `auth.GetUser()` for extracting authenticated user identity
|
||||
- `pkg/app` -- `app.Wrap()`, `app.Bind()`, `app.BindAndValidate()` for handler patterns
|
||||
- `pkg/httperror` -- Typed HTTP error constructors
|
||||
- `pkg/httpresponse` -- Response envelope helpers
|
||||
- `pkg/openapi` -- OpenAPI spec builder for documentation
|
||||
- `pkg/config` -- `DatabaseConfig` for PostgreSQL connection parameters
|
||||
- PostgreSQL database instance (local dev via `docker-compose` or `scripts/dev.sh`)
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- **Bulk operations**: No endpoint for fetching/updating preferences for multiple users at once
|
||||
- **Preference history/audit log**: No versioning or history of preference changes
|
||||
- **Real-time sync**: No WebSocket or push notification when preferences change on another device
|
||||
- **Custom/arbitrary preference keys**: Only the defined keys (theme, language, notifications.*) are supported -- extensibility is deferred
|
||||
- **DELETE endpoint**: Preferences are reset to defaults via `PUT`, not deleted
|
||||
- **Pagination**: Preferences are a fixed small set per user, no pagination needed
|
||||
- **Admin override**: No endpoint for admins to modify another user's preferences (admin read is permitted for server-rendered contexts but write is not)
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **Admin read access**: Should admin users (identified by a role in JWT) be allowed to read other users' preferences, or should the `{user_id}` always be strictly self-only? The spec currently allows admin read but this needs confirmation.
|
||||
2. **Preference key extensibility**: Should the API accept and store unknown preference keys (with a max key count limit), or strictly reject them? The spec currently rejects unknown keys.
|
||||
3. **Partial updates (PATCH)**: Should a `PATCH` endpoint be added for updating individual preference keys without sending the full set, or is `PUT` (full replace) sufficient for MVP?
|
||||
4. **Rate limiting**: Should preference updates be rate-limited to prevent abuse, or is auth sufficient protection?
|
||||
Loading…
Reference in New Issue
Block a user