# Sojorn Development TODO

**Last Updated**: February 7, 2026

---

## 🎯 High Priority — Feature Work

### 1. Finalize AI Moderation — Image & Video
**Status**: In Progress  
Text moderation is live (OpenAI Moderation API). Image and video moderation not yet implemented.

- [ ] Add image moderation to post creation flow (send image to OpenAI or Vision API)
- [ ] Add video moderation via thumbnail extraction (grab first frame or key frame)
- [ ] Run extracted thumbnail through same image moderation pipeline
- [ ] Flag content that exceeds thresholds into `moderation_flags` table
- [ ] Wire into existing Three Poisons scoring (Hate, Greed, Delusion)
- [ ] Add admin queue visibility for image/video flags

**Backend**: `go-backend/internal/handlers/post_handler.go` (CreatePost flow)  
**Key decision**: Use OpenAI Vision API for images, ffmpeg thumbnail extraction for video on the server side

---

### 2. Quips — Complete Video Recorder & Editor Overhaul
**Status**: Needs major work  
Current recorder is basic. Goal: TikTok/Instagram-level recording and editing experience.

- [ ] Multi-segment recording with pause/resume
- [ ] Speed control (0.5x, 1x, 2x, 3x)
- [ ] Filters and effects (color grading, beauty mode)
- [ ] Text overlays with timing and positioning
- [ ] Music/audio overlay from library or device
- [ ] Trim and reorder clips
- [ ] Transitions between segments
- [ ] Preview before posting
- [ ] Progress indicator during upload
- [ ] Thumbnail selection for posted quip

**Frontend**: `sojorn_app/lib/screens/quips/create/`  
**Packages to evaluate**: `camera`, `ffmpeg_kit_flutter`, `video_editor`

---

### 3. Beacon Page Overhaul — Local Safety & Social Awareness
**Status**: Basic beacon system exists (post, vouch, report). Needs full redesign.  
Vision: Citizen + Nextdoor but focused on social awareness over fear-mongering.

- [ ] Redesign beacon feed as a local safety dashboard
- [ ] Map view with clustered pins (incidents, community alerts, mutual aid)
- [ ] Beacon categories: Safety Alert, Community Need, Lost & Found, Event, Mutual Aid
- [ ] Verified/official source badges for local orgs
- [ ] "How to help" action items on each beacon (donate, volunteer, share)
- [ ] Tone guidelines — auto-moderate fear-bait and rage-bait language
- [ ] Neighborhood/radius filtering
- [ ] Push notifications for nearby beacons (opt-in)
- [ ] Confidence scoring visible to users (vouch/report ratio)
- [ ] Resolution status (active → resolved → archived)

**Backend**: `go-backend/internal/handlers/post_handler.go` (beacon endpoints)  
**Frontend**: `sojorn_app/lib/screens/beacons/`

---

## ⚠️ Medium Priority — Core Features

### 4. User Profile Customization — Modular Widget System
**Status**: Basic profiles exist. Needs a modular, personalized approach.  
Vision: New-age MySpace — users pick and arrange profile widgets to make it their own, without chaos.

**Core Architecture:**
- Profile is a grid/stack of draggable **widgets** the user can add, remove, and reorder
- Each widget is a self-contained component with a fixed max size and style boundary
- Widgets render inside a consistent design system (can't break the layout or go full HTML)
- Profile data stored as a JSON `profile_layout` column: ordered list of widget types + config

**Standard Fields (always present):**
- [ ] Avatar + display name + handle (non-removable header)
- [ ] Bio (rich text, links, emoji)
- [ ] Pronouns field
- [ ] Location (optional, city-level)

**Widget Catalog (user picks and arranges):**
- [ ] **Pinned Posts** — Pin up to 3 posts to the top of your profile
- [ ] **Music Widget** — Currently listening / favorite track (Spotify/Apple Music embed or manual)
- [ ] **Photo Grid** — Mini gallery (3-6 featured photos from uploads)
- [ ] **Social Links** — Icons row for external links (site, GitHub, IG, etc.)
- [ ] **Causes I Care About** — Tag-style badges (environment, mutual aid, arts, etc.)
- [ ] **Featured Friends** — Highlight 3-6 people (like MySpace Top 8 but chill)
- [ ] **Stats Widget** — Post count, follower count, member since (opt-in)
- [ ] **Quote Widget** — A single styled quote / motto
- [ ] **Beacon Activity** — Recent community contributions
- [ ] **Custom Text Block** — Markdown-rendered freeform section

**Theming (constrained but expressive):**
- [ ] Accent color picker (applies to profile header, widget borders, link color)
- [ ] Light/dark/auto profile theme (independent of app theme)
- [ ] Banner image (behind header area)
- [ ] Profile badges (verified, early adopter, community helper — system-assigned)

**Implementation:**
- [ ] Backend: `profile_layout JSONB` column on `profiles` table
- [ ] Backend: `PUT /profile/layout` endpoint to save widget arrangement
- [ ] Frontend: `ProfileWidgetRenderer` that reads layout JSON and renders widget stack
- [ ] Frontend: `ProfileEditor` with drag-to-reorder and add/remove widget catalog
- [ ] Widget sandboxing — each widget has max height, no custom CSS/HTML injection
- [ ] Default layout for new users (bio + social links + pinned posts)

---

### 5. Blocking System
**Status**: Basic block exists. Import/export not implemented.

- [ ] Verify block prevents: seeing posts, DMs, mentions, search results, follow
- [ ] Block list management screen (view, unblock)
- [ ] Export block list as JSON/CSV
- [ ] Import block list from JSON/CSV
- [ ] Import block list from other platforms (Twitter/X format, Mastodon format)
- [ ] Blocked users cannot see your profile or posts
- [ ] Silent block (user doesn't know they're blocked)

**Frontend**: `sojorn_app/lib/screens/profile/blocked_users_screen.dart`  
**Backend**: `go-backend/internal/handlers/user_handler.go`

---

### 6. E2EE Chat Stability & Sync
**Status**: X3DH implementation works but key sync across devices is fragile.

- [ ] Audit key recovery flow — ensure it reliably recovers from MAC errors
- [ ] Device-to-device key sync without storing plaintext on server
- [ ] QR code key verification between users
- [ ] "Encrypted with old keys" messages should offer re-request option
- [ ] Clean up `forceResetBrokenKeys()` dead code in `simple_e2ee_service.dart`
- [ ] Ensure cloud backup/restore cycle works end-to-end
- [ ] Add key fingerprint display in chat settings
- [ ] Rate limit key recovery to prevent loops

---

### 7. Repost / Boost Feature
**Status**: Not started.  
A "repost" action that amplifies content to your followers without quote-posting.

- [ ] Repost button on posts (share to your followers' feeds)
- [ ] Repost count displayed on posts
- [ ] Reposted-by attribution in feed ("@user reposted")
- [ ] Undo repost
- [ ] Backend: `reposts` table (user_id, post_id, created_at)
- [ ] Feed algorithm weights reposts into feed ranking

---

### 8. Algorithm Refactor — Promote Good, Discourage Anger
**Status**: Basic algorithm exists in `algorithm_config` table. Needs philosophical overhaul.  
Core principle: **Show users what they love, not what they hate.**

- [ ] Engagement scoring that weights positive interactions (save, repost, thoughtful reply) over rage-clicks
- [ ] De-rank content with high negative-reaction ratios
- [ ] "Cooling period" — delay viral anger content by 30min before amplifying
- [ ] Boost content tagged as good news, community, mutual aid, creativity
- [ ] User-controllable feed preferences ("show me more of X, less of Y")
- [ ] Diversity injection — prevent echo chambers by mixing in adjacent-interest content
- [ ] Transparency: show users why a post appeared in their feed
- [ ] Admin algorithm tuning panel (already built in admin dashboard)
- [ ] A/B testing framework for algorithm changes

---

## 🔧 Low Priority — Polish & Cleanup

### 9. Remaining Code TODOs
Small scattered items across the codebase:

- [ ] `sojorn_rich_text.dart` — Implement profile navigation from @mentions
- [ ] `post_with_video_widget.dart` — Implement post options menu (edit, delete, report)
- [ ] `video_player_with_comments.dart` — Implement "more options" button
- [ ] `sojorn_swipeable_post.dart` — Wire up allowChain setting when API supports it
- [ ] `reading_post_card.dart` — Implement share functionality

### 10. Legacy Cleanup
- [ ] Delete `go-backend/cmd/supabase-migrate/` directory (dead migration tool)
- [ ] Update 2 stale Supabase comments in `go-backend/internal/middleware/auth.go`
- [ ] Remove `forceResetBrokenKeys()` from `simple_e2ee_service.dart`

---

## ✅ Completed

### Core Platform (shipped)
- ✅ Go backend — 100% migrated from Supabase
- ✅ User auth (JWT, refresh tokens, email verification)
- ✅ Posts (create, edit, delete, visibility, chains)
- ✅ Comments (threaded, with replies)
- ✅ Feed algorithm (basic version)
- ✅ Image/video uploads to Cloudflare R2
- ✅ Follow/unfollow system
- ✅ Search (users, posts, hashtags)
- ✅ Categories and user settings
- ✅ Chain posts
- ✅ Beacon voting (vouch, report, remove vote)
- ✅ E2EE chat (X3DH, key backup/restore)
- ✅ Push notifications (FCM)
- ✅ Quips (basic video recording and feed)

### Admin & Moderation (shipped)
- ✅ Admin panel (Next.js dashboard, users, posts, moderation queue, appeals)
- ✅ OpenAI text moderation (auto-flag on post/comment creation)
- ✅ Three Poisons scoring (Hate, Greed, Delusion)
- ✅ Ban/suspend system with content jailing
- ✅ Email notifications (ban, suspend, restore, content removal)
- ✅ Moderation queue with dismiss/action/ban workflows
- ✅ User violation tracking and history
- ✅ IP-based ban evasion detection

### Infrastructure (shipped)
- ✅ PostgreSQL with full schema
- ✅ Cloudflare R2 media storage
- ✅ Nginx reverse proxy + SSL/TLS
- ✅ Systemd service management
- ✅ GeoIP for location features
- ✅ Automated deploy scripts

### NSFW Moderation System (Feb 7, 2026)
- ✅ AI moderation prompt: Cinemax nudity rule, violence 1-10 scale (≤5 allowed)
- ✅ Three-outcome moderation: clean / nsfw (auto-label + warn) / flag (remove + appeal email)
- ✅ DB: `nsfw_blur_enabled` column on `user_settings`
- ✅ Backend: `is_nsfw`/`nsfw_reason` returned from ALL post queries (feed, profile, detail, saved, liked, chain, focus context)
- ✅ Backend: NSFW posts excluded from search, discover, trending, hashtag pages
- ✅ Backend: NSFW in feed limited to own posts + followed users only
- ✅ Backend: `nsfw_warning` and `content_removed` notification types + appeal email
- ✅ Backend: user self-labeling (`is_nsfw` in CreatePost)
- ✅ Flutter: NSFW opt-in toggle + blur toggle in settings (hidden behind expandable at bottom)
- ✅ Flutter: 18+ confirmation dialog for enabling NSFW (moderation rules, not a free-for-all)
- ✅ Flutter: 18+ confirmation dialog for disabling blur (disturbing content warning)
- ✅ Flutter: 6-click path to enable (profile → settings → expand → toggle → confirm → enable)
- ✅ Flutter: blur enforced everywhere — post card, threaded conversation, parent preview, replies
- ✅ Flutter: NSFW self-label toggle in compose toolbar
- ✅ Flutter: `publishPost` API sends `is_nsfw`/`nsfw_reason`

### Recent Fixes (Feb 2026)
- ✅ Notification badge count clears on archive
- ✅ Notification UI → full page (was slide-up dialog)
- ✅ Moderation queue constraint fix (dismissed/actioned statuses)
- ✅ Debug print cleanup (190+ statements removed)
- ✅ Run scripts cleanup (run_dev, run_web, run_web_chrome)
