5.7 KiB
5.7 KiB
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 pairsGET /api/preferences-api/preferences/{user_id}returns an empty preferences object (not 404) for users with no saved preferencesPUT /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:
{
"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):
{
"data": {
"user_id": "uuid",
"preferences": {},
"updated_at": null
},
"meta": { ... }
}
PUT /api/preferences-api/preferences/{user_id}
Request:
{
"preferences": {
"theme": "dark",
"notifications_enabled": false
}
}
Response 200:
{
"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_enabledare accepted - Preference values must be validated per-key (enum for theme, ISO code pattern for language, boolean for notifications)
Database Schema
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/openapipackages
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
- Language validation strictness: Should language values be validated against a specific list of supported languages, or accept any valid ISO 639-1 code?
- Default preferences: Should the API return default values for unset preferences (e.g.,
theme: "light"if never set), or let the frontend handle defaults? - Rate limiting: Should preference updates be rate-limited to prevent abuse?
- Removing the example scaffold: Should the existing Example entity/handlers/routes be removed as part of this feature, or left for reference?