# Know Foolery - Technical Architecture Documentation ## Architecture Overview Know Foolery follows a microservices architecture with clear separation between frontend presentation, backend services, and data persistence layers. The system is designed for cross-platform compatibility, scalability, and maintainability. ## System Architecture Diagram ``` ┌────────────────────────────────────────────────────────────────────────────┐ │ Client Layer │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Web App │ │ Mobile iOS │ │ Mobile Androi│ │ Desktop ctr│ │ │ │ (React) │ │(React Native)│ │(React Native)│ │ (Wails) │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │ └────────────────────────────────────────────────────────────────────────────┘ │ HTTPS/WSS │ ┌─────────────────────────────────────────────────────────────────────────────┐ │ API Gateway Layer │ │ ┌────────────────────────────────────────────────────────────────────────┐ │ │ │ NGINX + API Gateway Service (Go) │ │ │ │ • Authentication & Authorization │ │ │ │ • Rate Limiting & CORS │ │ │ │ • Request Routing & Load Balancing │ │ │ │ • Security Headers & Input Validation │ │ │ └────────────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ │ gRPC/HTTP │ ┌─────────────────────────────────────────────────────────────────────────────┐ │ Microservices Layer │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Game │ │ Question │ │ User │ │ Leaderboard │ │ │ │ Service │ │ Service │ │ Service │ │ Service │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │ ┌─────────────┐ ┌─────────────┐ │ │ │ Session │ │ Admin │ │ │ │ Service │ │ Service │ │ │ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ │ Database Connections │ ┌─────────────────────────────────────────────────────────────────────────────┐ │ Data & External Layer │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ PostgreSQL │ │ Redis │ │ Zitadel │ │ Observabi- │ │ │ │ Primary │ │ Cache & │ │ OAuth │ │ lity │ │ │ │ Database │ │ Sessions │ │ Provider │ │ Stack │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` ## Technology Stack ### Frontend Technologies ```yaml Web Application: Framework: React 18.2+ Language: TypeScript 5.0+ Build Tool: Vite 4.0+ UI Library: Gluestack UI Styling: NativeWind/Tailwind CSS 3.0+ State Management: React Context + useReducer Testing: Jest + React Testing Library + Playwright Mobile Applications: Framework: React Native 0.81+ Language: TypeScript 5.9+ UI Library: Gluestack UI (Native) Navigation: React Navigation 6+ State Management: React Context + useReducer Testing: Jest + React Native Testing Library Desktop Application: Framework: Wails 2.10+ Template: wails-vite-react-ts-tailwind-template ``` ### Backend Technologies ```yaml Microservices: Language: Go 1.25+ HTTP Framework: Fiber 3.0+ gRPC: Protocol Buffers + gRPC-Go Database ORM: Ent (Facebook) Authentication: JWT + Zitadel Integration Testing: Go testing + testcontainers API Gateway: Reverse Proxy: NGINX Gateway Service: Go + Fiber Load Balancing: Round-robin + Health checks Rate Limiting: Redis-based sliding window ``` ### Data Technologies ```yaml Primary Database: Engine: PostgreSQL 15+ Connection Pooling: pgxpool Migrations: Ent migrations Backup: pg_dump + Object Storage Cache Layer: Engine: Redis 7+ Use Cases: Sessions, Rate limiting, Cache Clustering: Redis Cluster (Production) Persistence: RDB + AOF Authentication: Provider: Zitadel (Self-hosted) Protocol: OAuth 2.0 + OpenID Connect Tokens: JWT with RS256 signing MFA: TOTP + WebAuthn ``` ### Infrastructure Technologies ```yaml Containerization: Runtime: Docker 24+ Orchestration: Kubernetes 1.28+ Registry: Private Docker Registry Observability: Metrics: Prometheus + Node Exporter Visualization: Grafana + Custom Dashboards Tracing: Jaeger + OpenTelemetry Logging: Structured logging + Loki CI/CD: Platform: GitHub Actions Testing: Automated test suites Security: SAST/DAST scanning Deployment: GitOps with ArgoCD ``` ## Microservices Design ### Service Boundaries #### 1. Game Service ```go // Responsibilities type GameService struct { // Core game logic and session management SessionManager *SessionManager ScoreCalculator *ScoreCalculator AttemptTracker *AttemptTracker TimerManager *TimerManager } // API Endpoints POST /api/v1/game/start // Start new game session GET /api/v1/game/session/{id} // Get session details POST /api/v1/game/answer // Submit answer POST /api/v1/game/hint // Request hint POST /api/v1/game/end // End session GET /api/v1/game/status/{id} // Get session status ``` #### 2. Question Service ```go // Responsibilities type QuestionService struct { QuestionRepo *QuestionRepository ThemeManager *ThemeManager Randomizer *QuestionRandomizer Validator *AnswerValidator } // API Endpoints GET /api/v1/questions/random // Get random question GET /api/v1/questions/{id} // Get specific question GET /api/v1/questions/themes // List available themes POST /api/v1/questions // Create question (admin) PUT /api/v1/questions/{id} // Update question (admin) DELETE /api/v1/questions/{id} // Delete question (admin) ``` #### 3. User Service ```go // Responsibilities type UserService struct { UserRepo *UserRepository ProfileManager *ProfileManager SessionTracker *SessionTracker } // API Endpoints POST /api/v1/users/register // Register new player GET /api/v1/users/profile // Get user profile PUT /api/v1/users/profile // Update profile GET /api/v1/users/sessions // Get session history DELETE /api/v1/users/profile // Delete account (GDPR) ``` #### 4. Leaderboard Service ```go // Responsibilities type LeaderboardService struct { ScoreAggregator *ScoreAggregator RankingEngine *RankingEngine StatsCalculator *StatsCalculator } // API Endpoints GET /api/v1/leaderboard/top10 // Get top 10 scores GET /api/v1/leaderboard/stats // Get game statistics GET /api/v1/leaderboard/player/{id} // Get player ranking POST /api/v1/leaderboard/update // Update scores (internal) ``` #### 5. Session Service ```go // Responsibilities type SessionService struct { SessionStore *SessionStore TimerManager *TimerManager StateManager *StateManager } // API Endpoints POST /api/v1/sessions // Create session GET /api/v1/sessions/{id} // Get session PUT /api/v1/sessions/{id} // Update session DELETE /api/v1/sessions/{id} // End session GET /api/v1/sessions/{id}/timer // Get timer status ``` #### 6. Admin Service ```go // Responsibilities type AdminService struct { AuthManager *AuthManager QuestionMgmt *QuestionManagement UserMgmt *UserManagement AuditLogger *AuditLogger } // API Endpoints POST /api/v1/admin/auth // Admin authentication GET /api/v1/admin/dashboard // Dashboard data GET /api/v1/admin/questions // List all questions POST /api/v1/admin/questions/bulk // Bulk question import GET /api/v1/admin/users // User management GET /api/v1/admin/audit // Audit logs ``` ### Inter-Service Communication #### Service Mesh Architecture ```yaml Communication Patterns: Synchronous: gRPC for real-time operations Asynchronous: Event-driven via message queues (future) Service Discovery: Registry: Kubernetes DNS Health Checks: HTTP /health endpoints Load Balancing: Round-robin with health awareness Circuit Breaker: Pattern: Hystrix-style circuit breakers Fallback: Graceful degradation Timeout: Context-based timeouts ``` #### gRPC Service Definitions ```protobuf // game_service.proto service GameService { rpc StartGame(StartGameRequest) returns (StartGameResponse); rpc SubmitAnswer(SubmitAnswerRequest) returns (SubmitAnswerResponse); rpc GetSession(GetSessionRequest) returns (GetSessionResponse); rpc EndGame(EndGameRequest) returns (EndGameResponse); } // question_service.proto service QuestionService { rpc GetRandomQuestion(RandomQuestionRequest) returns (Question); rpc ValidateAnswer(ValidateAnswerRequest) returns (ValidationResponse); rpc GetQuestionHint(HintRequest) returns (HintResponse); } // leaderboard_service.proto service LeaderboardService { rpc UpdateScore(UpdateScoreRequest) returns (UpdateScoreResponse); rpc GetTopScores(TopScoresRequest) returns (TopScoresResponse); rpc GetPlayerRank(PlayerRankRequest) returns (PlayerRankResponse); } ``` ## Database Architecture ### Data Model Design #### Core Entities (Ent Schemas) ```go // Question Entity type Question struct { ent.Schema } func (Question) Fields() []ent.Field { return []ent.Field{ field.String("theme").NotEmpty(), field.Text("text").NotEmpty(), field.String("answer").NotEmpty(), field.Text("hint").Optional(), field.Enum("difficulty").Values("easy", "medium", "hard").Default("medium"), field.Bool("is_active").Default(true), field.Time("created_at").Default(time.Now), field.Time("updated_at").Default(time.Now).UpdateDefault(time.Now), } } func (Question) Indexes() []ent.Index { return []ent.Index{ index.Fields("theme"), index.Fields("difficulty"), index.Fields("is_active"), index.Fields("created_at"), } } // GameSession Entity type GameSession struct { ent.Schema } func (GameSession) Fields() []ent.Field { return []ent.Field{ field.String("player_name").NotEmpty(), field.Int("total_score").Default(0), field.Int("questions_asked").Default(0), field.Int("questions_correct").Default(0), field.Int("hints_used").Default(0), field.Time("start_time").Default(time.Now), field.Time("end_time").Optional().Nillable(), field.Enum("status").Values("active", "completed", "timeout", "abandoned").Default("active"), field.String("current_question_id").Optional(), field.Int("current_attempts").Default(0), } } func (GameSession) Edges() []ent.Edge { return []ent.Edge{ edge.To("attempts", QuestionAttempt.Type), edge.To("current_question", Question.Type).Unique().Field("current_question_id"), } } // QuestionAttempt Entity type QuestionAttempt struct { ent.Schema } func (QuestionAttempt) Fields() []ent.Field { return []ent.Field{ field.String("session_id"), field.String("question_id"), field.Int("attempt_number"), field.String("submitted_answer"), field.Bool("is_correct"), field.Bool("used_hint"), field.Int("points_awarded"), field.Time("submitted_at").Default(time.Now), field.Duration("time_taken"), } } func (QuestionAttempt) Edges() []ent.Edge { return []ent.Edge{ edge.From("session", GameSession.Type).Ref("attempts").Unique().Field("session_id"), edge.To("question", Question.Type).Unique().Field("question_id"), } } ``` #### Database Performance Optimization ```sql -- Indexes for optimal query performance CREATE INDEX idx_questions_theme_active ON questions(theme, is_active); CREATE INDEX idx_sessions_status_start_time ON game_sessions(status, start_time); CREATE INDEX idx_attempts_session_question ON question_attempts(session_id, question_id); CREATE INDEX idx_leaderboard_score_time ON game_sessions(total_score DESC, end_time ASC) WHERE status = 'completed'; -- Partitioning for large datasets (future scaling) CREATE TABLE game_sessions_y2024m01 PARTITION OF game_sessions FOR VALUES FROM ('2024-01-01') TO ('2024-02-01'); ``` ### Database Connection Management ```go // Database configuration type DatabaseConfig struct { Primary DatabaseInstance Replicas []DatabaseInstance Pool PoolConfig } type DatabaseInstance struct { Host string Port int Database string Username string Password string SSLMode string } type PoolConfig struct { MaxOpenConns int // 25 MaxIdleConns int // 5 ConnMaxLifetime time.Duration // 30 minutes ConnMaxIdleTime time.Duration // 15 minutes } // Connection pooling with read/write splitting func NewDatabaseClient(config DatabaseConfig) (*ent.Client, error) { primaryDSN := formatDSN(config.Primary) // Primary database for writes primaryDB, err := sql.Open("postgres", primaryDSN) if err != nil { return nil, err } configurePools(primaryDB, config.Pool) // Create Ent client with instrumented driver drv := entsql.OpenDB("postgres", primaryDB) return ent.NewClient(ent.Driver(drv)), nil } ``` ## Security Architecture ### Authentication Flow ```mermaid sequenceDiagram participant C as Client participant G as API Gateway participant Z as Zitadel participant S as Service C->>G: Request with credentials G->>Z: Validate credentials Z->>G: Return JWT token G->>C: Return token + user info C->>G: API request with JWT G->>G: Validate JWT signature G->>S: Forward request with user context S->>G: Return response G->>C: Return response ``` ### Authorization Strategy ```go // Role-based access control type Role string const ( RolePlayer Role = "player" RoleAdmin Role = "admin" ) type Permissions struct { CanPlayGame bool CanViewScores bool CanManageQuestions bool CanViewAuditLogs bool CanManageUsers bool } var RolePermissions = map[Role]Permissions{ RolePlayer: { CanPlayGame: true, CanViewScores: true, }, RoleAdmin: { CanPlayGame: true, CanViewScores: true, CanManageQuestions: true, CanViewAuditLogs: true, CanManageUsers: true, }, } // JWT middleware with role checking func AuthMiddleware() fiber.Handler { return func(c *fiber.Ctx) error { token := extractToken(c.Get("Authorization")) claims, err := validateJWT(token) if err != nil { return c.Status(401).JSON(fiber.Map{"error": "Invalid token"}) } c.Locals("user_id", claims.Subject) c.Locals("user_role", claims.Role) c.Locals("permissions", RolePermissions[Role(claims.Role)]) return c.Next() } } func RequirePermission(permission func(Permissions) bool) fiber.Handler { return func(c *fiber.Ctx) error { perms := c.Locals("permissions").(Permissions) if !permission(perms) { return c.Status(403).JSON(fiber.Map{"error": "Insufficient permissions"}) } return c.Next() } } ``` ### Input Validation & Security ```go // Comprehensive input validation type InputValidator struct { maxAnswerLength int maxNameLength int allowedChars *regexp.Regexp } func NewInputValidator() *InputValidator { return &InputValidator{ maxAnswerLength: 500, maxNameLength: 50, allowedChars: regexp.MustCompile(`^[a-zA-Z0-9\s\-_.]+$`), } } func (v *InputValidator) ValidateAnswer(answer string) error { if len(answer) == 0 { return errors.New("answer cannot be empty") } if len(answer) > v.maxAnswerLength { return errors.New("answer too long") } // Sanitize HTML and potential XSS clean := html.EscapeString(strings.TrimSpace(answer)) if clean != answer { return errors.New("invalid characters in answer") } return nil } func (v *InputValidator) ValidatePlayerName(name string) error { if len(name) < 2 || len(name) > v.maxNameLength { return errors.New("name must be 2-50 characters") } if !v.allowedChars.MatchString(name) { return errors.New("name contains invalid characters") } return nil } // Rate limiting implementation type RateLimiter struct { redis *redis.Client limits map[string]RateLimit } type RateLimit struct { Requests int // Number of requests Window time.Duration // Time window } func (rl *RateLimiter) Allow(key string, limit RateLimit) bool { current, err := rl.redis.Incr(key).Result() if err != nil { return false // Fail closed } if current == 1 { rl.redis.Expire(key, limit.Window) } return current <= int64(limit.Requests) } // Usage in middleware func RateLimitMiddleware() fiber.Handler { limiter := NewRateLimiter() return func(c *fiber.Ctx) error { userID := c.Locals("user_id").(string) clientIP := c.IP() // Per-user rate limiting userKey := fmt.Sprintf("rate_limit:user:%s", userID) if !limiter.Allow(userKey, RateLimit{Requests: 60, Window: time.Minute}) { return c.Status(429).JSON(fiber.Map{"error": "Rate limit exceeded"}) } // Per-IP rate limiting ipKey := fmt.Sprintf("rate_limit:ip:%s", clientIP) if !limiter.Allow(ipKey, RateLimit{Requests: 100, Window: time.Minute}) { return c.Status(429).JSON(fiber.Map{"error": "Rate limit exceeded"}) } return c.Next() } } ``` ## Cross-Platform Frontend Architecture ### Gluestack UI Integration ```typescript // Shared component library structure // packages/ui-components/src/index.ts export { GameCard } from './GameCard' export { Leaderboard } from './Leaderboard' export { Timer } from './Timer' export { ScoreDisplay } from './ScoreDisplay' export { AdminPanel } from './AdminPanel' // Component example with Gluestack UI // packages/ui-components/src/GameCard/GameCard.tsx import { Card, VStack, HStack, Text, Input, Button, Badge, Progress, Box } from '@gluestack-ui/themed' export interface GameCardProps { question: string theme: string timeRemaining: number attemptsLeft: number currentScore: number onSubmitAnswer: (answer: string) => void onRequestHint: () => void isLoading?: boolean } export const GameCard: React.FC = ({ question, theme, timeRemaining, attemptsLeft, currentScore, onSubmitAnswer, onRequestHint, isLoading = false }) => { const [answer, setAnswer] = useState('') const handleSubmit = () => { if (answer.trim()) { onSubmitAnswer(answer.trim()) setAnswer('') } } return ( {/* Header with theme and timer */} {theme} ⏱️ {Math.floor(timeRemaining / 60)}:{(timeRemaining % 60).toString().padStart(2, '0')} {/* Progress indicator */} {/* Question */} {question} {/* Answer input */} {/* Game stats */} Attempts left: {attemptsLeft}/3 Score: {currentScore} points {/* Action buttons */} ) } ``` ### Platform-Specific Adaptations ```typescript // Platform detection and adaptation // packages/shared-logic/src/platform.ts export interface PlatformCapabilities { hasTouch: boolean hasKeyboard: boolean hasCamera: boolean canVibrate: boolean supportsNotifications: boolean isOfflineCapable: boolean } export const getPlatformCapabilities = (): PlatformCapabilities => { // Web platform if (typeof window !== 'undefined') { return { hasTouch: 'ontouchstart' in window, hasKeyboard: true, hasCamera: !!navigator.mediaDevices?.getUserMedia, canVibrate: !!navigator.vibrate, supportsNotifications: 'Notification' in window, isOfflineCapable: 'serviceWorker' in navigator } } // React Native platform if (typeof require !== 'undefined') { try { const { Platform } = require('react-native') return { hasTouch: true, hasKeyboard: Platform.OS === 'ios' || Platform.OS === 'android', hasCamera: true, canVibrate: true, supportsNotifications: true, isOfflineCapable: true } } catch { // Fallback for other environments } } // Default capabilities return { hasTouch: false, hasKeyboard: true, hasCamera: false, canVibrate: false, supportsNotifications: false, isOfflineCapable: false } } // Responsive design utilities export const useResponsiveValue = (values: { mobile: T tablet: T desktop: T }) => { const [screenSize, setScreenSize] = useState<'mobile' | 'tablet' | 'desktop'>('desktop') useEffect(() => { const updateScreenSize = () => { const width = window.innerWidth if (width < 768) { setScreenSize('mobile') } else if (width < 1024) { setScreenSize('tablet') } else { setScreenSize('desktop') } } updateScreenSize() window.addEventListener('resize', updateScreenSize) return () => window.removeEventListener('resize', updateScreenSize) }, []) return values[screenSize] } ``` This technical architecture provides a solid foundation for building a scalable, secure, and maintainable quiz game platform with cross-platform capabilities.