**Major Features Added:** - **Inline Reply System**: Replace compose screen with inline reply boxes - **Thread Navigation**: Parent/child navigation with jump functionality - **Chain Flow UI**: Reply counts, expand/collapse animations, visual hierarchy - **Enhanced Animations**: Smooth transitions, hover effects, micro-interactions **Frontend Changes:** - **ThreadedCommentWidget**: Complete rewrite with animations and navigation - **ThreadNode Model**: Added parent references and descendant counting - **ThreadedConversationScreen**: Integrated navigation handlers - **PostDetailScreen**: Replaced with threaded conversation view - **ComposeScreen**: Added reply indicators and context - **PostActions**: Fixed visibility checks for chain buttons **Backend Changes:** - **API Route**: Added /posts/:id/thread endpoint - **Post Repository**: Include allow_chain and visibility fields in feed - **Thread Handler**: Support for fetching post chains **UI/UX Improvements:** - **Reply Context**: Clear indication when replying to specific posts - **Character Counting**: 500 character limit with live counter - **Visual Hierarchy**: Depth-based indentation and styling - **Smooth Animations**: SizeTransition, FadeTransition, hover states - **Chain Navigation**: Parent/child buttons with visual feedback **Technical Enhancements:** - **Animation Controllers**: Proper lifecycle management - **State Management**: Clean separation of concerns - **Navigation Callbacks**: Reusable navigation system - **Error Handling**: Graceful fallbacks and user feedback This creates a Reddit-style threaded conversation experience with smooth animations, inline replies, and intuitive navigation between posts in a chain.
175 lines
5.5 KiB
Markdown
175 lines
5.5 KiB
Markdown
# Beacon System Architecture
|
|
|
|
## Overview
|
|
|
|
Sojorn has **two separate posting systems** that share the same database but create slightly different content:
|
|
|
|
1. **Regular Posts** (compose_screen.dart) - Standard social media posts
|
|
2. **Beacon Posts** (create-beacon_sheet.dart) - GPS-tagged safety alerts
|
|
|
|
## How It Works
|
|
|
|
### Database Structure
|
|
|
|
Both systems create records in the `posts` table, but with different flags:
|
|
|
|
| Field | Regular Post | Beacon Post |
|
|
|-------|-------------|-------------|
|
|
| `is_beacon` | `FALSE` | `TRUE` |
|
|
| `beacon_type` | `NULL` | `'police'`, `'checkpoint'`, `'taskForce'`, `'hazard'`, `'safety'`, or `'community'` |
|
|
| `location` | `NULL` | GPS coordinates (PostGIS POINT) |
|
|
| `confidence_score` | `NULL` | 0.5 - 1.0 (starts at 50-80% based on user trust) |
|
|
| `is_active_beacon` | `NULL` | `TRUE` (becomes `FALSE` when pruned) |
|
|
| `allow_chain` | User choice | Always `FALSE` |
|
|
|
|
### User Opt-In System
|
|
|
|
**Critical Feature**: Beacon posts are **OPT-IN ONLY** for feeds.
|
|
|
|
#### `profiles.beacon_enabled` Column
|
|
- **Default**: `FALSE` (opted out)
|
|
- **When FALSE**: User NEVER sees beacon posts in their Following or Sojorn feeds
|
|
- **When TRUE**: User sees beacon posts mixed in with regular posts
|
|
- **Beacon Map**: ALWAYS visible regardless of this setting
|
|
|
|
#### Why Opt-In?
|
|
|
|
Some users don't want safety alerts mixed into their social feed. The opt-in system allows:
|
|
- **Casual users**: Just social content
|
|
- **Community safety advocates**: Social content + beacons
|
|
- **Everyone**: Can still view the Beacon Network map anytime
|
|
|
|
### Feed Filtering Logic
|
|
|
|
#### feed-personal (Following Feed)
|
|
```typescript
|
|
// Check user's beacon preference
|
|
const { data: profile } = await supabase
|
|
.from("profiles")
|
|
.select("beacon_enabled")
|
|
.eq("id", user.id)
|
|
.single();
|
|
|
|
const beaconEnabled = profile?.beacon_enabled || false;
|
|
|
|
// Build query
|
|
let postsQuery = supabase.from("posts").select(...);
|
|
|
|
// Filter out beacons if user has NOT opted in
|
|
if (!beaconEnabled) {
|
|
postsQuery = postsQuery.eq("is_beacon", false);
|
|
}
|
|
```
|
|
|
|
#### feed-sojorn (Algorithmic Feed)
|
|
Same logic - beacons are filtered unless `beacon_enabled = TRUE`.
|
|
|
|
### Beacon Creation Flow
|
|
|
|
1. User opens Beacon Network tab
|
|
2. Taps map to drop beacon
|
|
3. Fills out CreateBeaconSheet:
|
|
- Type (police, checkpoint, etc.)
|
|
- Title
|
|
- Description
|
|
- Optional photo
|
|
4. Submits → Edge function `create-beacon`
|
|
5. **Creates a POST in the `posts` table** with:
|
|
- `is_beacon = TRUE`
|
|
- `beacon_type = <selected_type>`
|
|
- `location = GPS point`
|
|
- `category_id = "Beacon Alerts"` category
|
|
- `confidence_score` based on user's trust score
|
|
- `allow_chain = FALSE`
|
|
|
|
### Regular Post Creation Flow
|
|
|
|
1. User taps "New Post" button
|
|
2. Fills out ComposeScreen:
|
|
- Community selection
|
|
- Body text
|
|
- Optional photo
|
|
- Toggle for chain responses
|
|
3. Submits → Edge function `publish-post`
|
|
4. **Creates a POST in the `posts` table** with:
|
|
- `is_beacon = FALSE`
|
|
- No GPS data
|
|
- User-selected category
|
|
- User's chain preference
|
|
|
|
## Key Differences
|
|
|
|
| Feature | Regular Post | Beacon Post |
|
|
|---------|-------------|-------------|
|
|
| **Purpose** | Social sharing | Safety alerts |
|
|
| **GPS Data** | No | Required |
|
|
| **Visible On** | Feeds (if user follows author) | Beacon map + feeds (if user opted in) |
|
|
| **Category** | User selects | Always "Beacon Alerts" |
|
|
| **Chaining** | User choice | Disabled |
|
|
| **Confidence Score** | No | Yes (trust-based) |
|
|
| **Voting** | No | Yes (vouch/report) |
|
|
| **Auto-Pruning** | No | Yes (low confidence + old = disabled) |
|
|
|
|
## User Experience Scenarios
|
|
|
|
### Scenario 1: User With Beacons Disabled (Default)
|
|
```
|
|
Following Feed: ✓ Regular posts from people they follow
|
|
Sojorn Feed: ✓ Algorithmic regular posts
|
|
Beacon Map: ✓ All active beacons in area
|
|
```
|
|
|
|
### Scenario 2: User With Beacons Enabled
|
|
```
|
|
Following Feed: ✓ Regular posts + beacons from people they follow
|
|
Sojorn Feed: ✓ Algorithmic regular posts + beacons
|
|
Beacon Map: ✓ All active beacons in area
|
|
```
|
|
|
|
### Scenario 3: User Creates Beacon
|
|
1. Beacon appears on map IMMEDIATELY for ALL users
|
|
2. Beacon appears in creator's feed (if they have beacons enabled)
|
|
3. Beacon appears in OTHER users' feeds (if they follow creator AND have beacons enabled)
|
|
|
|
## Migration Required
|
|
|
|
To enable this system, run:
|
|
|
|
```sql
|
|
-- Add beacon_enabled column to profiles
|
|
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS beacon_enabled BOOLEAN NOT NULL DEFAULT FALSE;
|
|
|
|
-- Add index for fast filtering
|
|
CREATE INDEX IF NOT EXISTS idx_profiles_beacon_enabled ON profiles(beacon_enabled) WHERE beacon_enabled = TRUE;
|
|
```
|
|
|
|
Or apply the migration file:
|
|
```bash
|
|
# Via Supabase Dashboard SQL Editor
|
|
# Paste contents of: supabase/migrations/add_beacon_opt_in.sql
|
|
```
|
|
|
|
## Edge Functions Updated
|
|
|
|
1. ✅ **feed-personal** - Now filters beacons based on user preference
|
|
2. ✅ **feed-sojorn** - Now filters beacons based on user preference
|
|
3. ✅ **create-beacon** - Creates beacon posts correctly
|
|
4. ✅ **publish-post** - Creates regular posts correctly
|
|
|
|
## Frontend Components
|
|
|
|
- ✅ **ComposeScreen** - Regular post composer
|
|
- ✅ **CreateBeaconSheet** - Beacon post composer
|
|
- 🔲 **Settings Screen** - TODO: Add toggle for `beacon_enabled` preference
|
|
- ✅ **BeaconScreen** - Shows beacons on map (always visible)
|
|
- ✅ **FeedPersonalScreen** - Filtered feed
|
|
- ✅ **FeedSojornScreen** - Filtered feed
|
|
|
|
## Next Steps
|
|
|
|
1. Apply database migration (`add_beacon_opt_in.sql`)
|
|
2. Deploy updated edge functions
|
|
3. Add UI toggle in user settings for beacon opt-in
|
|
4. Test both posting flows
|
|
5. Verify feed filtering works correctly
|