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
c5a7a54a9d
commit
3624cb8e6d
@ -22,7 +22,7 @@ artifacts:
|
||||
status: pending
|
||||
path: review.md
|
||||
spec:
|
||||
status: pending
|
||||
status: draft
|
||||
path: spec.md
|
||||
tasks:
|
||||
status: pending
|
||||
|
||||
141
.sdlc/features/user-preferences/spec.md
Normal file
141
.sdlc/features/user-preferences/spec.md
Normal file
@ -0,0 +1,141 @@
|
||||
# Feature: User Preferences API
|
||||
|
||||
## Problem Statement
|
||||
|
||||
Users need a way to persist and retrieve their application preferences (theme, language, notification settings) so that their experience is consistent across sessions and devices. Currently, the `preferences-api` service contains only scaffold code with no preference management functionality.
|
||||
|
||||
## User Stories
|
||||
|
||||
- As a user, I want to save my theme preference (light/dark) so that the UI renders consistently across sessions.
|
||||
- As a user, I want to save my language preference so that the application displays content in my chosen language.
|
||||
- As a user, I want to configure my notification settings so that I only receive the notifications I care about.
|
||||
- As a user, I want to retrieve all my preferences in a single request so that the frontend can initialize quickly.
|
||||
- As a user, I want to update individual preferences without overwriting others so that partial updates are safe.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `GET /api/preferences-api/preferences/{user_id}` returns all preferences for the given user as key-value pairs
|
||||
- [ ] `GET /api/preferences-api/preferences/{user_id}` returns an empty preferences object (not 404) for users with no saved preferences
|
||||
- [ ] `PUT /api/preferences-api/preferences/{user_id}` creates or updates preferences for the given user (upsert semantics)
|
||||
- [ ] `PUT /api/preferences-api/preferences/{user_id}` supports partial updates — only provided keys are changed, omitted keys are preserved
|
||||
- [ ] Supported preference keys: `theme` (values: `light`, `dark`), `language` (ISO 639-1 codes, e.g. `en`, `es`, `fr`), `notifications_enabled` (boolean)
|
||||
- [ ] Invalid preference values are rejected with a 400 Bad Request and descriptive error message
|
||||
- [ ] Unknown preference keys are rejected with a 400 Bad Request
|
||||
- [ ] Both endpoints require authentication — unauthenticated requests receive 401
|
||||
- [ ] Users can only access their own preferences — mismatched user ID returns 403
|
||||
- [ ] Preferences are persisted to PostgreSQL (not in-memory)
|
||||
- [ ] All endpoints return responses in the standard `{data, meta}` envelope
|
||||
- [ ] Endpoints are documented in OpenAPI spec via `spec.go`
|
||||
- [ ] Domain layer validates preference keys and values independently of HTTP layer
|
||||
- [ ] Service, handler, and repository layers follow existing hexagonal architecture patterns
|
||||
- [ ] Unit tests cover service layer business logic (valid/invalid keys, partial updates, authorization)
|
||||
- [ ] Integration tests cover handler layer HTTP behavior (status codes, response format, error cases)
|
||||
|
||||
## API Design
|
||||
|
||||
### GET /api/preferences-api/preferences/{user_id}
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"user_id": "uuid",
|
||||
"preferences": {
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"notifications_enabled": true
|
||||
},
|
||||
"updated_at": "2026-02-08T12:00:00Z"
|
||||
},
|
||||
"meta": {
|
||||
"request_id": "...",
|
||||
"timestamp": "..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response 200 (no preferences saved yet):**
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"user_id": "uuid",
|
||||
"preferences": {},
|
||||
"updated_at": null
|
||||
},
|
||||
"meta": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
### PUT /api/preferences-api/preferences/{user_id}
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"preferences": {
|
||||
"theme": "dark",
|
||||
"notifications_enabled": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response 200:**
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"user_id": "uuid",
|
||||
"preferences": {
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"notifications_enabled": false
|
||||
},
|
||||
"updated_at": "2026-02-08T12:00:05Z"
|
||||
},
|
||||
"meta": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
## Technical Constraints
|
||||
|
||||
- Must use PostgreSQL for persistence (migration in `services/preferences-api/migrations/`)
|
||||
- Must follow the existing hexagonal architecture: domain → service → port → adapter
|
||||
- Must use `app.Wrap()` handler pattern, `app.BindAndValidate()` for request binding
|
||||
- Must use `httperror.*` for error responses, `httpresponse.*` for success responses
|
||||
- Must use chi router with `{param}` brace syntax for URL parameters
|
||||
- Must use `auth.Middleware()` for authentication and validate user ownership
|
||||
- Preference keys are a closed set — only `theme`, `language`, `notifications_enabled` are accepted
|
||||
- Preference values must be validated per-key (enum for theme, ISO code pattern for language, boolean for notifications)
|
||||
|
||||
## Database Schema
|
||||
|
||||
```sql
|
||||
CREATE TABLE user_preferences (
|
||||
user_id UUID PRIMARY KEY,
|
||||
preferences JSONB NOT NULL DEFAULT '{}',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
```
|
||||
|
||||
Storing preferences as JSONB allows flexible key-value storage while the application layer enforces the allowed key set and value validation.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- PostgreSQL database accessible from the service (connection config via `DatabaseConfig`)
|
||||
- Authentication system functional (`auth.Middleware()` with JWT validation)
|
||||
- Existing `pkg/app`, `pkg/httperror`, `pkg/httpresponse`, `pkg/auth`, `pkg/openapi` packages
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Preference defaults / fallback values at the API level (frontend handles defaults)
|
||||
- Preference history or versioning
|
||||
- Bulk preference operations across multiple users
|
||||
- Admin endpoints to manage other users' preferences
|
||||
- Real-time preference change notifications (WebSocket/SSE)
|
||||
- Custom/user-defined preference keys beyond the initial set
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **Language validation strictness:** Should language values be validated against a specific list of supported languages, or accept any valid ISO 639-1 code?
|
||||
2. **Default preferences:** Should the API return default values for unset preferences (e.g., `theme: "light"` if never set), or let the frontend handle defaults?
|
||||
3. **Rate limiting:** Should preference updates be rate-limited to prevent abuse?
|
||||
4. **Removing the example scaffold:** Should the existing Example entity/handlers/routes be removed as part of this feature, or left for reference?
|
||||
Loading…
Reference in New Issue
Block a user