# Development & Architecture Comprehensive Guide ## Overview This guide consolidates all development, architecture, and design system documentation for the Sojorn platform, covering the philosophical foundations, technical architecture, and implementation patterns. --- ## Architecture Philosophy ### Core Principles Sojorn's calm is not aspirational—it is **structural**. The architecture enforces behavioral philosophy through database constraints, API design, and systematic patterns that make certain behaviors impossible, not just discouraged. ### 1. Blocking: Complete Disappearance **Principle**: When you block someone, they disappear from your world and you from theirs. **Implementation**: - Database function: `has_block_between(user_a, user_b)` checks bidirectional blocks - API middleware prevents blocked users from: - Seeing each other's profiles - Seeing each other's posts - Seeing each other's follows - Interacting in any way **Effect**: No notifications, no traces, no conflict. The system enforces separation silently. ### 2. Consent: Conversation Requires Mutual Follow **Principle**: You cannot reply to someone unless you mutually follow each other. **Implementation**: - Database function: `is_mutual_follow(user_a, user_b)` verifies bidirectional following - Comment creation requires mutual follow relationship - API endpoints enforce conversation gating **Effect**: Unwanted replies are impossible. Conversation is opt-in by structure. ### 3. Exposure: Opt-In by Default **Principle**: Users choose what content they see. Filtering is private and encouraged. **Implementation**: - All categories except `general` have `default_off = true` - Users must explicitly enable categories to see posts - Feed algorithms respect user preferences **Effect**: Users control their content exposure without social pressure. --- ## Technical Architecture ### System Overview ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Flutter App │ │ Go Backend │ │ PostgreSQL │ │ │ │ │ │ │ │ - UI/UX │◄──►│ - REST API │◄──►│ - Data Store │ │ - State Mgmt │ │ - Business Logic│ │ - Constraints │ │ - Navigation │ │ - Validation │ │ - Functions │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ │ │ │ ▼ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Local Storage │ │ File System │ │ Extensions │ │ │ │ │ │ │ │ - Secure Storage│ │ - Uploads │ │ - PostGIS │ │ - Cache │ │ - Logs │ │ - pg_trgm │ │ - Preferences │ │ - Temp Files │ │ - uuid-ossp │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` ### Backend Architecture #### Layer Structure ``` ┌─────────────────────────────────────────┐ │ API Layer │ │ ┌─────────────┐ ┌─────────────────┐ │ │ │ Gin │ │ Middleware │ │ │ │ Router │ │ - Auth │ │ │ │ │ │ - CORS │ │ │ │ │ │ - Rate Limit │ │ │ └─────────────┘ └─────────────────┘ │ └─────────────────────────────────────────┘ ┌─────────────────────────────────────────┐ │ Service Layer │ │ ┌─────────────┐ ┌─────────────────┐ │ │ │ Business │ │ External │ │ │ │ Logic │ │ Services │ │ │ │ │ │ - FCM │ │ │ │ │ │ - R2 Storage │ │ │ └─────────────┘ └─────────────────┘ │ └─────────────────────────────────────────┘ ┌─────────────────────────────────────────┐ │ Repository Layer │ │ ┌─────────────┐ ┌─────────────────┐ │ │ │ Data │ │ Database │ │ │ │ Access │ │ - PostgreSQL │ │ │ │ │ │ - Migrations │ │ │ │ │ │ - Queries │ │ │ └─────────────┘ └─────────────────┘ │ └─────────────────────────────────────────┘ ``` #### Key Components **1. Authentication & Authorization** - JWT-based authentication with refresh tokens - Role-based access control - Session management with secure cookies **2. Data Validation** - Structured request/response models - Input sanitization and validation - Error handling with proper HTTP status codes **3. Business Logic Services** - User management and relationships - Content moderation and filtering - Notification and messaging systems **4. External Integrations** - Firebase Cloud Messaging - Cloudflare R2 storage - Email services ### Database Architecture #### Core Schema Design **Identity & Relationships** ```sql profiles (users, identity, settings) ├── follows (mutual relationships) ├── blocks (complete separation) └── user_category_settings (content preferences) ``` **Content & Engagement** ```sql posts (content, metadata) ├── post_metrics (engagement data) ├── post_likes (boosts only) ├── post_saves (private bookmarks) └── comments (mutual-follow-only) ``` **Moderation & Trust** ```sql reports (community moderation) ├── trust_state (harmony scoring) └── audit_log (transparency trail) ``` #### Database Functions **Relationship Checking** ```sql -- Bidirectional blocking CREATE OR REPLACE FUNCTION has_block_between(user_a UUID, user_b UUID) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT 1 FROM blocks WHERE (blocker_id = user_a AND blocked_id = user_b) OR (blocker_id = user_b AND blocked_id = user_a) ); $$ LANGUAGE SQL; -- Mutual follow verification CREATE OR REPLACE FUNCTION is_mutual_follow(user_a UUID, user_b UUID) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT 1 FROM follows f1 JOIN follows f2 ON f1.follower_id = f2.following_id AND f1.following_id = f2.follower_id WHERE f1.follower_id = user_a AND f1.following_id = user_b ); $$ LANGUAGE SQL; ``` **Rate Limiting** ```sql -- Posting rate limits CREATE OR REPLACE FUNCTION can_post(user_id UUID) RETURNS BOOLEAN AS $$ SELECT get_post_rate_limit(user_id) > 0; $$ LANGUAGE SQL; ``` --- ## Design System ### Visual Philosophy **Calm, Not Sterile** - Warm neutrals (beige/paper tones) instead of cold grays - Soft shadows, never harsh - Muted semantic colors that inform without alarming **Modern, Not Trendy** - Timeless color palette - Classic typography hierarchy - Subtle animations and transitions **Text-Forward** - Generous line height (1.6-1.65 for body text) - Optimized for reading, not scanning - Clear hierarchy without relying on color **Intentionally Slow** - Animation durations: 300-400ms - Ease curves that feel deliberate - No jarring transitions ### Color System #### Background Palette ```dart background = #F8F7F4 // Warm off-white (like paper) surface = #FFFFFD // Barely warm white surfaceElevated = #FFFFFF // Pure white for cards surfaceVariant = #F0EFEB // Subtle warm gray (inputs) ``` #### Semantic Colors ```dart primary = #6B5B95 // Soft purple (calm authority) secondary = #8B7355 // Warm brown (earth tone) success = #6B8E6F // Muted green (gentle confirmation) warning = #B8956A // Soft amber (warm caution) error = #B86B6B // Muted rose (gentle error) ``` #### Border System ```dart borderSubtle = #E8E6E1 // Barely visible dividers border = #D8D6D1 // Default borders borderStrong = #C8C6C1 // Emphasized borders ``` ### Typography #### Font Hierarchy ```dart // Display displayLarge = 32px / 48px / 300 displayMedium = 28px / 42px / 300 displaySmall = 24px / 36px / 300 // Headings headlineLarge = 20px / 30px / 400 headlineMedium = 18px / 27px / 400 headlineSmall = 16px / 24px / 500 // Body bodyLarge = 16px / 26px / 400 bodyMedium = 14px / 22px / 400 bodySmall = 12px / 20px / 400 // Labels labelLarge = 14px / 20px / 500 labelMedium = 12px / 16px / 500 labelSmall = 10px / 14px / 500 ``` #### Typography Principles - **Line Height**: 1.6-1.65 for body text (optimized for reading) - **Font Weight**: Conservative use (300-500, rarely 700) - **Letter Spacing**: Subtle adjustments for readability - **Color**: Primary use of gray scale, semantic colors sparingly ### Component System #### Buttons ```dart // Primary Button ButtonStyle( backgroundColor: MaterialStateProperty.all(primary), foregroundColor: MaterialStateProperty.all(surface), elevation: MaterialStateProperty.all(2), padding: MaterialStateProperty.all( EdgeInsets.symmetric(horizontal: 24, vertical: 16) ), shape: MaterialStateProperty.all( RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)) ) ) // Secondary Button ButtonStyle( backgroundColor: MaterialStateProperty.all(surfaceVariant), foregroundColor: MaterialStateProperty.all(primary), elevation: MaterialStateProperty.all(1), // ... same padding and shape ) ``` #### Cards ```dart Card( elevation: 3, shadowColor: Colors.black.withOpacity(0.1), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12) ), child: Padding( padding: EdgeInsets.all(16), child: // content ) ) ``` #### Input Fields ```dart InputDecoration( filled: true, fillColor: surfaceVariant, border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide(color: border) ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide(color: primary, width: 2) ), contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 12) ) ``` --- ## Development Patterns ### Code Organization #### Flutter Structure ``` lib/ ├── main.dart # App entry point ├── config/ # Configuration │ ├── api_config.dart │ └── theme_config.dart ├── models/ # Data models │ ├── user.dart │ ├── post.dart │ └── chat.dart ├── providers/ # State management │ ├── auth_provider.dart │ ├── feed_provider.dart │ └── theme_provider.dart ├── services/ # Business logic │ ├── api_service.dart │ ├── auth_service.dart │ └── notification_service.dart ├── screens/ # UI screens │ ├── auth/ │ ├── home/ │ └── chat/ ├── widgets/ # Reusable components │ ├── post_card.dart │ ├── user_avatar.dart │ └── chat_bubble.dart └── utils/ # Utilities ├── constants.dart ├── helpers.dart └── validators.dart ``` #### Go Structure ``` cmd/ └── api/ └── main.go # Application entry internal/ ├── config/ # Configuration │ └── config.go ├── models/ # Data models │ ├── user.go │ ├── post.go │ └── chat.go ├── handlers/ # HTTP handlers │ ├── auth_handler.go │ ├── post_handler.go │ └── chat_handler.go ├── services/ # Business logic │ ├── auth_service.go │ ├── post_service.go │ └── notification_service.go ├── repository/ # Data access │ ├── user_repository.go │ ├── post_repository.go │ └── chat_repository.go ├── middleware/ # HTTP middleware │ ├── auth.go │ ├── cors.go │ └── ratelimit.go └── database/ # Database ├── migrations/ └── queries.go ``` ### State Management Patterns #### Flutter Provider Pattern ```dart // Authentication Provider final authServiceProvider = Provider((ref) { return AuthService(); }); final currentUserProvider = Provider((ref) { final authService = ref.watch(authServiceProvider); ref.watch(authStateProvider); return authService.currentUser; }); final authStateProvider = StreamProvider((ref) { final authService = ref.watch(authServiceProvider); return authService.authStateChanges; }); ``` #### Go Service Pattern ```dart // Service Interface type PostService interface { CreatePost(ctx context.Context, req *CreatePostRequest) (*Post, error) GetFeed(ctx context.Context, userID string, pagination *Pagination) ([]*Post, error) LikePost(ctx context.Context, userID, postID string) error } // Service Implementation type postService struct { postRepo repository.PostRepository userRepo repository.UserRepository notifier services.NotificationService } func NewPostService(postRepo, userRepo repository.PostRepository, notifier services.NotificationService) PostService { return &postService{ postRepo: postRepo, userRepo: userRepo, notifier: notifier, } } ``` ### Error Handling Patterns #### Flutter Error Handling ```dart // Result Type class Result { final T? data; final String? error; Result.success(this.data) : error = null; Result.error(this.error) : data = null; bool get isSuccess => error == null; bool get isError => error != null; } // Usage Future> createPost(CreatePostRequest request) async { try { final post = await apiService.createPost(request); return Result.success(post); } catch (e) { return Result.error(e.toString()); } } ``` #### Go Error Handling ```go // Custom Error Types type ValidationError struct { Field string Message string } func (e ValidationError) Error() string { return fmt.Sprintf("validation error on %s: %s", e.Field, e.Message) } // Service Error Handling func (s *postService) CreatePost(ctx context.Context, req *CreatePostRequest) (*Post, error) { if err := req.Validate(); err != nil { return nil, ValidationError{Field: "request", Message: err.Error()} } post, err := s.postRepo.Create(ctx, req) if err != nil { return nil, fmt.Errorf("failed to create post: %w", err) } return post, nil } ``` --- ## Testing Strategy ### Flutter Testing #### Unit Tests ```dart // Example: Post Service Test void main() { group('PostService', () { late MockApiService mockApiService; late PostService postService; setUp(() { mockApiService = MockApiService(); postService = PostService(mockApiService); }); test('createPost should return post on success', () async { // Arrange final mockPost = Post(id: '1', content: 'Test post'); when(mockApiService.createPost(any)) .thenAnswer((_) async => mockPost); // Act final result = await postService.createPost(CreatePostRequest(content: 'Test post')); // Assert expect(result.isSuccess, true); expect(result.data?.content, 'Test post'); }); }); } ``` #### Widget Tests ```dart void main() { testWidgets('PostCard displays post content', (WidgetTester tester) async { // Arrange final post = Post(id: '1', content: 'Test post', author: User(name: 'Test User')); // Act await tester.pumpWidget( MaterialApp( home: PostCard(post: post), ), ); // Assert expect(find.text('Test post'), findsOneWidget); expect(find.text('Test User'), findsOneWidget); }); } ``` ### Go Testing #### Unit Tests ```go func TestPostService_CreatePost(t *testing.T) { tests := []struct { name string request *CreatePostRequest want *Post wantErr bool }{ { name: "valid request", request: &CreatePostRequest{ UserID: "user123", Content: "Test post", }, want: &Post{ ID: "post123", UserID: "user123", Content: "Test post", }, wantErr: false, }, { name: "invalid request", request: &CreatePostRequest{ UserID: "", Content: "Test post", }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockRepo := &MockPostRepository{} service := NewPostService(mockRepo, nil, nil) if !tt.wantErr { mockRepo.On("Create", mock.Anything, tt.request).Return(tt.want, nil) } got, err := service.CreatePost(context.Background(), tt.request) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) assert.Equal(t, tt.want, got) } mockRepo.AssertExpectations(t) }) } } ``` --- ## Performance Optimization ### Flutter Performance #### Key Optimizations 1. **Const Constructors**: Use `const` for immutable widgets 2. **Lazy Loading**: Implement `ListView.builder` for large lists 3. **Image Caching**: Use `cached_network_image` for remote images 4. **State Management**: Minimize rebuilds with selective providers #### Example: Optimized List View ```dart ListView.builder( itemCount: posts.length, itemBuilder: (context, index) { return PostCard( key: ValueKey(posts[index].id), post: posts[index], ); }, ) ``` ### Go Performance #### Database Optimizations 1. **Connection Pooling**: Configure appropriate pool sizes 2. **Query Optimization**: Use prepared statements and proper indexes 3. **Caching**: Implement Redis for frequently accessed data #### Example: Database Configuration ```go config, err := pgxpool.ParseConfig(databaseURL) if err != nil { return nil, err } config.MaxConns = 25 config.MinConns = 5 config.MaxConnLifetime = time.Hour config.HealthCheckPeriod = time.Minute * 5 pool, err := pgxpool.NewWithConfig(context.Background(), config) ``` --- ## Security Considerations ### Authentication Security - JWT tokens with proper expiration - Secure token storage (FlutterSecureStorage) - Refresh token rotation - Rate limiting on auth endpoints ### Data Protection - Input validation and sanitization - SQL injection prevention with parameterized queries - XSS protection in web views - CSRF protection for state-changing operations ### Privacy Protection - Data minimization in API responses - Anonymous analytics collection - User data export and deletion capabilities - GDPR compliance considerations --- ## Deployment Architecture ### Production Stack ``` Internet ↓ Nginx (SSL Termination, Static Files) ↓ Go Backend (API, Business Logic) ↓ PostgreSQL (Data, PostGIS) ↓ File System (Uploads) / Cloudflare R2 ``` ### Environment Configuration - **Development**: Local PostgreSQL, mock services - **Staging**: Production-like environment with test data - **Production**: Full stack with monitoring and backups ### Monitoring & Observability - **Application Metrics**: Request latency, error rates, user activity - **Infrastructure Metrics**: CPU, memory, disk usage - **Database Metrics**: Query performance, connection pool status - **Business Metrics**: User engagement, content creation rates --- **Last Updated**: January 30, 2026 **Version**: 1.0 **Next Review**: February 15, 2026