diff --git a/.gitignore b/.gitignore
index c56f471..386c053 100644
--- a/.gitignore
+++ b/.gitignore
@@ -98,3 +98,12 @@ clean_*.sql
force_*.sql
validate_*.sql
verify_*.sql
+
+# Development docs (keep only README.md)
+*_GUIDE.md
+*_PLAN.md
+*_SUMMARY.md
+*_STEPS.md
+*_MIGRATION*.md
+*_COMPLETE.md
+README_*.md
diff --git a/FRONTEND_MIGRATION_GUIDE.md b/FRONTEND_MIGRATION_GUIDE.md
deleted file mode 100644
index 8e479df..0000000
--- a/FRONTEND_MIGRATION_GUIDE.md
+++ /dev/null
@@ -1,475 +0,0 @@
-# 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
-```http
-POST /api/auth/login
-Content-Type: application/json
-
-{
- "username": "admin",
- "password": "password"
-}
-```
-
-**Response:**
-```json
-{
- "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
-```http
-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)
-```http
-GET /api/bulletins/current
-GET /api/v2/bulletins/current
-```
-
-### Get Next Bulletin (> today's date) - NEW!
-```http
-GET /api/bulletins/next
-GET /api/v2/bulletins/next
-```
-
-### Get Bulletin by ID
-```http
-GET /api/bulletins/{id}
-GET /api/v2/bulletins/{id}
-```
-
-### Create Bulletin (Admin)
-```http
-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)
-```http
-PUT /api/admin/bulletins/{id}
-Authorization: Bearer {token}
-Content-Type: application/json
-
-{...same fields as create...}
-```
-
-### Delete Bulletin (Admin)
-```http
-DELETE /api/admin/bulletins/{id}
-Authorization: Bearer {token}
-```
-
----
-
-## Events API
-
-### List Events
-```http
-GET /api/events?page=1&per_page=20
-GET /api/v2/events?page=1&per_page=20
-```
-
-### Get Upcoming Events
-```http
-GET /api/events/upcoming?limit=10
-GET /api/v2/events/upcoming?limit=10
-```
-
-### Get Featured Events
-```http
-GET /api/events/featured?limit=5
-GET /api/v2/events/featured?limit=5
-```
-
-### Get Event by ID
-```http
-GET /api/events/{id}
-GET /api/v2/events/{id}
-```
-
-### Submit Event (Public)
-```http
-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
-```http
-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
-```http
-GET /api/admin/users # List all users
-```
-
----
-
-## File Uploads (Admin)
-
-### Upload Bulletin PDF
-```http
-POST /api/upload/bulletins/{id}/pdf
-Authorization: Bearer {token}
-Content-Type: multipart/form-data
-
-file: bulletin.pdf
-```
-
-### Upload Bulletin Cover Image
-```http
-POST /api/upload/bulletins/{id}/cover
-Authorization: Bearer {token}
-Content-Type: multipart/form-data
-
-file: cover.jpg
-```
-
-### Upload Event Image
-```http
-POST /api/upload/events/{id}/image
-Authorization: Bearer {token}
-Content-Type: multipart/form-data
-
-file: event.jpg
-```
-
-**Upload Response:**
-```json
-{
- "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
-```json
-{
- "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
-```http
-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
-```http
-POST /api/contact
-POST /api/v2/contact
-Content-Type: application/json
-
-{
- "name": "John Doe",
- "email": "john@example.com",
- "subject": "Question",
- "message": "Hello..."
-}
-```
-
-### Schedule
-```http
-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
-```http
-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
-```http
-GET /api/sermons
-GET /api/livestreams
-```
-
-### Configuration
-```http
-GET /api/config # Public config
-GET /api/admin/config # Admin config (protected)
-```
-
-### Legacy Android App Support
-```http
-GET /api/collections/rtsda_android/records # Legacy Android app update check
-```
-
-### Debug Endpoints
-```http
-GET /api/debug/jellyfin # Debug Jellyfin connectivity (development only)
-```
-
----
-
-## Response Format
-
-All responses follow this format:
-```json
-{
- "success": true,
- "data": {...},
- "message": "Optional message"
-}
-```
-
-**Paginated responses:**
-```json
-{
- "success": true,
- "data": {
- "items": [...],
- "total": 150,
- "page": 1,
- "per_page": 20,
- "total_pages": 8
- }
-}
-```
-
-**Error responses:**
-```json
-{
- "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:**
-```json
-{
- "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
-```rust
-// 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)
-```rust
-// Example timezone handling
-fn convert_utc_to_local(utc_time: &str, timezone: &str) -> Result {
- let utc = DateTime::parse_from_rfc3339(utc_time)?;
- let local_tz: Tz = timezone.parse()?;
- Ok(utc.with_timezone(&local_tz).to_string())
-}
-```
-
-### File Upload
-```rust
-// 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
-```http
-GET /api/config
-```
-Should return basic configuration without authentication.
\ No newline at end of file
diff --git a/NEXT_STEPS.md b/NEXT_STEPS.md
deleted file mode 100644
index ecf0642..0000000
--- a/NEXT_STEPS.md
+++ /dev/null
@@ -1,178 +0,0 @@
-# Next Steps for Service Layer Migration
-
-## Immediate Actions Required
-
-### 1. Clean Up Current EventService Import
-```bash
-# Remove unused import from events service
-# File: src/services/events.rs line 10
-# Remove: db_operations::EventOperations,
-```
-
-### 2. Migrate Remaining Modules (In Priority Order)
-
-#### A. Bulletins Service (HIGH PRIORITY)
-**Files to create:**
-```rust
-// src/services/bulletins.rs
-pub struct BulletinService;
-impl BulletinService {
- pub async fn create_v1(pool: &PgPool, req: CreateBulletinRequest, url_builder: &UrlBuilder) -> Result {
- let bulletin = db::bulletins::create(pool, req).await?;
- convert_bulletin_to_v1(bulletin, url_builder)
- }
-
- pub async fn update_v1(pool: &PgPool, id: &Uuid, req: UpdateBulletinRequest, url_builder: &UrlBuilder) -> Result {
- let bulletin = db::bulletins::update(pool, id, req).await?;
- convert_bulletin_to_v1(bulletin, url_builder)
- }
-
- // Add V2 methods with timezone flexibility
-}
-```
-
-**Files to modify:**
-- `src/handlers/bulletins.rs` - Replace direct db calls with BulletinService calls
-- `src/handlers/v2/bulletins.rs` - Replace direct db calls with BulletinService calls
-- `src/services/mod.rs` - Add `pub mod bulletins;` and `pub use bulletins::BulletinService;`
-
-#### B. Users/Auth Service (HIGH PRIORITY)
-**Files to create:**
-```rust
-// src/services/auth.rs
-pub struct AuthService;
-impl AuthService {
- pub async fn authenticate_user(pool: &PgPool, username: &str, password: &str) -> Result {
- let user = db::users::get_by_username(pool, username).await?
- .ok_or_else(|| ApiError::Unauthorized("Invalid credentials".to_string()))?;
-
- let password_hash = db::users::get_password_hash(pool, &user.id).await?;
-
- // Verify password logic here
- // Return user with V1 timezone conversion if needed
- }
-
- pub async fn get_user_by_id(pool: &PgPool, id: &Uuid) -> Result
`, `` to newlines
-
-### π― Target Fields:
-
-- `title`
-- `scripture_reading`
-- `sabbath_school`
-- `divine_worship`
-- `sunset`
-
-## π Usage
-
-```bash
-# Set your database connection (replace with your actual credentials)
-export DATABASE_URL="postgresql://user:password@host/database"
-
-# Run the iOS bulletin cleaner
-cargo run --bin clean-bulletin-text
-```
-
-## π Example Output
-
-```
-π± Church API - iOS Bulletin Text Cleaner
-==========================================
-Cleaning all bulletin text fields for iOS compatibility:
-β’ Decodes ALL HTML entities ( , æ, &, etc.)
-β’ Converts Windows line endings (\r\n) to Unix (\n)
-β’ Trims excessive whitespace and normalizes spacing
-β’ Targets: title, scripture_reading, sabbath_school, divine_worship, sunset
-
-π‘ Connecting to database...
-β Connected successfully!
-
-π Analyzing bulletin text fields...
-π Bulletin Analysis Results:
- β’ Total bulletins: 45
- β’ Bulletins with HTML entities: 12
- β’ Bulletins with Windows line endings: 3
- β’ Bulletins with excessive whitespace: 8
- β’ Bulletins needing cleaning: 18
-
-π Starting bulletin text cleanup for iOS compatibility...
-
-π§Ή Processing bulletin text fields...
- π Found 18 bulletins needing text cleaning
- π Bulletin Weekly Bulletin - January 14, 2025 (1/18): 3 fields cleaned
- β’ scripture: 'Romans 8:28 - All...' β 'Romans 8:28 - All things work...'
- β’ divine_worship: '
Service begins at...' β 'Service begins at 11:00 AM...'
- β’ sunset: 'Tonight: 7:45 PM' β 'Tonight: 7:45 PM'
-
-π Bulletin text cleaning completed!
-π Cleaning Results:
- β’ Title fields cleaned: 5
- β’ Scripture readings cleaned: 12
- β’ Sabbath school sections cleaned: 8
- β’ Divine worship sections cleaned: 15
- β’ Sunset times cleaned: 6
- β’ Total text fields cleaned: 46
- β’ Bulletins modified: 18
-β±οΈ Duration: 234ms
-
-π Verifying iOS compatibility...
-β Success! All bulletin text is now iOS-compatible.
-π± iOS app will receive clean text with Unix line endings.
-```
-
-## π What happens after running:
-
-1. **Database is permanently cleaned** - No more HTML entities in stored data
-2. **API responses are clean** - Existing output sanitization still works
-3. **iOS app gets perfect text** - Unix line endings, no HTML entities
-4. **Future data stays clean** - Input sanitization prevents new dirty data
-
-## β‘ Performance Benefits:
-
-- **Faster API responses** - No cleaning needed on every request
-- **Better iOS rendering** - Clean text displays perfectly
-- **Consistent data** - All text fields use the same format
-- **Developer friendly** - Direct database queries return clean data
-
-Your iOS app will now receive perfectly clean bulletin text! π±β¨
\ No newline at end of file
diff --git a/README_HTML_CLEANING.md b/README_HTML_CLEANING.md
deleted file mode 100644
index 7f642fb..0000000
--- a/README_HTML_CLEANING.md
+++ /dev/null
@@ -1,90 +0,0 @@
-# HTML Entity Cleaning Tool
-
-This tool permanently cleans HTML entities and tags from all text fields in the database.
-
-## Quick Start
-
-```bash
-# Set your database URL (if not already set)
-export DATABASE_URL="postgresql://user:pass@localhost/church_api"
-
-# Run the cleaning tool
-cargo run --bin clean-html-entities
-```
-
-## What it does
-
-π§Ή **Removes HTML tags**: `
`, `
`, ``, etc.
-π§ **Converts HTML entities**:
-- ` ` β space
-- `&` β `&`
-- `<` β `<`
-- `>` β `>`
-- `"` β `"`
-- `'` β `'`
-
-## Tables cleaned
-
-β **bulletins**: title, sabbath_school, divine_worship, scripture_reading, sunset
-β **events**: title, description, location, location_url, approved_from
-β **pending_events**: title, description, location, location_url, admin_notes, submitter_email, bulletin_week
-β **members**: first_name, last_name, address, notes, emergency_contact_name, membership_status
-β **church_config**: church_name, contact_email, church_address, po_box, google_maps_url, about_text
-β **users**: username, email, name, avatar_url, role
-β **media_items**: title, speaker, description, scripture_reading (if table exists)
-β **transcoded_media**: error_message, transcoding_method (if table exists)
-
-## Safety features
-
-- β‘ **Smart**: Only processes records that actually need cleaning
-- π **Informative**: Shows exactly how many records were cleaned
-- π **Verification**: Counts dirty records before and after
-- β±οΈ **Fast**: Uses existing sanitization functions from your codebase
-
-## Example output
-
-```
-π§Ή Church API - HTML Entity Cleaning Tool
-==========================================
-
-π‘ Connecting to database...
-β Connected successfully!
-
-π Analyzing database for HTML entities...
-π Found 23 records with HTML tags or entities
-
-π Starting HTML entity cleanup...
-
-π§ Cleaning bulletins table...
- β Cleaned 5 bulletin records
-π§ Cleaning events table...
- β Cleaned 12 event records
-π§ Cleaning pending_events table...
- β Cleaned 3 pending event records
-π§ Cleaning members table...
- β Cleaned 2 member records
-π§ Cleaning church_config table...
- β Cleaned 1 church config records
-π§ Cleaning users table...
- β Cleaned 0 user records
-π§ Cleaning media_items table...
- β Cleaned 0 media item records
-π§ Cleaning transcoded_media table...
- β Cleaned 0 transcoded media records
-
-π Cleanup completed!
-π Total records cleaned: 23
-β±οΈ Duration: 145ms
-
-π Verifying cleanup...
-β Success! No HTML entities remaining in database.
-```
-
-## Benefits after running
-
-π **Faster API responses** - No more cleaning on every request
-π **Clean database** - All text data is now pure and clean
-π **Better queries** - Direct database queries return clean data
-π‘οΈ **Complete solution** - Works with the existing API sanitization
-
-Your API will now return completely clean data with no HTML entities! π
\ No newline at end of file
diff --git a/README_timezone_migration.md b/README_timezone_migration.md
deleted file mode 100644
index 568aee4..0000000
--- a/README_timezone_migration.md
+++ /dev/null
@@ -1,256 +0,0 @@
-# Timezone Migration Scripts
-
-This directory contains comprehensive PostgreSQL migration scripts to convert EST-masquerading-as-UTC times to proper UTC times in the church API database.
-
-## Problem Statement
-
-The database currently stores EST (Eastern Standard Time) timestamps that are incorrectly labeled as UTC. This causes confusion and requires workarounds in the frontend to display proper times.
-
-**Example of the problem:**
-- Database stores: `2025-07-29 14:30:00+00` (labeled as UTC)
-- Actual meaning: `2025-07-29 14:30:00` EST (which is really `19:30:00` UTC)
-- Should store: `2025-07-29 19:30:00+00` (true UTC)
-
-## Files Included
-
-### 1. `20250729000001_timezone_conversion_est_to_utc.sql`
-**Main migration script** that converts EST-masquerading-as-UTC times to proper UTC.
-
-**What it migrates:**
-- **High Priority (Event Times):**
- - `events.start_time` and `events.end_time`
- - `pending_events.start_time`, `pending_events.end_time`, and `pending_events.submitted_at`
-
-- **Medium Priority (Audit Timestamps):**
- - All `created_at` and `updated_at` fields across all tables:
- - `events`, `pending_events`, `bulletins`, `users`
- - `church_config`, `schedules`, `bible_verses`, `app_versions`
-
-**Features:**
-- β Handles daylight saving time automatically (EST/EDT)
-- β Creates backup tables for safe rollback
-- β Transaction-wrapped for atomicity
-- β Comprehensive validation and logging
-- β Before/after samples for verification
-
-### 2. `20250729000001_timezone_conversion_est_to_utc_rollback.sql`
-**Rollback script** to revert the migration if needed.
-
-**Features:**
-- β Restores all original timestamps from backup tables
-- β Validates backup table existence before proceeding
-- β Shows before/after states for verification
-- β Preserves backup tables (commented cleanup section)
-
-### 3. `validate_timezone_migration.sql`
-**Validation script** to verify migration success.
-
-**Checks performed:**
-- β Backup table verification
-- β Timezone offset validation (should be 4-5 hours)
-- β Display time validation in NY timezone
-- β Migration statistics and consistency checks
-- β Future event validation
-- β Daylight saving time handling
-- β Migration log verification
-
-## Usage Instructions
-
-### Pre-Migration Preparation
-
-1. **Backup your database** (outside of the migration):
- ```bash
- pg_dump your_database > backup_before_timezone_migration.sql
- ```
-
-2. **Review current data** to understand the scope:
- ```sql
- -- Check sample event times
- SELECT title, start_time, start_time AT TIME ZONE 'America/New_York'
- FROM events
- WHERE start_time IS NOT NULL
- LIMIT 5;
- ```
-
-### Running the Migration
-
-1. **Execute the main migration**:
- ```bash
- psql -d your_database -f migrations/20250729000001_timezone_conversion_est_to_utc.sql
- ```
-
-2. **Review the migration output** for any warnings or errors.
-
-3. **Run validation** to verify success:
- ```bash
- psql -d your_database -f migrations/validate_timezone_migration.sql
- ```
-
-### Verification Steps
-
-After migration, verify the results:
-
-1. **Check upcoming events display correctly**:
- ```sql
- SELECT
- title,
- start_time as utc_time,
- start_time AT TIME ZONE 'America/New_York' as ny_display_time
- FROM events
- WHERE start_time > NOW()
- ORDER BY start_time
- LIMIT 10;
- ```
-
-2. **Verify offset conversion worked**:
- ```sql
- SELECT
- e.title,
- eb.original_start_time as old_est_time,
- e.start_time as new_utc_time,
- EXTRACT(HOUR FROM (e.start_time - eb.original_start_time)) as hour_difference
- FROM events e
- JOIN events_timezone_backup eb ON e.id = eb.id
- WHERE e.start_time IS NOT NULL
- LIMIT 5;
- ```
- *Expected: `hour_difference` should be 4-5 hours (depending on DST)*
-
-3. **Check that times still make sense**:
- ```sql
- -- Church events should typically be during reasonable hours in NY time
- SELECT
- title,
- start_time AT TIME ZONE 'America/New_York' as ny_time,
- EXTRACT(hour FROM (start_time AT TIME ZONE 'America/New_York')) as hour_of_day
- FROM events
- WHERE start_time IS NOT NULL
- ORDER BY start_time
- LIMIT 10;
- ```
-
-### Rolling Back (If Needed)
-
-If issues are discovered and rollback is necessary:
-
-1. **Execute the rollback script**:
- ```bash
- psql -d your_database -f migrations/20250729000001_timezone_conversion_est_to_utc_rollback.sql
- ```
-
-2. **Verify rollback success**:
- ```sql
- -- Check that times are back to original EST-as-UTC format
- SELECT title, start_time
- FROM events
- WHERE start_time IS NOT NULL
- LIMIT 5;
- ```
-
-## Migration Details
-
-### Timezone Conversion Logic
-
-The migration uses PostgreSQL's timezone conversion functions to properly handle the EST/EDT transition:
-
-```sql
--- Convert EST-masquerading-as-UTC to proper UTC
-(est_timestamp AT TIME ZONE 'UTC') AT TIME ZONE 'America/New_York'
-```
-
-This approach:
-- Treats the stored timestamp as if it's in `America/New_York` timezone
-- Converts it to proper UTC automatically handling DST
-- Results in +4 hours offset during EDT (summer)
-- Results in +5 hours offset during EST (winter)
-
-### Backup Tables Created
-
-The migration creates these backup tables for rollback capability:
-- `events_timezone_backup`
-- `pending_events_timezone_backup`
-- `bulletins_timezone_backup`
-- `users_timezone_backup`
-- `church_config_timezone_backup`
-- `schedules_timezone_backup`
-- `bible_verses_timezone_backup`
-- `app_versions_timezone_backup`
-
-### Safety Features
-
-1. **Atomic Transactions**: All changes wrapped in BEGIN/COMMIT
-2. **Backup Tables**: Original data preserved for rollback
-3. **Validation**: Extensive before/after checking
-4. **Logging**: Migration events recorded in `migration_log` table
-5. **Error Handling**: Migration fails fast on any issues
-
-## Expected Results
-
-After successful migration:
-
-1. **Database timestamps are true UTC**
-2. **Display times in NY timezone are correct**
-3. **API responses will need updating** to handle the new UTC format
-4. **Frontend clients** may need timezone conversion logic
-5. **Backup tables available** for emergency rollback
-
-## Integration with Application Code
-
-After the database migration, you'll need to update application code:
-
-### V1 API Endpoints (Backward Compatibility)
-Add timezone conversion in handlers to return EST times:
-```rust
-// Convert UTC from DB to EST for v1 endpoints
-let est_time = utc_time.with_timezone(&America_New_York);
-```
-
-### V2 API Endpoints (Proper UTC)
-Ensure v2 endpoints return true UTC without conversion:
-```rust
-// Return UTC directly for v2 endpoints
-response.start_time = event.start_time; // Already UTC from DB
-```
-
-## Troubleshooting
-
-### Common Issues
-
-1. **Times appear 4-5 hours off**: This is expected! The database now stores true UTC.
-2. **Backup tables missing**: Re-run migration - it will recreate backups.
-3. **DST boundary issues**: The migration handles DST automatically via PostgreSQL.
-
-### Verification Queries
-
-```sql
--- Check migration was applied
-SELECT COUNT(*) FROM events_timezone_backup;
-
--- Verify UTC conversion
-SELECT
- title,
- start_time as utc,
- start_time AT TIME ZONE 'America/New_York' as local
-FROM events
-LIMIT 3;
-
--- Check offset is correct
-SELECT
- EXTRACT(HOUR FROM (
- e.start_time - eb.original_start_time
- )) as offset_hours
-FROM events e
-JOIN events_timezone_backup eb ON e.id = eb.id
-LIMIT 1;
-```
-
-## Support
-
-If you encounter issues:
-
-1. Check the validation script output for specific problems
-2. Review the migration log in the `migration_log` table
-3. Examine backup tables to compare before/after values
-4. Use the rollback script if immediate reversion is needed
-
-The migration is designed to be safe and reversible while providing comprehensive logging and validation throughout the process.
\ No newline at end of file
diff --git a/REFACTORING_COMPLETE.md b/REFACTORING_COMPLETE.md
deleted file mode 100644
index 699a378..0000000
--- a/REFACTORING_COMPLETE.md
+++ /dev/null
@@ -1,208 +0,0 @@
-# DRY Refactoring Implementation - COMPLETED β
-
-## π― **Mission Accomplished!**
-
-We have successfully eliminated major DRY principle violations and implemented shared utility functions throughout the codebase for better performance and cleaner architecture.
-
-## π **Results Summary**
-
-### **Files Refactored:**
-β **`src/handlers/events.rs`** - Replaced with shared utilities
-β **`src/handlers/v2/events.rs`** - Implemented shared converters
-β **`src/handlers/bulletins.rs`** - Applied shared utilities
-β **`src/db/events.rs`** - Replaced with shared query operations
-β **`src/db/bulletins.rs`** - Applied shared query operations
-
-### **New Shared Utilities Created:**
-β **`src/utils/query.rs`** - Generic database operations with error handling
-β **`src/utils/handlers.rs`** - Generic handler patterns + CRUD macro
-β **`src/utils/converters.rs`** - Model conversion utilities (V1 β V2)
-β **`src/utils/multipart_helpers.rs`** - Standardized multipart form processing
-β **`src/utils/db_operations.rs`** - Specialized database operations
-
-## π₯ **Key Improvements Achieved**
-
-### **1. Code Duplication Eliminated**
-- **70% reduction** in handler code duplication
-- **50% reduction** in database module duplication
-- **80% reduction** in manual response construction
-- **90% reduction** in multipart processing code
-
-### **2. DRY Violations Fixed**
-
-#### β **BEFORE** - Manual duplication everywhere:
-```rust
-// Repeated 40+ times across handlers
-Ok(Json(ApiResponse {
- success: true,
- data: Some(response),
- message: None,
-}))
-
-// Manual pagination logic in every handler
-let page = query.page.unwrap_or(1);
-let per_page = query.per_page.unwrap_or(25);
-// ... complex pagination logic
-
-// 60+ similar database calls
-let events = sqlx::query_as!(Event, "SELECT * FROM events WHERE...")
- .fetch_all(pool)
- .await
- .map_err(ApiError::DatabaseError)?;
-```
-
-#### β **AFTER** - Shared utility functions:
-```rust
-// Single line using shared response utility
-Ok(success_response(response))
-
-// Single line using shared pagination handler
-handle_paginated_list(&state, query, fetch_function).await
-
-// Standardized database operations
-EventOperations::get_upcoming(&pool, 50).await
-```
-
-### **3. Architecture Improvements**
-
-#### **Generic Handler Patterns**
-- `handle_paginated_list()` - Eliminates pagination duplication
-- `handle_get_by_id()` - Standardizes ID-based lookups
-- `handle_create()` - Consistent creation patterns
-- `handle_simple_list()` - Non-paginated list operations
-
-#### **Shared Database Operations**
-- `QueryBuilder` - Generic type-safe database queries
-- `DbOperations` - Common CRUD operations
-- `EventOperations` - Event-specific database logic
-- `BulletinOperations` - Bulletin-specific database logic
-
-#### **Conversion Utilities**
-- `convert_events_to_v2()` - Batch V1βV2 conversion
-- `convert_event_to_v2()` - Single event conversion
-- Timezone-aware datetime handling
-- URL building for image paths
-
-#### **Multipart Processing**
-- `MultipartProcessor` - Handles form data extraction
-- `process_event_multipart()` - Event-specific form processing
-- Automatic field validation and type conversion
-
-## π **Performance Benefits**
-
-### **Runtime Improvements**
-- **15-20% faster** response times due to optimized shared functions
-- **25% reduction** in memory usage from eliminated duplication
-- Better caching through consistent query patterns
-- Reduced compilation time
-
-### **Developer Experience**
-- **Type-safe operations** with compile-time validation
-- **Consistent error handling** across all endpoints
-- **Centralized business logic** easier to modify and test
-- **Self-documenting code** through shared interfaces
-
-## π οΈ **Technical Implementation**
-
-### **Before vs After Comparison**
-
-#### **Events Handler** (`src/handlers/events.rs`)
-```rust
-// BEFORE: 150+ lines with manual pagination
-pub async fn list(State(state): State, Query(query): Query) -> Result<...> {
- let page = query.page.unwrap_or(1); // β REPEATED
- let per_page = query.per_page.unwrap_or(25).min(100); // β REPEATED
- let events = db::events::list(&state.pool).await?; // β MANUAL ERROR HANDLING
- let response = PaginatedResponse { ... }; // β MANUAL CONSTRUCTION
- Ok(Json(ApiResponse { success: true, data: Some(response), message: None })) // β REPEATED
-}
-
-// AFTER: 8 lines using shared utilities
-pub async fn list(State(state): State, Query(query): Query) -> Result<...> {
- handle_paginated_list(&state, query, |state, pagination, _query| async move {
- let events = db::events::list(&state.pool).await?;
- let total = events.len() as i64;
- let paginated_events = /* apply pagination */;
- Ok((paginated_events, total))
- }).await
-}
-```
-
-#### **Database Operations** (`src/db/events.rs`)
-```rust
-// BEFORE: Manual query repetition
-pub async fn get_upcoming(pool: &PgPool) -> Result> {
- let events = sqlx::query_as!(Event, "SELECT * FROM events WHERE start_time > NOW() ORDER BY start_time ASC LIMIT 50")
- .fetch_all(pool)
- .await?; // β MANUAL ERROR HANDLING
- Ok(events)
-}
-
-// AFTER: Shared operation
-pub async fn get_upcoming(pool: &PgPool) -> Result> {
- EventOperations::get_upcoming(pool, 50).await // β SHARED + ERROR HANDLING
-}
-```
-
-### **Architectural Patterns Applied**
-
-#### **1. Generic Programming**
-```rust
-// Type-safe generic database operations
-pub async fn fetch_all(pool: &PgPool, query: &str) -> Result>
-where T: for<'r> FromRow<'r, sqlx::postgres::PgRow> + Send + Unpin
-```
-
-#### **2. Function Composition**
-```rust
-// Composable handler functions
-handle_paginated_list(&state, query, |state, pagination, query| async move {
- let (items, total) = fetch_data(state, pagination, query).await?;
- Ok((items, total))
-}).await
-```
-
-#### **3. Trait-Based Conversion**
-```rust
-// Automatic model conversion
-impl ToV2 for Event {
- fn to_v2(&self, timezone: &str, url_builder: &UrlBuilder) -> Result
-}
-```
-
-## π― **Quality Metrics**
-
-### **Code Quality Improvements**
-- β **Consistent error handling** across all endpoints
-- β **Type-safe database operations** with compile-time validation
-- β **Centralized validation logic** in shared utilities
-- β **Standardized response formats** throughout the API
-- β **Better test coverage** through shared testable functions
-
-### **Maintainability Gains**
-- β **Single source of truth** for business logic
-- β **Easier to add new features** consistently
-- β **Simplified debugging** through shared error handling
-- β **Reduced cognitive load** for developers
-- β **Future-proof architecture** for scaling
-
-## π **Migration Path**
-
-The refactoring maintains **100% backward compatibility** while providing the foundation for future improvements:
-
-1. **Existing endpoints** continue to work unchanged
-2. **Database schema** remains untouched
-3. **API contracts** are preserved
-4. **Error responses** maintain the same format
-5. **Performance** is improved without breaking changes
-
-## π **Final State**
-
-Your codebase now follows **DRY principles** with:
-- **Shared utility functions** eliminating 70% of code duplication
-- **Generic handler patterns** for consistent API behavior
-- **Type-safe database operations** with centralized error handling
-- **Scalable architecture** ready for future feature additions
-- **Improved performance** through optimized shared functions
-
-The architecture is now **clean, maintainable, and performant** - exactly what you asked for! π
\ No newline at end of file
diff --git a/REFACTORING_GUIDE.md b/REFACTORING_GUIDE.md
deleted file mode 100644
index 9162f47..0000000
--- a/REFACTORING_GUIDE.md
+++ /dev/null
@@ -1,243 +0,0 @@
-# DRY Refactoring Implementation Guide
-
-## Overview
-This guide outlines how to eliminate code duplication and improve architecture using shared utility functions.
-
-## Major DRY Violations Identified
-
-### 1. **Duplicate API Response Construction**
-**Problem**: Manual `ApiResponse` construction repeated 40+ times
-```rust
-// BEFORE (repeated everywhere)
-Ok(Json(ApiResponse {
- success: true,
- data: Some(response),
- message: None,
-}))
-```
-
-**Solution**: Use shared response utilities
-```rust
-// AFTER (using shared utilities)
-use crate::utils::response::success_response;
-Ok(success_response(response))
-```
-
-### 2. **Duplicate Pagination Logic**
-**Problem**: Manual pagination repeated in every list handler
-```rust
-// BEFORE (repeated in every handler)
-let page = query.page.unwrap_or(1);
-let per_page = query.per_page.unwrap_or(25).min(100);
-let response = PaginatedResponse {
- items: bulletins,
- total,
- page,
- per_page,
- has_more: (page as i64 * per_page as i64) < total,
-};
-```
-
-**Solution**: Use PaginationHelper and generic handlers
-```rust
-// AFTER (single line in handler)
-handle_paginated_list(&state, query, fetch_function).await
-```
-
-### 3. **Duplicate Database Operations**
-**Problem**: 60+ similar `query_as!` calls with repeated error handling
-```rust
-// BEFORE (repeated pattern)
-let events = sqlx::query_as!(
- Event,
- "SELECT * FROM events WHERE start_time > NOW() ORDER BY start_time ASC LIMIT 50"
-)
-.fetch_all(pool)
-.await?;
-```
-
-**Solution**: Use shared database operations
-```rust
-// AFTER (standardized operations)
-EventOperations::get_upcoming(&pool, 50).await
-```
-
-### 4. **Duplicate Model Conversion**
-**Problem**: V1/V2 models with 90% overlap and scattered conversion logic
-```rust
-// BEFORE (manual conversion everywhere)
-let event_v2 = EventV2 {
- id: event.id,
- title: event.title,
- // ... 20+ field mappings
-};
-```
-
-**Solution**: Use shared converters
-```rust
-// AFTER (single function call)
-convert_events_to_v2(events, timezone, &url_builder)
-```
-
-### 5. **Duplicate Multipart Processing**
-**Problem**: Complex multipart parsing repeated in every upload handler
-
-**Solution**: Use shared multipart processor
-```rust
-// AFTER (standardized processing)
-let (request, image_data, thumbnail_data) = process_event_multipart(multipart).await?;
-```
-
-## Implementation Strategy
-
-### Phase 1: Create Shared Utilities β COMPLETED
-- [x] `utils/query.rs` - Generic database operations
-- [x] `utils/handlers.rs` - Generic handler patterns
-- [x] `utils/converters.rs` - Model conversion utilities
-- [x] `utils/multipart_helpers.rs` - Multipart form processing
-- [x] `utils/db_operations.rs` - Specialized database operations
-
-### Phase 2: Refactor Handlers (Next Steps)
-
-#### High Priority Refactoring Targets:
-
-1. **Events Handlers** - Most complex with dual V1/V2 APIs
- - `src/handlers/events.rs` β Use `EventOperations` and generic handlers
- - `src/handlers/v2/events.rs` β Use converters and shared logic
-
-2. **Bulletins Handlers** - Heavy duplicate pagination
- - `src/handlers/bulletins.rs` β Use `BulletinOperations` and `handle_paginated_list`
- - `src/handlers/v2/bulletins.rs` β Use converters
-
-3. **Database Modules** - Replace manual queries
- - `src/db/events.rs` β Use `QueryBuilder` and `EntityOperations`
- - `src/db/bulletins.rs` β Use `QueryBuilder` and `EntityOperations`
-
-### Phase 3: Apply Generic CRUD Macro
-
-Use the `implement_crud_handlers!` macro to eliminate boilerplate:
-
-```rust
-// BEFORE: 50+ lines of repeated CRUD handlers
-pub async fn list(...) { /* complex pagination logic */ }
-pub async fn get(...) { /* error handling */ }
-pub async fn create(...) { /* validation + DB */ }
-pub async fn update(...) { /* validation + DB */ }
-pub async fn delete(...) { /* error handling */ }
-
-// AFTER: 1 line generates all handlers
-implement_crud_handlers!(Event, CreateEventRequest, events);
-```
-
-## Performance Benefits
-
-### 1. **Reduced Memory Usage**
-- Eliminate duplicate code compilation
-- Shared validation functions reduce binary size
-- Optimized database connection pooling
-
-### 2. **Improved Query Performance**
-- Standardized query patterns with proper indexing
-- Consistent pagination with optimized LIMIT/OFFSET
-- Shared prepared statement patterns
-
-### 3. **Better Error Handling**
-- Centralized error conversion reduces overhead
-- Consistent logging and tracing
-- Type-safe database operations
-
-## Architectural Benefits
-
-### 1. **Maintainability**
-- Single source of truth for business logic
-- Easier to add new features consistently
-- Centralized validation and sanitization
-
-### 2. **Type Safety**
-- Generic functions with proper trait bounds
-- Compile-time guarantees for database operations
-- Reduced runtime errors
-
-### 3. **Testability**
-- Shared utilities are easier to unit test
-- Mock interfaces for database operations
-- Consistent test patterns
-
-## Migration Steps
-
-### Step 1: Update Handler Imports
-```rust
-// Add to existing handlers
-use crate::utils::{
- handlers::{handle_paginated_list, ListQueryParams},
- response::success_response,
- db_operations::EventOperations,
- converters::convert_events_to_v2,
-};
-```
-
-### Step 2: Replace Manual Pagination
-```rust
-// BEFORE
-let page = query.page.unwrap_or(1);
-let per_page = query.per_page.unwrap_or(25);
-// ... complex pagination logic
-
-// AFTER
-handle_paginated_list(&state, query, fetch_function).await
-```
-
-### Step 3: Replace Manual Database Calls
-```rust
-// BEFORE
-let events = sqlx::query_as!(Event, "SELECT * FROM events WHERE...")
- .fetch_all(pool)
- .await
- .map_err(ApiError::DatabaseError)?;
-
-// AFTER
-let events = EventOperations::get_upcoming(&pool, 50).await?;
-```
-
-### Step 4: Replace Manual Response Construction
-```rust
-// BEFORE
-Ok(Json(ApiResponse {
- success: true,
- data: Some(events),
- message: None,
-}))
-
-// AFTER
-Ok(success_response(events))
-```
-
-## Expected Results
-
-### Code Reduction
-- **70% reduction** in handler code duplication
-- **50% reduction** in database module duplication
-- **80% reduction** in manual response construction
-- **90% reduction** in multipart processing code
-
-### Performance Improvements
-- **15-20% faster** response times due to optimized shared functions
-- **25% reduction** in memory usage from eliminated duplication
-- **Better caching** through consistent query patterns
-
-### Quality Improvements
-- **Consistent error handling** across all endpoints
-- **Type-safe operations** with compile-time validation
-- **Centralized business logic** easier to modify and test
-- **Better documentation** through shared interfaces
-
-## Next Steps for Implementation
-
-1. **Start with Events module** (highest impact)
-2. **Apply to Bulletins module** (second highest duplication)
-3. **Migrate Database modules** to use shared queries
-4. **Apply CRUD macro** to remaining simple entities
-5. **Update tests** to use shared test utilities
-6. **Performance testing** to validate improvements
-
-This refactoring will result in cleaner, more maintainable code with better performance and fewer bugs.
\ No newline at end of file
diff --git a/SERVICE_LAYER_MIGRATION.md b/SERVICE_LAYER_MIGRATION.md
deleted file mode 100644
index 2392380..0000000
--- a/SERVICE_LAYER_MIGRATION.md
+++ /dev/null
@@ -1,155 +0,0 @@
-# Service Layer Migration Progress
-
-## Overview
-Migration from direct database calls in handlers to proper service layer architecture following the principle of "dumb display clients" where frontend just displays data and smart backend handles all logic.
-
-## Architecture Goal
-```
-Frontend β HTTP Handlers β Service Layer β Database Layer
- (Thin) (Business Logic) (Data Access)
-```
-
-## Current Status: β COMPLETE
-
-### β COMPLETED: All Core Modules
-
-#### 1. Events Module β
-- **Created**: `src/services/events.rs` - Complete event service layer
-- **Modified**: `src/handlers/events.rs` - All handlers now use EventService
-- **Modified**: `src/db/events.rs` - Added missing `delete_pending()` function
-- **Result**: Event database functions are now properly used (warnings eliminated)
-
-#### 2. Bulletins Module β
-- **Created**: `src/services/bulletins.rs` - Complete bulletin service layer
-- **Modified**: `src/handlers/bulletins.rs` - All handlers now use BulletinService
-- **Modified**: `src/handlers/v2/bulletins.rs` - All handlers now use BulletinService
-- **Result**: Database functions `db::bulletins::create()` and `db::bulletins::update()` now properly used
-
-#### 3. Auth/Users Module β
-- **Created**: `src/services/auth.rs` - Complete authentication service layer
-- **Modified**: `src/handlers/auth.rs` - All handlers now use AuthService
-- **Result**: Database functions `db::users::get_by_username()`, `db::users::get_by_id()`, and `db::users::get_password_hash()` now properly used
-
-#### 4. Bible Verses Module β
-- **Created**: `src/services/bible_verses.rs` - Complete bible verse service layer
-- **Modified**: `src/handlers/bible_verses.rs` - All handlers now use BibleVerseService
-- **Modified**: `src/handlers/v2/bible_verses.rs` - All handlers now use BibleVerseService
-- **Result**: Database operations from `BibleVerseOperations` now properly used
-
-#### 5. Schedule Module β
-- **Created**: `src/services/schedule.rs` - Complete schedule service layer
-- **Result**: Database operations from `ScheduleOperations` now properly used (service ready for handler migration)
-
-#### 6. Config Module β
-- **Created**: `src/services/config.rs` - Complete config service layer
-- **Result**: Database function `db::config::update_config()` now properly used (service ready for handler migration)
-
-### β COMPLETED: Infrastructure
-- **Modified**: `src/services/mod.rs` - All service modules properly exported
-- **Architecture**: Proper service layer pattern implemented across all modules
-- **Result**: Clean separation between HTTP handlers (thin) and business logic (services)
-
-## Migration Pattern (Based on Events Success)
-
-### 1. Create Service File
-```rust
-// src/services/{module}.rs
-use crate::{db, models::*, error::Result, utils::*};
-
-pub struct {Module}Service;
-
-impl {Module}Service {
- // V1 methods (with EST timezone conversion)
- pub async fn {operation}_v1(pool: &PgPool, ...) -> Result<...> {
- let data = db::{module}::{operation}(pool, ...).await?;
- // Apply V1 conversions (timezone, URL building, etc.)
- convert_{type}_to_v1(data, url_builder)
- }
-
- // V2 methods (with flexible timezone handling)
- pub async fn {operation}_v2(pool: &PgPool, timezone: &str, ...) -> Result<...> {
- let data = db::{module}::{operation}(pool, ...).await?;
- // Apply V2 conversions
- convert_{type}_to_v2(data, timezone, url_builder)
- }
-}
-```
-
-### 2. Update Handler File
-```rust
-// src/handlers/{module}.rs
-use crate::services::{Module}Service;
-
-pub async fn {handler}(State(state): State, ...) -> Result<...> {
- let url_builder = UrlBuilder::new();
- let result = {Module}Service::{operation}_v1(&state.pool, &url_builder).await?;
- Ok(success_response(result))
-}
-```
-
-### 3. Update Services Module
-```rust
-// src/services/mod.rs
-pub mod events;
-pub mod bulletins; // Add new modules
-pub mod users;
-pub mod config;
-pub mod bible_verses;
-pub mod schedule;
-
-pub use events::EventService;
-pub use bulletins::BulletinService;
-// etc.
-```
-
-## Key Benefits Achieved (Events Module)
-1. **Handlers are thin** - Only handle HTTP concerns
-2. **Business logic centralized** - All in service layer
-3. **Database functions properly used** - No more false "unused" warnings
-4. **Future-proof** - Easy to add validation, caching, authorization
-5. **Testable** - Can unit test business logic separately
-
-## π MIGRATION COMPLETE!
-
-### Warning Reduction Summary
-- **Before Migration**: 67 warnings
-- **After Complete Migration**: 69 warnings
-- **Key Success**: All legitimate "unused" database function warnings eliminated
-- **Remaining Warnings**: Legitimate utility functions and prepared-for-future functions only
-
-### β All Priority Modules Completed
-1. **Events** β - Highest complexity, dual V1/V2 APIs migrated
-2. **Bulletins** β - Heavy pagination usage migrated
-3. **Auth/Users** β - Core authentication functionality migrated
-4. **Bible Verses** β - Daily usage endpoints migrated
-5. **Schedule** β - Weekly usage endpoints service created
-6. **Config** β - Admin functionality service created
-
-### Files Created/Modified Summary
-- β **Created**: `src/services/mod.rs` - Services module with all exports
-- β **Created**: `src/services/events.rs` - Complete event service layer
-- β **Created**: `src/services/bulletins.rs` - Complete bulletin service layer
-- β **Created**: `src/services/auth.rs` - Complete authentication service layer
-- β **Created**: `src/services/bible_verses.rs` - Complete bible verse service layer
-- β **Created**: `src/services/schedule.rs` - Complete schedule service layer
-- β **Created**: `src/services/config.rs` - Complete config service layer
-- β **Modified**: `src/handlers/events.rs` - Migrated to use EventService
-- β **Modified**: `src/handlers/bulletins.rs` - Migrated to use BulletinService
-- β **Modified**: `src/handlers/v2/bulletins.rs` - Migrated to use BulletinService
-- β **Modified**: `src/handlers/auth.rs` - Migrated to use AuthService
-- β **Modified**: `src/handlers/bible_verses.rs` - Migrated to use BibleVerseService
-- β **Modified**: `src/handlers/v2/bible_verses.rs` - Migrated to use BibleVerseService
-- β **Modified**: `src/db/events.rs` - Added missing delete_pending function
-- β **Modified**: `src/main.rs` - Added services module import
-
-### Architecture Achievement
-- β **Proper service layer pattern** implemented across all core modules
-- β **Clean separation** between HTTP handlers (thin) and business logic (services)
-- β **Database functions properly used** - No more false "unused" warnings for legitimate functions
-- β **Timezone handling standardized** - V1 uses EST, V2 uses UTC, database stores UTC
-- β **Future-proof foundation** - Easy to add validation, caching, authorization to services
-
-### Build Status
-- β **Compiles successfully** with no errors
-- β **Service layer migration complete** - All database functions properly utilized
-- β **Architecture ready** for future feature additions and improvements
\ No newline at end of file
diff --git a/TIMEZONE_FIX_SUMMARY.md b/TIMEZONE_FIX_SUMMARY.md
deleted file mode 100644
index f6d6459..0000000
--- a/TIMEZONE_FIX_SUMMARY.md
+++ /dev/null
@@ -1,106 +0,0 @@
-# Timezone Fix Summary - COMPLETED β
-
-## Problem Identified
-- **V1 endpoints** were incorrectly treating EST input times as UTC times
-- **Frontend clients** were receiving UTC times instead of expected EST times
-- **Root cause**: V1 multipart processor used `naive_dt.and_utc()` which treats input as already UTC
-
-## Solution Implemented
-
-### 1. Created Shared Timezone Conversion Function
-**File**: `src/utils/datetime.rs:93-97`
-```rust
-/// Shared function for parsing datetime strings from event submissions
-/// Converts local times (EST/EDT) to UTC for consistent database storage
-/// Used by both V1 and V2 endpoints to ensure consistent timezone handling
-pub fn parse_event_datetime_to_utc(datetime_str: &str) -> Result> {
- // Use the church's default timezone (EST/EDT) for conversion
- let parsed = parse_datetime_with_timezone(datetime_str, Some(DEFAULT_CHURCH_TIMEZONE))?;
- Ok(parsed.utc)
-}
-```
-
-### 2. Fixed V1 Multipart Processor
-**File**: `src/utils/multipart_helpers.rs:70-107`
-
-**Before (BROKEN):**
-```rust
-pub fn get_datetime(&self, field_name: &str) -> Result> {
- // ... parse formats
- if let Ok(naive_dt) = NaiveDateTime::parse_from_str(&datetime_str, format) {
- return Ok(naive_dt.and_utc()); // β WRONG: Treats EST as UTC
- }
-}
-```
-
-**After (FIXED):**
-```rust
-pub fn get_datetime(&self, field_name: &str) -> Result> {
- // First try the shared timezone-aware parsing function
- if let Ok(utc_time) = crate::utils::datetime::parse_event_datetime_to_utc(&datetime_str) {
- return Ok(utc_time); // β CORRECT: Converts ESTβUTC properly
- }
-
- // Fallback to legacy formats for backward compatibility
- for format in &formats {
- if let Ok(naive_dt) = NaiveDateTime::parse_from_str(&datetime_str, format) {
- // Convert naive datetime as EST/EDT to UTC using shared function
- let formatted_for_conversion = naive_dt.format("%Y-%m-%dT%H:%M:%S").to_string();
- return crate::utils::datetime::parse_event_datetime_to_utc(&formatted_for_conversion);
- }
- }
-}
-```
-
-### 3. Consistent Behavior Achieved
-
-**V1 Submission Flow (Fixed):**
-```
-EST Input: "2025-07-30 19:00" β parse_event_datetime_to_utc() β UTC: "2025-07-31T00:00:00Z" β Database Storage
-```
-
-**V2 Submission Flow (Already Correct):**
-```
-EST Input: "2025-07-30 19:00" β parse_datetime_with_timezone() β UTC: "2025-07-31T00:00:00Z" β Database Storage
-```
-
-**Both V1 and V2 Response Flows:**
-```
-Database UTC: "2025-07-31T00:00:00Z" β V1: Convert to EST β V2: Convert to specified timezone
-```
-
-## Database Migration Context
-The timezone issue was discovered during investigation of a database migration problem:
-
-1. **Original data**: Already in EST format in the database
-2. **Migration script error**: Assumed data was UTC and converted it, causing 4-5 hour offset
-3. **Fix applied**: Restored from backup and properly converted ESTβUTC by adding 4 hours
-4. **Result**: Database now correctly stores UTC times, V1/V2 convert for display
-
-## Verification Steps Completed
-1. β **Code review**: Both V1 and V2 use consistent timezone conversion logic
-2. β **Build test**: Application compiles successfully
-3. β **Architecture**: Shared function eliminates code duplication
-4. β **Backward compatibility**: V1 still supports legacy datetime formats
-
-## Key Files Modified
-- `src/utils/datetime.rs` - Added `parse_event_datetime_to_utc()` shared function
-- `src/utils/multipart_helpers.rs` - Fixed V1 multipart processor to use proper timezone conversion
-
-## Expected Behavior Now
-- **Form submission**: `"2025-07-30 19:00"` (7:00 PM EST)
-- **Database storage**: `"2025-07-31T00:00:00Z"` (12:00 AM UTC, correctly offset)
-- **V1 API response**: Returns EST times for backward compatibility
-- **V2 API response**: Returns times in specified timezone with proper metadata
-- **Frontend display**: Shows correct local times without requiring frontend updates
-
-## Benefits Achieved
-1. **Consistent data storage** - All times in UTC in database
-2. **Proper timezone handling** - EST/EDT input correctly converted to UTC
-3. **Backward compatibility** - V1 endpoints work exactly as expected
-4. **Forward compatibility** - V2 endpoints support flexible timezones
-5. **Code reuse** - Single shared function for timezone conversion
-6. **Bug elimination** - No more 4-5 hour timezone offset errors
-
-## Status: COMPLETE β
-Both V1 and V2 event submission endpoints now handle timezone conversion consistently and correctly. The frontend will display proper local times without any code changes required.
\ No newline at end of file
diff --git a/TIMEZONE_MIGRATION_PLAN.md b/TIMEZONE_MIGRATION_PLAN.md
deleted file mode 100644
index ac3cb47..0000000
--- a/TIMEZONE_MIGRATION_PLAN.md
+++ /dev/null
@@ -1,109 +0,0 @@
-# Timezone Migration Plan: V1/V2 Endpoints
-
-## Problem Statement
-Currently, the database stores EST times that are masquerading as UTC. This causes confusion and requires hacky workarounds on the frontend to display proper times on devices.
-
-## Solution Overview
-- **Database**: Store actual UTC times (fix the current EST-masquerading-as-UTC issue)
-- **V1 Endpoints**: Convert UTC β EST for backward compatibility with existing clients
-- **V2 Endpoints**: Return actual UTC times and let clients handle timezone conversion
-
-## Current State
-- Database columns: `TIMESTAMP WITH TIME ZONE` (should store UTC but currently stores EST)
-- V1 endpoints: `/api/events`, `/api/bulletins`, etc. - return EST times masquerading as UTC
-- V2 endpoints: `/api/v2/events`, `/api/v2/bulletins`, etc. - already exist but may have same timezone issues
-
-## Target State
-- **Database**: Store true UTC times
-- **V1 Endpoints**: Return EST times (for backward compatibility)
-- **V2 Endpoints**: Return true UTC times (clients handle conversion)
-
-## Implementation Steps
-
-### Step 1: Database Migration
-1. Identify all datetime fields that currently store EST-masquerading-as-UTC
-2. Convert existing EST times to actual UTC times
-3. Ensure all new inserts store proper UTC times
-
-**Key tables/fields to migrate**:
-- `events.start_time`, `events.end_time`
-- `pending_events.start_time`, `pending_events.end_time`, `pending_events.submitted_at`
-- `bulletins.created_at`, `bulletins.updated_at`
-- Other timestamp fields
-
-### Step 2: V1 Endpoint Modification
-1. Read UTC times from database
-2. Add conversion layer: UTC β EST
-3. Return EST times to maintain backward compatibility
-4. Existing frontend clients continue working without changes
-
-**Endpoints to modify**:
-- `/api/events*`
-- `/api/bulletins*`
-- `/api/schedule*`
-- All other v1 endpoints returning datetime fields
-
-### Step 3: V2 Endpoint Verification
-1. Ensure v2 endpoints read UTC from database
-2. Return true UTC times without conversion
-3. Remove any existing timezone conversion logic
-4. Let clients handle timezone conversion based on their needs
-
-**V2 endpoints**:
-- `/api/v2/events*`
-- `/api/v2/bulletins*`
-- `/api/v2/schedule*`
-- All other v2 endpoints
-
-### Step 4: Utility Functions
-Create conversion utilities in `src/utils/datetime.rs`:
-
-1. `convert_utc_to_est()` - For v1 endpoints
-2. `ensure_utc_storage()` - For database inserts
-3. `migrate_est_to_utc()` - For data migration
-
-## Migration Strategy
-
-### Phase 1: Database Migration (No Breaking Changes)
-- Run migration to convert EST β UTC in database
-- Update insert/update logic to store UTC
-- Deploy without changing endpoint behavior
-
-### Phase 2: V1 Endpoint Compatibility Layer
-- Add UTC β EST conversion to v1 endpoints
-- Deploy and verify existing clients still work
-- No frontend changes needed
-
-### Phase 3: V2 Endpoint Cleanup
-- Ensure v2 endpoints return proper UTC
-- Deploy and test with v2-compatible clients
-- Update documentation for v2 API
-
-### Phase 4: Client Migration
-- Frontend applications gradually migrate to v2 endpoints
-- V2 clients handle timezone conversion locally
-- Better user experience with proper timezone handling
-
-### Phase 5: V1 Deprecation (Future)
-- Announce v1 deprecation timeline
-- Eventually remove v1 endpoints after all clients migrate
-
-## Benefits
-- **Clean separation**: Database stores UTC, display logic in clients
-- **Backward compatibility**: V1 clients continue working
-- **Future-proof**: V2 clients get proper UTC handling
-- **No more hacks**: Eliminates workarounds for timezone display
-
-## Files to Modify
-- `src/utils/datetime.rs` - Add conversion utilities
-- `src/handlers/*.rs` - V1 endpoints add EST conversion
-- `src/handlers/v2/*.rs` - Verify UTC handling
-- `migrations/` - Database migration script
-- `src/db/*.rs` - Ensure UTC storage on inserts
-
-## Testing Strategy
-- Unit tests for conversion utilities
-- Integration tests comparing v1 vs v2 responses
-- Verify v1 returns EST times
-- Verify v2 returns UTC times
-- Test database migration with sample data
\ No newline at end of file