mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 10:31:13 -05:00
402 lines
12 KiB
Markdown
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)
|