Files
thrilltrack-explorer/PHASE_2_COMPLETE_SUPABASE_REMOVAL_PLAN.md

402 lines
12 KiB
Markdown

# Phase 2: Complete Supabase Removal Plan
## Current Status
### ✅ Completed - Reports Integration
All three components now use Django API for reports operations:
- `ReportButton.tsx` - Uses `reportsService.submitReport()`
- `useModerationStats.ts` - Uses `reportsService.getStatistics()` for report stats
- `ReportsQueue.tsx` - Uses `reportsService.listReports()` and `reportsService.updateReportStatus()`
### ⚠️ Remaining Supabase Dependencies
#### ReportsQueue.tsx
1. **Line ~195-210: Reporter Profile Fetching**
```typescript
await supabase.rpc('get_users_with_emails')
// OR
await supabase.from('profiles').select(...)
```
**Django Endpoint Exists:** ✅ `GET /api/v1/users/` (batch fetch)
2. **Lines ~219-258: Related Content Fetching**
- Reviews: `supabase.from('reviews').select(...).in('id', reviewIds)`
- Profiles: `supabase.rpc('get_users_with_emails')`
- Submissions: `supabase.from('content_submissions').select(...).in('id', submissionIds)`
**Django Endpoints Exist:**
- ✅ `GET /api/v1/reviews/` (batch fetch with filters)
- ✅ `GET /api/v1/users/` (batch fetch)
- ✅ `GET /api/v1/moderation/submissions` (batch fetch)
3. **Lines ~385-401: Audit Logging**
```typescript
await supabase.rpc('log_admin_action', {...})
```
**Django Endpoint:** ❌ MISSING - needs to be created
#### useModerationStats.ts
1. **Lines ~81-84: Content Submissions Stats**
```typescript
await supabase.from('content_submissions')
.select('id', { count: 'exact', head: true })
.eq('status', 'pending')
```
**Django Endpoint:** ⚠️ EXISTS but needs stats endpoint
2. **Lines ~86-89: Flagged Reviews Stats**
```typescript
await supabase.from('reviews')
.select('id', { count: 'exact', head: true })
.eq('moderation_status', 'flagged')
```
**Django Endpoint:** ⚠️ EXISTS but needs count/stats endpoint
3. **Lines ~143-181: Realtime Subscriptions**
- Supabase realtime for submissions
- Supabase realtime for reviews
**Solution:** Convert to polling (already have polling code)
## Django API Audit
### ✅ Endpoints That Exist
#### Users/Auth (`/api/v1/auth/`)
- `GET /api/v1/users/` - List users with filters (supports batch via search)
- `GET /api/v1/users/{id}` - Get single user
- `GET /api/v1/me` - Get current user profile
#### Reviews (`/api/v1/reviews/`)
- `GET /api/v1/reviews/` - List reviews with filters
- `GET /api/v1/reviews/{id}` - Get single review
- Supports filtering by `entity_id`, `user_id`, `rating`, etc.
#### Content Submissions (`/api/v1/moderation/`)
- `GET /api/v1/moderation/submissions` - List submissions with pagination
- `GET /api/v1/moderation/submissions/{id}` - Get single submission
- Supports filtering by `status`
### ❌ Missing Django Endpoints
#### 1. Batch User Fetch by IDs
**Current:** `GET /api/v1/users/?search={query}` (not ideal for batch by IDs)
**Needed:** `GET /api/v1/users/batch?ids=id1,id2,id3`
**Alternative:** Use search with IDs or fetch individually (less efficient)
#### 2. Batch Reviews Fetch by IDs
**Current:** `GET /api/v1/reviews/?entity_id={id}` (filters by entity)
**Needed:** `GET /api/v1/reviews/batch?ids=id1,id2,id3`
**Alternative:** Fetch individually or filter by entity_id if all same entity
#### 3. Batch Submissions Fetch by IDs
**Current:** `GET /api/v1/moderation/submissions` (no ID filter)
**Needed:** `GET /api/v1/moderation/submissions/batch?ids=id1,id2,id3`
**Alternative:** Fetch individually
#### 4. Moderation Statistics Endpoint
**Needed:** `GET /api/v1/moderation/stats`
**Response:**
```json
{
"pending_submissions": 5,
"reviewing_submissions": 2,
"flagged_reviews": 3
}
```
#### 5. Audit Logging Endpoint
**Needed:** `POST /api/v1/audit/log`
**Request:**
```json
{
"action": "report_resolved",
"target_user_id": "uuid",
"details": {}
}
```
## Implementation Plan
### Phase 2A: Add Missing Django Endpoints (~2-3 hours)
#### 1. Add Batch Fetch Endpoints
**File: `django/api/v1/endpoints/auth.py`**
```python
@router.get("/users/batch", response={200: List[UserProfileOut]})
def batch_get_users(request, ids: str = Query(..., description="Comma-separated user IDs")):
"""Batch fetch users by IDs"""
user_ids = [id.strip() for id in ids.split(',')]
users = User.objects.filter(id__in=user_ids)
return list(users)
```
**File: `django/api/v1/endpoints/reviews.py`**
```python
@router.get("/batch", response={200: List[ReviewOut]})
def batch_get_reviews(request, ids: str = Query(..., description="Comma-separated review IDs")):
"""Batch fetch reviews by IDs"""
review_ids = [id.strip() for id in ids.split(',')]
reviews = Review.objects.filter(id__in=review_ids).select_related('user')
return [_serialize_review(review) for review in reviews]
```
**File: `django/api/v1/endpoints/moderation.py`**
```python
@router.get('/submissions/batch', response={200: List[ContentSubmissionOut]})
def batch_get_submissions(request, ids: str = Query(..., description="Comma-separated submission IDs")):
"""Batch fetch submissions by IDs"""
submission_ids = [id.strip() for id in ids.split(',')]
submissions = ContentSubmission.objects.filter(id__in=submission_ids)
return [_submission_to_dict(sub) for sub in submissions]
```
#### 2. Add Moderation Statistics Endpoint
**File: `django/api/v1/endpoints/moderation.py`**
```python
@router.get('/stats', response={200: ModerationStatsOut})
def get_moderation_stats(request):
"""Get moderation queue statistics"""
from django.db.models import Count, Q
from apps.reviews.models import Review
pending_submissions = ContentSubmission.objects.filter(
status='pending'
).count()
reviewing_submissions = ContentSubmission.objects.filter(
status='reviewing'
).count()
flagged_reviews = Review.objects.filter(
moderation_status='flagged'
).count()
return {
'pending_submissions': pending_submissions,
'reviewing_submissions': reviewing_submissions,
'flagged_reviews': flagged_reviews
}
```
#### 3. Add Audit Logging Endpoint
**File: `django/api/v1/endpoints/audit.py` (NEW)**
```python
from ninja import Router
from apps.users.permissions import jwt_auth, require_auth
router = Router(tags=['Audit'])
@router.post("/log", auth=jwt_auth, response={201: MessageSchema})
@require_auth
def log_admin_action(request, data: AdminActionLog):
"""Log an admin action for audit trail"""
# TODO: Implement audit logging
# Could use django-auditlog or custom model
return 201, {"message": "Action logged", "success": True}
```
### Phase 2B: Create Frontend Service Layers (~3-4 hours)
#### 1. Users Service (`src/services/users/`)
**Structure:**
```
src/services/users/
├── types.ts # User interfaces
├── mappers.ts # Data transformation
├── usersService.ts # API client
└── index.ts # Exports
```
**Key Methods:**
- `getUserProfile(userId: string)`
- `getUserProfiles(userIds: string[])` - batch fetch
- `getCurrentUser()`
#### 2. Reviews Service (`src/services/reviews/`)
**Structure:**
```
src/services/reviews/
├── types.ts
├── mappers.ts
├── reviewsService.ts
└── index.ts
```
**Key Methods:**
- `getReview(reviewId: string)`
- `getReviews(reviewIds: string[])` - batch fetch
- `getReviewsByEntity(entityType, entityId)`
#### 3. Submissions Service (`src/services/submissions/`)
**Structure:**
```
src/services/submissions/
├── types.ts
├── mappers.ts
├── submissionsService.ts
└── index.ts
```
**Key Methods:**
- `getSubmission(submissionId: string)`
- `getSubmissions(submissionIds: string[])` - batch fetch
- `getSubmissionStats()`
#### 4. Audit Service (`src/services/audit/`)
**Structure:**
```
src/services/audit/
├── types.ts
├── auditService.ts
└── index.ts
```
**Key Methods:**
- `logAdminAction(action, targetUserId, details)`
### Phase 2C: Update Components (~2-3 hours)
#### Update ReportsQueue.tsx
**Changes:**
1. Replace reporter profile fetching:
```typescript
// BEFORE
const { data: allProfiles } = await supabase.rpc('get_users_with_emails');
// AFTER
import { usersService } from '@/services/users';
const result = await usersService.getUserProfiles(reporterIds);
const profiles = result.success ? result.data : [];
```
2. Replace related content fetching:
```typescript
// BEFORE
const { data: reviewsData } = await supabase.from('reviews')
.select('id, title, content, rating')
.in('id', reviewIds);
// AFTER
import { reviewsService } from '@/services/reviews';
const result = await reviewsService.getReviews(reviewIds);
const reviewsData = result.success ? result.data : [];
```
3. Replace audit logging:
```typescript
// BEFORE
await supabase.rpc('log_admin_action', {...});
// AFTER
import { auditService } from '@/services/audit';
await auditService.logAdminAction(action, targetUserId, details);
```
4. Remove Supabase import
#### Update useModerationStats.ts
**Changes:**
1. Replace submission stats:
```typescript
// BEFORE
const { count } = await supabase.from('content_submissions')
.select('*', { count: 'exact', head: true })
.eq('status', 'pending');
// AFTER
import { submissionsService } from '@/services/submissions';
const result = await submissionsService.getStats();
const pendingSubmissions = result.success ? result.data.pending_submissions : 0;
```
2. Replace flagged reviews stats:
```typescript
// BEFORE
const { count } = await supabase.from('reviews')
.select('*', { count: 'exact', head: true })
.eq('moderation_status', 'flagged');
// AFTER
// Use moderation stats endpoint from submissions service
const flaggedContent = result.success ? result.data.flagged_reviews : 0;
```
3. Remove realtime subscriptions, rely on polling only
4. Remove Supabase import
### Phase 2D: Testing (~2 hours)
1. **Unit Tests**
- Test each service layer method
- Test data mappers
- Test error handling
2. **Integration Tests**
- Test component integration
- Test data flow
- Test error scenarios
3. **E2E Tests**
- Test complete report flow
- Test stats updates
- Test audit logging
## Estimated Timeline
| Phase | Task | Time | Dependencies |
|-------|------|------|--------------|
| 2A | Add Django endpoints | 2-3 hrs | None |
| 2B | Create service layers | 3-4 hrs | Phase 2A |
| 2C | Update components | 2-3 hrs | Phase 2B |
| 2D | Testing | 2 hrs | Phase 2C |
| **Total** | | **9-12 hrs** | |
## Alternative: Simplified Approach
If full batch endpoints are too much work, we can:
1. **Keep individual fetches** - Less efficient but simpler
2. **Use existing filter parameters** - e.g., filter by entity_id instead of batch IDs
3. **Skip audit logging** - Remove audit log calls entirely for now
This would reduce Phase 2A to just adding the moderation stats endpoint (~30 min).
## Recommendation
**Option 1: Full Implementation (9-12 hours)**
- Complete Supabase removal
- Optimal performance with batch endpoints
- Full feature parity
**Option 2: Simplified (4-6 hours)**
- Skip batch endpoints, fetch individually
- Add only stats endpoint
- Remove audit logging calls
- Still removes all Supabase dependencies
**Option 3: Phased Approach**
- Phase 2A: Stats endpoint only (30 min)
- Phase 2B: Service layers with individual fetches (2-3 hrs)
- Phase 2C: Update components (2-3 hrs)
- Phase 2D: Testing (2 hrs)
- **Total: 6.5-8.5 hours**
- Later: Add batch endpoints for optimization
## Decision Point
Which approach would you like to proceed with?
1. Full implementation with batch endpoints
2. Simplified without batch endpoints
3. Phased approach (recommended for incremental progress)