Files
ocean-cleanup/server/USER_PROFILE_ENDPOINTS.md
Paul Bailey c84bcb2fd6 feat: implement user profile endpoints (task 31)
- Add GET /api/users/:id for profile retrieval with stats
- Add PATCH /api/users/:id for profile updates
- Add GET /api/users/:id/reports to fetch user's reports
- Add GET /api/users/:id/events to fetch user's events (registered & organized)
- Add PATCH /api/users/:id/preferences for notification settings
- Add POST /api/users/:id/calculate-impact for impact score calculation
- Create userService with all business logic
- Create userController with request handling
- Create userRoutes and register in main server
- Update frontend userService with new endpoints
- Add comprehensive documentation in USER_PROFILE_ENDPOINTS.md
- Add test script for manual endpoint testing

Requirements satisfied: 6.3, 6.4, 6.5, 10.4
2025-11-16 21:38:16 +00:00

402 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# User Profile Endpoints Documentation
This document describes the user profile API endpoints implemented for the Beach Litter Mapping Platform.
## Overview
The user profile endpoints provide functionality for:
- Retrieving user profiles with statistics
- Updating user profile information
- Managing notification preferences
- Fetching user's reports and events
- Calculating impact scores
## Authentication
Most endpoints require authentication via Clerk session token:
```
Authorization: Bearer <clerk_session_token>
```
## Endpoints
### 1. Get User Profile
**Endpoint:** `GET /api/users/:id`
**Description:** Retrieve a user's profile including statistics about their contributions.
**Authentication:** Not required (public profiles)
**Parameters:**
- `id` (path) - User database ID
**Response:**
```json
{
"id": "uuid",
"clerkId": "user_xxx",
"email": "user@example.com",
"username": "johndoe",
"firstName": "John",
"lastName": "Doe",
"avatarUrl": "https://...",
"impactScore": 150,
"notificationEmail": true,
"notificationInApp": true,
"areasOfInterest": [
{
"lat": 53.3498,
"lng": -6.2603,
"radius": 10
}
],
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z",
"stats": {
"reportsSubmitted": 5,
"eventsAttended": 3,
"eventsOrganized": 1
}
}
```
**Error Responses:**
- `404` - User not found
- `500` - Internal server error
---
### 2. Update User Profile
**Endpoint:** `PATCH /api/users/:id`
**Description:** Update user profile information (first name, last name, username).
**Authentication:** Required (users can only update their own profile)
**Parameters:**
- `id` (path) - User database ID
**Request Body:**
```json
{
"firstName": "John",
"lastName": "Doe",
"username": "johndoe123"
}
```
All fields are optional. Only provided fields will be updated.
**Response:**
```json
{
"id": "uuid",
"clerkId": "user_xxx",
"email": "user@example.com",
"username": "johndoe123",
"firstName": "John",
"lastName": "Doe",
"avatarUrl": "https://...",
"impactScore": 150,
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
```
**Error Responses:**
- `400` - Username already taken
- `401` - Not authenticated
- `403` - Cannot update another user's profile
- `404` - User not found
- `500` - Internal server error
---
### 3. Get User Reports
**Endpoint:** `GET /api/users/:id/reports`
**Description:** Retrieve all reports submitted by a user.
**Authentication:** Not required
**Parameters:**
- `id` (path) - User database ID
**Response:**
```json
[
{
"id": "uuid",
"userId": "uuid",
"latitude": 53.3498,
"longitude": -6.2603,
"locationSource": "gps",
"photoUrls": ["/uploads/photo1.jpg"],
"photoTimestamp": "2024-01-01T12:00:00.000Z",
"litterType": "plastic",
"quantity": "moderate",
"description": "Plastic bottles on beach",
"verificationStatus": "verified",
"createdAt": "2024-01-01T12:00:00.000Z",
"environmentalConcerns": [],
"verifications": []
}
]
```
**Error Responses:**
- `500` - Internal server error
---
### 4. Get User Events
**Endpoint:** `GET /api/users/:id/events`
**Description:** Retrieve events the user has registered for and organized.
**Authentication:** Not required
**Parameters:**
- `id` (path) - User database ID
**Response:**
```json
{
"registered": [
{
"id": "uuid",
"title": "Beach Cleanup",
"description": "Community cleanup event",
"latitude": 53.3498,
"longitude": -6.2603,
"locationName": "Sandymount Beach",
"scheduledDate": "2024-02-01T10:00:00.000Z",
"duration": 120,
"status": "upcoming",
"participantCount": 15,
"organizer": {
"id": "uuid",
"username": "organizer",
"avatarUrl": "https://..."
},
"registeredAt": "2024-01-15T10:00:00.000Z",
"attended": false
}
],
"organized": [
{
"id": "uuid",
"title": "My Beach Cleanup",
"description": "Event I organized",
"latitude": 53.3498,
"longitude": -6.2603,
"locationName": "Dollymount Beach",
"scheduledDate": "2024-03-01T10:00:00.000Z",
"duration": 180,
"status": "upcoming",
"participantCount": 20,
"organizer": {
"id": "uuid",
"username": "johndoe",
"avatarUrl": "https://..."
},
"registrations": []
}
]
}
```
**Error Responses:**
- `500` - Internal server error
---
### 5. Update Notification Preferences
**Endpoint:** `PATCH /api/users/:id/preferences`
**Description:** Update user's notification preferences and areas of interest.
**Authentication:** Required (users can only update their own preferences)
**Parameters:**
- `id` (path) - User database ID
**Request Body:**
```json
{
"notificationEmail": true,
"notificationInApp": true,
"areasOfInterest": [
{
"lat": 53.3498,
"lng": -6.2603,
"radius": 10
},
{
"lat": 51.8985,
"lng": -8.4756,
"radius": 25
}
]
}
```
**Field Validation:**
- `radius` must be between 1 and 50 kilometers
- Each area must have `lat`, `lng`, and `radius`
**Response:**
```json
{
"id": "uuid",
"notificationEmail": true,
"notificationInApp": true,
"areasOfInterest": [
{
"lat": 53.3498,
"lng": -6.2603,
"radius": 10
}
]
}
```
**Error Responses:**
- `400` - Validation error (invalid radius, missing fields, etc.)
- `401` - Not authenticated
- `403` - Cannot update another user's preferences
- `404` - User not found
- `500` - Internal server error
---
### 6. Calculate Impact Score
**Endpoint:** `POST /api/users/:id/calculate-impact`
**Description:** Calculate and update the user's impact score based on their contributions.
**Authentication:** Not required
**Parameters:**
- `id` (path) - User database ID
**Impact Score Formula:**
```
Impact Score = (reports × 10) + (events attended × 20) + (events organized × 50)
```
**Response:**
```json
{
"impactScore": 150
}
```
**Error Responses:**
- `404` - User not found
- `500` - Internal server error
---
## Usage Examples
### Get User Profile
```bash
curl http://localhost:3005/api/users/abc-123
```
### Update Profile
```bash
curl -X PATCH http://localhost:3005/api/users/abc-123 \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"firstName": "John",
"lastName": "Doe",
"username": "johndoe"
}'
```
### Update Notification Preferences
```bash
curl -X PATCH http://localhost:3005/api/users/abc-123/preferences \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"notificationEmail": true,
"notificationInApp": true,
"areasOfInterest": [
{
"lat": 53.3498,
"lng": -6.2603,
"radius": 10
}
]
}'
```
### Calculate Impact Score
```bash
curl -X POST http://localhost:3005/api/users/abc-123/calculate-impact
```
## Frontend Integration
The frontend service (`src/services/userService.ts`) provides TypeScript methods for all endpoints:
```typescript
import { userService } from '@/services/userService';
// Get profile
const profile = await userService.getProfile(userId);
// Update profile
const updated = await userService.updateProfile(userId, {
firstName: 'John',
lastName: 'Doe',
username: 'johndoe'
});
// Get user's reports
const reports = await userService.getUserReports(userId);
// Get user's events
const events = await userService.getUserEvents(userId);
// Update notification preferences
const preferences = await userService.updateNotificationPreferences(userId, {
notificationEmail: true,
notificationInApp: true,
areasOfInterest: [
{ lat: 53.3498, lng: -6.2603, radius: 10 }
]
});
// Calculate impact score
const { impactScore } = await userService.calculateImpactScore(userId);
```
## Requirements Satisfied
This implementation satisfies the following requirements from the specification:
- **Requirement 6.3**: User profile display showing submitted reports and events attended
- **Requirement 6.4**: Impact score calculation based on contributions
- **Requirement 6.5**: User profile showing map of submitted report locations (data provided via reports endpoint)
- **Requirement 10.4**: Notification preferences with area of interest configuration (1-50km radius)
## Notes
- User authentication is handled by Clerk
- Users are automatically created in the database when they first interact with the API
- The `areasOfInterest` field is stored as JSON in the database
- Impact scores are calculated on-demand but can be cached for performance
- All endpoints follow RESTful conventions
- Error responses follow a consistent format with error codes and timestamps