Spaces:
Sleeping
Sleeping
| # Devil's Dozen - Technical Architecture | |
| ## 1. System Overview | |
| ``` | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β CLIENT (Browser) β | |
| β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β | |
| β β Streamlit Frontend β β | |
| β β βββββββββββββββ βββββββββββββββ βββββββββββββββββββββββ β β | |
| β β β Dice Tray β β Scoreboard β β Turn Controls β β β | |
| β β βββββββββββββββ βββββββββββββββ βββββββββββββββββββββββ β β | |
| β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β | |
| β β β | |
| β βΌ β | |
| β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β | |
| β β Game Engine β β | |
| β β ββββββββββββββββββββ ββββββββββββββββββββββββββββββββ β β | |
| β β β PeasantsGamble β β AlchemistsAscent β β β | |
| β β β Engine β β Engine β β β | |
| β β ββββββββββββββββββββ ββββββββββββββββββββββββββββββββ β β | |
| β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β | |
| βΌ | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β SUPABASE β | |
| β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ β | |
| β β Lobbies β β Players β β Game State β β | |
| β β Table β β Table β β Table β β | |
| β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ β | |
| β β β | |
| β βΌ β | |
| β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β | |
| β β Realtime Channels β β | |
| β β (WebSocket Push Notifications) β β | |
| β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ``` | |
| --- | |
| ## 2. Module Dependency Graph | |
| ``` | |
| βββββββββββββ | |
| β config β | |
| βββββββ¬ββββββ | |
| β | |
| βββββββββββββββββΌββββββββββββββββ | |
| β β β | |
| βΌ βΌ βΌ | |
| ββββββββββββ ββββββββββββ ββββββββββββ | |
| β engine β β database β β realtime β | |
| ββββββββββββ ββββββ¬ββββββ ββββββ¬ββββββ | |
| β β β | |
| β ββββββββ¬ββββββββ | |
| β β | |
| βΌ βΌ | |
| βββββββββββββββββββββββββββββββββββββββ | |
| β ui β | |
| β (imports engine, database, realtime)β | |
| βββββββββββββββββββββββββββββββββββββββ | |
| ``` | |
| **Dependency Rules**: | |
| - `engine` has ZERO external dependencies (pure Python) | |
| - `database` depends only on `config` for settings | |
| - `realtime` depends on `database` for client access | |
| - `ui` imports from all other modules | |
| - No circular dependencies allowed | |
| --- | |
| ## 3. Data Flow | |
| ### 3.1 Turn Flow (Happy Path) | |
| ``` | |
| Player A Supabase Player B | |
| β β β | |
| βββββ Click "Roll" ββββββββββΊ β | |
| β β β | |
| β [Engine calculates β β | |
| β scoring locally] β β | |
| β β β | |
| βββββ UPDATE game_state βββββΊ β | |
| β (dice, turn_score) β β | |
| β βββ Realtime broadcast βββββΊβ | |
| β β β | |
| βββββ Confirmation ββββββββββ β | |
| β β β | |
| βββββ Click "Bank" ββββββββββΊ β | |
| β β β | |
| βββββ UPDATE players ββββββββΊ β | |
| β (add turn_score) β β | |
| β β β | |
| βββββ UPDATE lobbies ββββββββΊ β | |
| β (next turn_index) β β | |
| β βββ Realtime broadcast βββββΊβ | |
| ``` | |
| ### 3.2 Bust Flow | |
| ``` | |
| Player A Supabase Player B | |
| β β β | |
| βββββ Click "Roll" ββββββββββΊ β | |
| β β β | |
| β [Engine: no scoring β β | |
| β dice = BUST] β β | |
| β β β | |
| βββββ UPDATE game_state βββββΊ β | |
| β (bust: true) β β | |
| β βββ Realtime broadcast βββββΊβ | |
| β β (bust event) β | |
| β β β | |
| βββββ UPDATE lobbies ββββββββΊ β | |
| β (next turn_index) β β | |
| β β β | |
| βββββ Now it's Player B ββββββββ Player B's turn now βββ | |
| ``` | |
| --- | |
| ## 4. Database Schema | |
| ### 4.1 Tables | |
| ```sql | |
| -- Lobby: Game room containing players | |
| CREATE TABLE lobbies ( | |
| id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | |
| code VARCHAR(6) UNIQUE NOT NULL, -- Shareable join code | |
| game_mode VARCHAR(20) NOT NULL, -- 'peasants_gamble' | 'alchemists_ascent' | |
| win_condition INT NOT NULL, -- Target score to win | |
| current_turn_index INT DEFAULT 0, -- Index into player turn order | |
| status VARCHAR(20) DEFAULT 'waiting', -- waiting | active | finished | |
| winner_id UUID REFERENCES players(id), -- Set when game ends | |
| created_at TIMESTAMPTZ DEFAULT NOW(), | |
| updated_at TIMESTAMPTZ DEFAULT NOW() | |
| ); | |
| -- Player: Participant in a game | |
| CREATE TABLE players ( | |
| id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | |
| lobby_id UUID REFERENCES lobbies(id) ON DELETE CASCADE, | |
| username VARCHAR(30) NOT NULL, | |
| total_score INT DEFAULT 0, | |
| turn_order INT NOT NULL, -- 0, 1, 2, or 3 | |
| is_connected BOOLEAN DEFAULT true, | |
| created_at TIMESTAMPTZ DEFAULT NOW(), | |
| UNIQUE(lobby_id, username), -- No duplicate names in lobby | |
| UNIQUE(lobby_id, turn_order) -- No duplicate turn orders | |
| ); | |
| -- Game State: Current turn state (transient) | |
| CREATE TABLE game_state ( | |
| lobby_id UUID PRIMARY KEY REFERENCES lobbies(id) ON DELETE CASCADE, | |
| active_dice JSONB DEFAULT '[]', -- Current dice values [1,4,5,2,3,6] | |
| held_indices JSONB DEFAULT '[]', -- Indices of held dice [0, 2] | |
| turn_score INT DEFAULT 0, -- Points accumulated this turn | |
| is_bust BOOLEAN DEFAULT false, -- Did player bust? | |
| roll_count INT DEFAULT 0, -- Number of rolls this turn | |
| tier INT DEFAULT 1, -- For Alchemist's Ascent | |
| previous_dice JSONB DEFAULT '[]', -- For Tier 2 reroll comparison | |
| updated_at TIMESTAMPTZ DEFAULT NOW() | |
| ); | |
| -- Indexes for performance | |
| CREATE INDEX idx_players_lobby ON players(lobby_id); | |
| CREATE INDEX idx_lobbies_code ON lobbies(code); | |
| CREATE INDEX idx_lobbies_status ON lobbies(status); | |
| ``` | |
| ### 4.2 Row Level Security | |
| ```sql | |
| -- Lobbies: Anyone can read, only creator can update | |
| ALTER TABLE lobbies ENABLE ROW LEVEL SECURITY; | |
| CREATE POLICY "Lobbies are publicly readable" | |
| ON lobbies FOR SELECT | |
| USING (true); | |
| CREATE POLICY "Anyone can create lobbies" | |
| ON lobbies FOR INSERT | |
| WITH CHECK (true); | |
| CREATE POLICY "Lobby members can update" | |
| ON lobbies FOR UPDATE | |
| USING (true); -- Simplified for MVP | |
| -- Similar policies for players and game_state tables | |
| ``` | |
| --- | |
| ## 5. State Management | |
| ### 5.1 Streamlit Session State | |
| ```python | |
| # Session state structure | |
| st.session_state = { | |
| # Identity | |
| "player_id": "uuid", | |
| "player_name": "string", | |
| # Lobby | |
| "lobby_id": "uuid", | |
| "lobby_code": "ABC123", | |
| "game_mode": "peasants_gamble", | |
| # Turn state | |
| "is_my_turn": bool, | |
| "current_dice": [1, 4, 5, 2, 3, 6], | |
| "held_indices": {0, 2}, | |
| "turn_score": 0, | |
| # UI state | |
| "sound_enabled": True, | |
| "show_rules": False, | |
| } | |
| ``` | |
| ### 5.2 Optimistic Updates | |
| To reduce perceived latency: | |
| 1. Update local state immediately on user action | |
| 2. Send update to Supabase | |
| 3. If Supabase update fails, rollback local state | |
| 4. Other players receive update via Realtime subscription | |
| --- | |
| ## 6. Error Handling Strategy | |
| | Error Type | Response | | |
| |------------|----------| | |
| | Network failure | Retry 3x with backoff, then show error | | |
| | Supabase error | Log, show user-friendly message | | |
| | Invalid game state | Reset to last known good state | | |
| | Concurrent modification | Last write wins (simplified) | | |
| | Player disconnect | Mark as disconnected, allow rejoin | | |
| --- | |
| ## 7. Deployment Architecture | |
| ``` | |
| ββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ | |
| β GitHub (source) β β Hugging Face Spaces β | |
| β origin/master β β hf/main (live app) β | |
| ββββββββββββ¬ββββββββββββββββ ββββββββββββ¬ββββββββββββββββ | |
| β git push origin master β git push hf master:main | |
| βββββββββββββββββ¬ββββββββββββββββββββ | |
| β | |
| ββββββββββββββΌβββββββββββββββββββββ | |
| β Streamlit Application β | |
| β - Serves UI + game engine β | |
| β - JS-cached audio system β | |
| β - Connects to Supabase (HTTPS) β | |
| ββββββββββββββ¬βββββββββββββββββββββ | |
| β | |
| ββββββββββββββΌβββββββββββββββββββββ | |
| β Supabase β | |
| β - PostgreSQL database β | |
| β - Realtime WebSocket channels β | |
| β - Row Level Security β | |
| βββββββββββββββββββββββββββββββββββ | |
| ``` | |
| ### Remotes | |
| | Remote | URL | Branch | | |
| |--------|-----|--------| | |
| | `origin` | `https://github.com/legomaheggoz-source/DevilsDozen.git` | `master` | | |
| | `hf` | `https://huggingface.co/spaces/legomaheggo/DevilsDozen` | push `master:main` | | |
| ### Environment Variables (HF Spaces Secrets / `.env` locally) | |
| ``` | |
| SUPABASE_URL=https://xxx.supabase.co | |
| SUPABASE_ANON_KEY=sb_publishable_xxx... | |
| ``` | |
| --- | |
| ## 8. Performance Considerations | |
| ### Bottlenecks & Mitigations | |
| | Bottleneck | Mitigation | | |
| |------------|------------| | |
| | Streamlit rerun on state change | Use `st.fragment` for isolated updates | | |
| | Database round-trips | Batch updates where possible | | |
| | Realtime subscription limits | One channel per lobby | | |
| | Animation performance | CSS animations over JS | | |
| | Audio data re-send on rerun | JS Audio caching in `window.parent` β base64 sent once, then tiny control commands | | |
| | Widget prefs lost on `st.rerun()` | Non-widget session state keys (`_sfx_pref`, `_music_pref`, etc.) | | |
| ### Scaling Limits (Free Tier) | |
| - **Supabase**: 500MB database, 2GB bandwidth/month | |
| - **HF Spaces**: 2 vCPU, 16GB RAM | |
| - **Concurrent games**: ~50 lobbies estimated | |