sojorn/sojorn_docs/SOCIAL_GRAPH_IMPLEMENTATION.md

170 lines
5.2 KiB
Markdown

# Social Graph & Privacy Implementation Status
## ✅ Completed Backend Features
### 1. Database Schema
- **Circle Members Table**: `public.circle_members` created with user_id/member_id pairs
- **SQL Function**: `is_in_circle(owner_id, user_id)` for efficient membership checks
- **Migration**: `20260204000002_circle_privacy.up.sql` ready to apply
### 2. Repository Methods (Go Backend)
#### Followers & Following
- `GetFollowers(ctx, userID, limit, offset)` - Returns paginated list with harmony scores/tiers
- `GetFollowing(ctx, userID, limit, offset)` - Returns paginated list with harmony scores/tiers
#### Circle Management
- `AddToCircle(ctx, userID, memberID)` - Add user to circle (validates following first)
- `RemoveFromCircle(ctx, userID, memberID)` - Remove from circle
- `GetCircleMembers(ctx, userID)` - List all circle members
- `IsInCircle(ctx, ownerID, userID)` - Check membership
#### Data Export
- `ExportUserData(ctx, userID)` - Complete export (profile, posts, following list)
### 3. API Endpoints
All routes registered in `cmd/api/main.go`:
```
GET /api/v1/users/:id/followers - Get user's followers list
GET /ap/v1/users/:id/following - Get list of users they follow
POST /api/v1/users/circle/:id - Add user to your circle
DELETE /api/v1/users/circle/:id - Remove user from circle
GET /api/v1/users/circle/members - Get your circle members
GET /api/v1/users/me/export - Export your complete data
```
## ⚠️ Remaining Implementation
### Circle Privacy in Feed Queries
Add this WHERE clause to `post_repository.go` in these methods:
- `GetFeed()` (line ~156)
- `GetPostsByAuthor()` (line ~243)
- `GetPostByID()` (line ~310)
**Code to add** (after the blocking check):
```go
AND (
p.visibility != 'circle' -- Non-circle posts visible to all
OR p.author_id = CASE WHEN $4::text != '' THEN $4::text::uuid ELSE NULL END -- Author sees own circle posts
OR public.is_in_circle(p.author_id, CASE WHENylt:text != '' THEN $4::text::uuid ELSE NULL END) -- Circle members see circle posts
)
```
### Frontend Flutter Implementation
#### 1. Update Following Screen (`lib/screens/profile/following_screen.dart`)
Replace `_generateMockData()` with real API call:
```dart
Future<void> _loadFollowing() async {
setState(() {
_isLoading = true;
_error = null;
});
try {
final api = ref.read(apiServiceProvider);
final currentUser = ref.read(currentUserProvider);
final data = await api.callGoApi(
'/users/${currentUser?.id}/following',
queryParams: {'limit': '20', 'offset': '${_followedUsers.length}'},
);
final List<FollowedUser> users = (data['following'] as List)
.map( (json) => FollowedUser.fromJson(json))
.toList();
setState(() {
_followedUsers = users;
});
} catch (e) {
setState(() {
_error = e.toString();
});
} finally {
setState(() {
_isLoading = false;
});
}
}
```
#### 2. Create Followers Screen
Create `lib/screens/profile/followers_screen.dart` - similar structure to `FollowingScreen` but calling `/users/:id/followers`.
#### 3. Add Circle Management Screen
Create `lib/screens/settings/circle_management_screen.dart`:
- List current circle members (GET `/users/circle/members`)
- Show "Add to Circle" button on following list
- Handle add (POST `/users/circle/:id`) and remove (DELETE `/users/circle/:id`)
#### 4. Data Export Button
In `lib/screens/settings/profile_settings_screen.dart`:
```dart
ListTile(
leading: Icon(Icons.download),
title: Text('Export My Data'),
subtitle: Text('Download your profile, posts, and connections'),
onTap: () async {
final api = ref.read(apiServiceProvider);
final data = await api.callGoApi('/users/me/export');
// Save to file
final file = File('${documentsDir}/sojorn_export.json');
await file.writeAsString(jsonEncode(data));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Data exported successfully!')),
);
},
)
```
#### 5. Circle Visibility in Compose
In `lib/screens/compose/compose_screen.dart`, ensure "Circle" option in visibility dropdown:
- Options: 'public', 'friends', 'circle'
- When "Circle" is selected, post won't appear in feed for non-circle members
## Migration Instructions
1. **Apply Database Migration**:
```bash
cd go-backend
migrate -path internal/database/migrations -database "your_db_url" up
```
2. **Restart Go Backend** to load new routes
3. **Test Endpoints**:
```bash
# Get followers
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8080/api/v1/users/USER_ID/followers"
# Export data
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8080/api/v1/users/me/export" > export.json
```
4. **Update Flutter App**:
- Implement the frontend screens listed above
- Test circle visibility by creating circle-only posts
- Verify data export downloads correctly
## Security Notes
- Circle membership is verified via `is_in_circle()` SQL function (performant, indexed)
- Blocked users cannot see any posts (via `has_block_between()`)
- Data export only returns user's own data (enforced by JWT user_id)
- All endpoints require authentication via JWT middleware