## Phase 1: Critical Feature Completion (Beacon Voting) - Add VouchBeacon, ReportBeacon, RemoveBeaconVote methods to PostRepository - Implement beacon voting HTTP handlers with confidence score calculations - Register new beacon routes: /beacons/:id/vouch, /beacons/:id/report, /beacons/:id/vouch (DELETE) - Auto-flag beacons at 5+ reports, confidence scoring (0.5 base + 0.1 per vouch) ## Phase 2: Feed Logic & Post Distribution Integrity - Verify unified feed logic supports all content types (Standard, Quips, Beacons) - Ensure proper distribution: Profile Feed + Main/Home Feed for followers - Beacon Map integration for location-based content - Video content filtering for Quips feed ## Phase 3: The Notification System - Create comprehensive NotificationService with FCM integration - Add CreateNotification method to NotificationRepository - Implement smart deep linking: beacon_map, quip_feed, main_feed - Trigger notifications for beacon interactions and cross-post comments - Push notification logic with proper content type detection ## Phase 4: The Great Supabase Purge - Delete function_proxy.go and remove /functions/:name route - Remove SupabaseURL, SupabaseKey from config.go - Remove SupabaseID field from User model - Clean all Supabase imports and dependencies - Sanitize codebase of legacy Supabase references ## Phase 5: Flutter Frontend Integration - Implement vouchBeacon(), reportBeacon(), removeBeaconVote() in ApiService - Replace TODO delay in video_comments_sheet.dart with actual publishComment call - Fix compilation errors (named parameters, orphaned child properties) - Complete frontend integration with Go API endpoints ## Additional Improvements - Fix compilation errors in threaded_comment_widget.dart (orphaned child property) - Update video_comments_sheet.dart to use proper named parameters - Comprehensive error handling and validation - Production-ready notification system with deep linking ## Migration Status: 100% Complete - Backend: Fully migrated from Supabase to custom Go/Gin API - Frontend: Integrated with new Go endpoints - Notifications: Complete FCM integration with smart routing - Database: Clean of all Supabase dependencies - Features: All functionality preserved and enhanced Ready for VPS deployment and production testing!
726 lines
21 KiB
Markdown
726 lines
21 KiB
Markdown
# 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<Color>(primary),
|
|
foregroundColor: MaterialStateProperty.all<Color>(surface),
|
|
elevation: MaterialStateProperty.all<double>(2),
|
|
padding: MaterialStateProperty.all<EdgeInsets>(
|
|
EdgeInsets.symmetric(horizontal: 24, vertical: 16)
|
|
),
|
|
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
|
|
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))
|
|
)
|
|
)
|
|
|
|
// Secondary Button
|
|
ButtonStyle(
|
|
backgroundColor: MaterialStateProperty.all<Color>(surfaceVariant),
|
|
foregroundColor: MaterialStateProperty.all<Color>(primary),
|
|
elevation: MaterialStateProperty.all<double>(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<AuthService>((ref) {
|
|
return AuthService();
|
|
});
|
|
|
|
final currentUserProvider = Provider<User?>((ref) {
|
|
final authService = ref.watch(authServiceProvider);
|
|
ref.watch(authStateProvider);
|
|
return authService.currentUser;
|
|
});
|
|
|
|
final authStateProvider = StreamProvider<AuthState>((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<T> {
|
|
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<Result<Post>> 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
|