## 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!
96 lines
3.1 KiB
Go
96 lines
3.1 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"strconv"
|
|
|
|
"github.com/joho/godotenv"
|
|
)
|
|
|
|
type Config struct {
|
|
Port string
|
|
Env string
|
|
LogLevel string
|
|
DatabaseURL string
|
|
JWTSecret string
|
|
CORSOrigins string
|
|
RateLimitRPS int
|
|
SMTPHost string
|
|
SMTPPort int
|
|
SMTPUser string
|
|
SMTPPass string
|
|
SMTPFrom string
|
|
SenderAPIToken string
|
|
SendPulseID string
|
|
SendPulseSecret string
|
|
R2SigningSecret string
|
|
R2PublicBaseURL string
|
|
FirebaseCredentialsFile string
|
|
R2AccountID string
|
|
R2APIToken string
|
|
R2ImgDomain string
|
|
R2VidDomain string
|
|
R2Endpoint string
|
|
R2AccessKey string
|
|
R2SecretKey string
|
|
R2MediaBucket string
|
|
R2VideoBucket string
|
|
}
|
|
|
|
func LoadConfig() *Config {
|
|
// Try current directory first
|
|
err := godotenv.Load()
|
|
if err != nil {
|
|
// Try parent directory (common for VPS structure /opt/sojorn/.env while binary is in /opt/sojorn/go-backend)
|
|
_ = godotenv.Load("../.env")
|
|
// Try absolute path specified by user
|
|
_ = godotenv.Load("/opt/sojorn/.env")
|
|
}
|
|
|
|
return &Config{
|
|
Port: getEnv("PORT", "8080"),
|
|
Env: getEnv("ENV", "development"),
|
|
LogLevel: getEnv("LOG_LEVEL", "info"),
|
|
DatabaseURL: getEnv("DATABASE_URL", ""),
|
|
JWTSecret: getEnv("JWT_SECRET", ""),
|
|
CORSOrigins: getEnv("CORS_ORIGINS", "*"),
|
|
RateLimitRPS: getEnvInt("RATE_LIMIT_RPS", 10),
|
|
SMTPHost: getEnv("SMTP_HOST", "smtp.sender.net"),
|
|
SMTPPort: getEnvInt("SMTP_PORT", 587),
|
|
SMTPUser: getEnv("SMTP_USER", ""),
|
|
SMTPPass: getEnv("SMTP_PASS", ""),
|
|
SMTPFrom: getEnv("SMTP_FROM", "no-reply@gosojorn.com"),
|
|
SenderAPIToken: getEnv("SENDER_API_TOKEN", ""),
|
|
SendPulseID: getEnv("SENDPULSE_ID", ""),
|
|
SendPulseSecret: getEnv("SENDPULSE_SECRET", ""),
|
|
R2SigningSecret: getEnv("R2_SIGNING_SECRET", ""),
|
|
// Default to the public CDN domain to avoid mixed-content/http defaults.
|
|
R2PublicBaseURL: getEnv("R2_PUBLIC_BASE_URL", "https://img.gosojorn.com"),
|
|
FirebaseCredentialsFile: getEnv("FIREBASE_CREDENTIALS_FILE", "firebase-service-account.json"),
|
|
R2AccountID: getEnv("R2_ACCOUNT_ID", ""),
|
|
R2APIToken: getEnv("R2_API_TOKEN", ""),
|
|
R2ImgDomain: getEnv("R2_IMG_DOMAIN", "img.gosojorn.com"),
|
|
R2VidDomain: getEnv("R2_VID_DOMAIN", "quips.gosojorn.com"),
|
|
R2Endpoint: getEnv("R2_ENDPOINT", ""),
|
|
R2AccessKey: getEnv("R2_ACCESS_KEY", ""),
|
|
R2SecretKey: getEnv("R2_SECRET_KEY", ""),
|
|
R2MediaBucket: getEnv("R2_MEDIA_BUCKET", "sojorn-media"),
|
|
R2VideoBucket: getEnv("R2_VIDEO_BUCKET", "sojorn-videos"),
|
|
}
|
|
}
|
|
|
|
func getEnv(key, fallback string) string {
|
|
if value, exists := os.LookupEnv(key); exists {
|
|
return value
|
|
}
|
|
return fallback
|
|
}
|
|
|
|
func getEnvInt(key string, fallback int) int {
|
|
valueStr := getEnv(key, "")
|
|
if value, err := strconv.Atoi(valueStr); err == nil {
|
|
return value
|
|
}
|
|
return fallback
|
|
}
|