church-api/FRONTEND_MIGRATION_GUIDE.md
Benjamin Slingo 0c06e159bb Initial commit: Church API Rust implementation
Complete church management system with bulletin management, media processing, live streaming integration, and web interface. Includes authentication, email notifications, database migrations, and comprehensive test suite.
2025-08-19 20:56:41 -04:00

10 KiB

Frontend Migration Guide

Backend API Overview

The backend provides two API versions with smart timezone handling and proper URL generation:

API Versions

  • V1 API (/api/*): Legacy compatibility, returns EST timezone, existing URL formats
  • V2 API (/api/v2/*): Modern API, returns UTC timestamps, client handles timezone conversion

Authentication

Login

POST /api/auth/login
Content-Type: application/json

{
  "username": "admin",
  "password": "password"
}

Response:

{
  "success": true,
  "data": {
    "token": "jwt_token_here",
    "user": {
      "id": "uuid",
      "username": "admin"
    }
  }
}

Protected Routes

  • Add header: Authorization: Bearer {token}
  • Admin routes are under /api/admin/*

Bulletins API

List Bulletins

GET /api/bulletins?page=1&per_page=20&active_only=true
GET /api/v2/bulletins?page=1&per_page=20

Get Current Bulletin (≤ today's date)

GET /api/bulletins/current
GET /api/v2/bulletins/current

Get Next Bulletin (> today's date) - NEW!

GET /api/bulletins/next
GET /api/v2/bulletins/next

Get Bulletin by ID

GET /api/bulletins/{id}
GET /api/v2/bulletins/{id}

Create Bulletin (Admin)

POST /api/admin/bulletins
Authorization: Bearer {token}
Content-Type: application/json

{
  "title": "Weekly Bulletin",
  "date": "2025-08-02",
  "url": "https://example.com",
  "cover_image": null,
  "sabbath_school": "Elder Smith",
  "divine_worship": "Pastor Johnson",
  "scripture_reading": "John 3:16",
  "sunset": "7:45 PM",
  "is_active": true
}

Update Bulletin (Admin)

PUT /api/admin/bulletins/{id}
Authorization: Bearer {token}
Content-Type: application/json

{...same fields as create...}

Delete Bulletin (Admin)

DELETE /api/admin/bulletins/{id}
Authorization: Bearer {token}

Events API

List Events

GET /api/events?page=1&per_page=20
GET /api/v2/events?page=1&per_page=20

Get Upcoming Events

GET /api/events/upcoming?limit=10
GET /api/v2/events/upcoming?limit=10
GET /api/events/featured?limit=5
GET /api/v2/events/featured?limit=5

Get Event by ID

GET /api/events/{id}
GET /api/v2/events/{id}

Submit Event (Public)

POST /api/events/submit
Content-Type: application/json

{
  "title": "Prayer Meeting",
  "description": "Weekly prayer meeting",
  "start_time": "2025-08-02T19:00:00",
  "end_time": "2025-08-02T20:00:00",
  "location": "Fellowship Hall",
  "location_url": "https://maps.google.com/...",
  "category": "worship",
  "is_featured": false,
  "recurring_type": "weekly",
  "bulletin_week": "2025-08-02",
  "submitter_email": "user@example.com"
}

Admin Event Management

POST /api/admin/events                    # Create event
PUT /api/admin/events/{id}                # Update event
DELETE /api/admin/events/{id}             # Delete event
GET /api/admin/events/pending             # List pending submissions
POST /api/admin/events/pending/{id}/approve  # Approve pending
POST /api/admin/events/pending/{id}/reject   # Reject pending
DELETE /api/admin/events/pending/{id}     # Delete pending

Admin User Management

GET /api/admin/users                      # List all users

File Uploads (Admin)

Upload Bulletin PDF

POST /api/upload/bulletins/{id}/pdf
Authorization: Bearer {token}
Content-Type: multipart/form-data

file: bulletin.pdf

Upload Bulletin Cover Image

POST /api/upload/bulletins/{id}/cover
Authorization: Bearer {token}
Content-Type: multipart/form-data

file: cover.jpg

Upload Event Image

POST /api/upload/events/{id}/image
Authorization: Bearer {token}
Content-Type: multipart/form-data

file: event.jpg

Upload Response:

{
  "success": true,
  "file_path": "uploads/bulletins/uuid.pdf",
  "pdf_path": "https://api.rockvilletollandsda.church/uploads/bulletins/uuid.pdf",
  "message": "File uploaded successfully"
}

Note: Files are served at /uploads/* path (handled by Caddy, not API)


Scripture Processing

The API now automatically processes scripture references in bulletin fields:

Automatic Scripture Lookup

  • Input: Short reference like "John 3:16 KJV"
  • Output: Enhanced with full verse text: "For God so loved the world... - John 3:16 KJV"
  • Fallback: If no match found, returns original text unchanged
  • Smart Detection: Already long texts (>50 chars) are left unchanged

How It Works

  1. When creating/updating bulletins, scripture_reading field is processed
  2. Uses existing Bible verse database with fuzzy search
  3. Matches on both reference and partial text content
  4. Returns best match from database

Example API Response

{
  "success": true,
  "data": {
    "id": "...",
    "title": "Weekly Bulletin",
    "scripture_reading": "For God so loved the world, that he gave his only begotten Son, that whosoever believeth in him should not perish, but have everlasting life. - John 3:16 KJV",
    ...
  }
}

Other APIs

Bible Verses

GET /api/bible_verses/random
GET /api/bible_verses?page=1&per_page=20
GET /api/bible_verses/search?q=love&limit=10

GET /api/v2/bible_verses/random
GET /api/v2/bible_verses?page=1&per_page=20
GET /api/v2/bible_verses/search?q=love&limit=10

Contact Form

POST /api/contact
POST /api/v2/contact
Content-Type: application/json

{
  "name": "John Doe",
  "email": "john@example.com",
  "subject": "Question",
  "message": "Hello..."
}

Schedule

GET /api/schedule?date=2025-08-02
GET /api/conference-data

GET /api/v2/schedule?date=2025-08-02
GET /api/v2/conference-data

Admin Schedule Management

POST /api/admin/schedule              # Create schedule
PUT /api/admin/schedule/{date}        # Update schedule by date
DELETE /api/admin/schedule/{date}     # Delete schedule by date
GET /api/admin/schedule               # List all schedules

Sermons & Livestreams

GET /api/sermons
GET /api/livestreams

Configuration

GET /api/config                    # Public config
GET /api/admin/config              # Admin config (protected)

Legacy Android App Support

GET /api/collections/rtsda_android/records    # Legacy Android app update check

Debug Endpoints

GET /api/debug/jellyfin            # Debug Jellyfin connectivity (development only)

Response Format

All responses follow this format:

{
  "success": true,
  "data": {...},
  "message": "Optional message"
}

Paginated responses:

{
  "success": true,
  "data": {
    "items": [...],
    "total": 150,
    "page": 1,
    "per_page": 20,
    "total_pages": 8
  }
}

Error responses:

{
  "success": false,
  "message": "Error description"
}

Timezone Handling

V1 API (Legacy)

  • Input: Accepts times in any format
  • Output: Converts all timestamps to EST timezone
  • Use case: Existing clients that expect EST times

V2 API (Modern)

  • Input: Expects UTC timestamps with timezone info when needed
  • Output: Returns UTC timestamps
  • Client responsibility: Convert to local timezone for display

V2 Timezone Example:

{
  "start_time": "2025-08-02T23:00:00Z",
  "timezone_info": {
    "utc": "2025-08-02T23:00:00Z",
    "local_display": "2025-08-02T19:00:00-04:00"
  }
}

Frontend Migration Strategy

Phase 1: Update Shared Rust Crate

  1. Add V2 API models with UTC timestamp handling
  2. Keep V1 models for backward compatibility
  3. Add timezone conversion utilities
  4. Update HTTP client to handle both API versions

Phase 2: Client-by-Client Migration

  1. Web Admin Panel: Migrate to V2 API first
  2. Mobile App: Update to use new bulletin endpoints (/next)
  3. Website: Gradually migrate public endpoints
  4. Keep V1 for old clients until all are updated

Phase 3: New Features

  1. Use V2 API only for new features
  2. Proper UTC handling from day one
  3. Client-side timezone conversion

Breaking Changes to Watch For

URL Structure

  • Old: Some inconsistent URL patterns
  • New: Consistent /api/v2/* structure
  • Files: Always served at /uploads/* (via Caddy)

Timestamp Format

  • V1: Mixed timezone handling, EST output
  • V2: Consistent UTC timestamps
  • Migration: Update date parsing/formatting code

Response Fields

  • V2 may have additional fields for timezone info
  • V1 fields remain unchanged for compatibility
  • New endpoints (like /next) available in both versions

Authentication

  • Same JWT tokens work for both API versions
  • Admin routes use same authorization header
  • No changes needed to auth flow

Implementation Notes

Error Handling

// Example error handling in shared crate
match api_client.get_current_bulletin().await {
    Ok(response) if response.success => {
        // Handle response.data
    },
    Ok(response) => {
        // Handle API error: response.message
    },
    Err(e) => {
        // Handle network/parsing error
    }
}

Timezone Conversion (V2)

// Example timezone handling
fn convert_utc_to_local(utc_time: &str, timezone: &str) -> Result<String> {
    let utc = DateTime::parse_from_rfc3339(utc_time)?;
    let local_tz: Tz = timezone.parse()?;
    Ok(utc.with_timezone(&local_tz).to_string())
}

File Upload

// Example multipart upload
let form = multipart::Form::new()
    .file("file", path_to_file)?;

let response = client
    .post(&format!("{}/api/upload/bulletins/{}/pdf", base_url, bulletin_id))
    .bearer_auth(&token)
    .multipart(form)
    .send()
    .await?;

Testing Endpoints

Development

  • API Base: http://localhost:3002
  • Files: http://localhost:3002/uploads/*

Production

  • API Base: https://api.rockvilletollandsda.church
  • Files: https://api.rockvilletollandsda.church/uploads/*

Health Check

GET /api/config

Should return basic configuration without authentication.