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

8.6 KiB
Raw Blame History

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:

{
  "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:

{
  "firstName": "John",
  "lastName": "Doe",
  "username": "johndoe123"
}

All fields are optional. Only provided fields will be updated.

Response:

{
  "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:

[
  {
    "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:

{
  "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:

{
  "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:

{
  "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:

{
  "impactScore": 150
}

Error Responses:

  • 404 - User not found
  • 500 - Internal server error

Usage Examples

Get User Profile

curl http://localhost:3005/api/users/abc-123

Update Profile

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

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

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:

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