# Quick setup for development
./setup.sh
# Install dependencies
poetry install
# Run application (old monolithic structure)
poetry run python main.py
# Run application (new modular structure)
poetry run python app.py
# Run tests
poetry run pytest
# Run tests with coverage
poetry run pytest --cov=src --cov-report=html
# Lint code
poetry run flake8
poetry run black --check .
poetry run isort --check .
# Format code
poetry run black .
poetry run isort .
# Build Docker container
docker build -t bingo .
# Run Docker container
docker run -p 8080:8080 bingo
# Helm deployment
cd helm && ./package.sh && helm install bingo ./bingo
# Using Makefile
make install # Install dependencies
make run # Run application
make test # Run tests
make lint # Run linters
make format # Format code
make build # Build package- Imports: Standard library first, third-party second, local modules last
- Formatting: Use f-strings for string formatting
- Constants: Defined at top of file in UPPER_CASE
- Naming: snake_case for functions/variables, UPPER_CASE for constants
- Error Handling: Use try/except blocks with proper logging
- UI Elements: Define class constants for styling
- Logging: Use Python's logging module with descriptive messages
- Comments: Use docstrings for functions and descriptive comments
- Line Length: Max 88 characters (Black's default)
- Code Formatting: Use Black for code formatting and isort for import sorting
app.py: Main entry point for modular applicationsrc/: Source code directoryconfig/: Configuration and constantscore/: Core game logicui/: User interface componentsutils/: Utility functions
phrases.txt: Contains customizable bingo phrasesstatic/: Static assets for fonts and stylestests/: Unit and integration testshelm/: Kubernetes deployment configuration.github/workflows/: CI pipeline configurationCHANGELOG.md: Release history tracking
- Use feature branches for each change:
feature/description-of-change - Use bugfix branches for bug fixes:
fix/description-of-bug - Use chore branches for maintenance:
chore/description-of-task
Follow conventional changelog format:
<type>(<scope>): <subject>
<body>
<footer>
-
Types:
feat: A new featurefix: A bug fixdocs: Documentation only changesstyle: Changes that do not affect meaning (white-space, formatting)refactor: Code change that neither fixes a bug nor adds a featureperf: Change that improves performancetest: Adding missing tests or correcting existing testschore: Changes to the build process or auxiliary tools
-
Scope (optional): The module/component affected, e.g.,
core,ui,board -
Subject: Short description in imperative, present tense (not past tense)
- Good: "add feature X" (not "added feature X")
- Use lowercase
- No period at the end
-
Body (optional): Detailed explanation of changes
- Use present tense
- Include motivation and context
- Explain "what" and "why" (not "how")
-
Footer (optional): Reference issues, PRs, breaking changes
feat(board): add color theme selector
Add ability for users to choose color themes for the bingo board
Resolves #123
fix(ui): resolve client disconnection issues
Handle race conditions during client disconnects to prevent
server exceptions and ensure smooth reconnection
Fixes #456
This project follows semantic versioning (SEMVER) principles:
- MAJOR version when making incompatible API changes (X.0.0)
- MINOR version when adding functionality in a backwards compatible manner (0.X.0)
- PATCH version when making backwards compatible bug fixes (0.0.X)
Version numbers are automatically updated by the CI/CD pipeline based on commit messages. The project uses python-semantic-release to analyze commit messages and determine the appropriate version bump according to the conventional commit format.
The project utilizes GitHub Actions for continuous integration and deployment:
-
CI Job:
- Runs on each push to main and pull request
- Installs dependencies
- Runs linters (flake8, black, isort)
- Runs all tests with pytest
- Uploads coverage reports
-
Release Job:
- Runs after successful CI job on the main branch
- Determines new version based on commit messages
- Updates CHANGELOG.md
- Creates Git tag for the release
- Publishes release on GitHub
Before pushing changes to the repository, run these checks locally to ensure the CI pipeline will pass:
# 1. Run linters to ensure code quality and style
poetry run flake8 main.py src/ tests/
poetry run black --check .
poetry run isort --check .
# 2. Run tests to ensure functionality works
poetry run pytest
# 3. Check test coverage to ensure sufficient testing
poetry run pytest --cov=main --cov-report=term-missing
# 4. Fix any linting issues
poetry run black .
poetry run isort .
# 5. Run tests again after fixing linting issues
poetry run pytest
# 6. Verify application starts without errors
poetry run python main.py # (Ctrl+C to exit after confirming it starts)-
Code Style Issues:
- Inconsistent indentation
- Line length exceeding 88 characters
- Missing docstrings
- Improper import ordering
-
Test Failures:
- Broken functionality due to recent changes
- Missing tests for new features
- Incorrectly mocked dependencies in tests
- Race conditions in async tests
-
Coverage Thresholds:
- Insufficient test coverage on new code
- Missing edge case tests
- Uncovered exception handling paths
If you encounter CI failures, this sequence often resolves common issues:
# Fix style issues
poetry run black .
poetry run isort .
# Run tests with coverage to identify untested code
poetry run pytest --cov=main --cov-report=term-missing
# Add tests for any uncovered code sections then run again
poetry run pytestSpecial attention should be paid to testing game state synchronization between the main view and the stream view:
# Run specific tests for state synchronization
poetry run pytest -v tests/test_ui_functions.py::TestUIFunctions::test_header_updates_on_both_paths
poetry run pytest -v tests/test_ui_functions.py::TestUIFunctions::test_stream_header_update_when_game_closedWhen making changes to game state management, especially related to:
- Game closing/reopening
- Header text updates
- Board visibility
- Broadcast mechanisms
Verify both these scenarios:
- Changes made on main view are reflected in stream view
- Changes persist across page refreshes
- New connections to stream page see the correct state
Common issues:
- Missing ui.broadcast() calls
- Not handling header updates across different views
- Not checking if game is closed in sync_board_state
- Ignoring exception handling for disconnected clients
The application uses a server-side StateManager for persistent state management:
- StateManager Pattern: Server-side file persistence to
game_state.json - Previous Issue:
app.storage.generalwas client-side browser localStorage - Solution: Implemented
src/core/state_manager.pywith atomic file writes
- Persistent Data: Game state survives app restarts via server-side JSON file
- Serialization: Handles conversion of Python types (sets → lists, tuples → lists)
- Auto-save: State saved after every user action with debouncing
- Load on Init: State restored from file when app starts
- Atomic Writes: Uses temp file + rename for data integrity
clicked_tiles: Set of clicked (row, col) positionsis_game_closed: Boolean for game statusheader_text: Current header messageboard_iteration: Tracks board versionbingo_patterns: Winning patterns foundtoday_seed: Daily seed for board generation
save_state_to_storage(): Uses StateManager to persist to fileload_state_from_storage(): Creates new StateManager instance and loads from filetoggle_tile(): Updates tile state and triggers async saveclose_game(): Closes game and saves statereopen_game(): Reopens game and saves state
- Async operations with proper locking
- Debounced saves (100ms delay) to reduce I/O
- Singleton pattern for global access
- Thread-safe concurrent access
- Corrupted state recovery
- Atomic file writes with temp file pattern
- 96% test coverage
# Get singleton instance
from src.core.state_manager import get_state_manager
state_manager = get_state_manager()
# Async operations
await state_manager.toggle_tile(row, col)
await state_manager.update_board(board, iteration, seed)
await state_manager.set_game_closed(is_closed)
await state_manager.update_header(text)
await state_manager.update_bingo_patterns(patterns)
await state_manager.reset_board()
# Get current state
state = await state_manager.get_full_state()
# Properties (read-only)
clicked_tiles = state_manager.clicked_tiles # Returns copy
is_game_closed = state_manager.is_game_closed
board_iteration = state_manager.board_iteration- File Location:
game_state.json(gitignored) - Initialization: Uses
@app.on_startupfor async setup - Error Handling: Gracefully handles missing/corrupted files
- Performance: Debounced saves prevent excessive I/O
- Testing: Full test suite in
tests/test_state_manager.py
The application maintains two synchronized views:
- Root Path (
/): Full interactive board with controls - Stream Path (
/stream): Read-only view for audiences
- Timer-based: Uses 0.05 second interval timers
- NiceGUI 2.11+ Compatible: Removed deprecated
ui.broadcast() - Automatic Updates: UI changes propagate to all connected clients
- State Consistency: Both views share same game state
- Active connections tracked per path
- Connection/disconnection handled gracefully
- Health endpoint reports user counts
- UI displays active user count
- Built for NiceGUI 2.11.0+
- Uses
app.storage.generalfor persistence - Timer-based synchronization pattern
- No longer uses deprecated
ui.broadcast()
# Store data
app.storage.general['key'] = value
# Retrieve with default
value = app.storage.general.get('key', default_value)
# Check existence
if 'key' in app.storage.general:
# process- Buttons support text + icons for mobile
- Use context managers for UI containers
- Handle disconnected clients in try/except
- Timer callbacks for periodic updates
- Touch targets: minimum 44x44 pixels
- Descriptive text alongside icons
- Responsive design classes
- Clear visual feedback
- ✅ Just solved something? → SAVE NOW
- ✅ Created a script? → SAVE NOW
- ✅ Fixed an error? → SAVE NOW
- ✅ Made a decision? → SAVE NOW
- ✅ Discovered a pattern? → SAVE NOW
DON'T WAIT UNTIL THE END OF THE SESSION!
- ALWAYS search memory BEFORE starting any work:
mcp__mcp-memory__searchMCPMemory "bingo [topic]" - ALWAYS save solutions after fixing issues:
mcp__mcp-memory__addToMCPMemory "bingo: Problem: X, Solution: Y" - Save context switches: When interrupted or switching tasks, save current state
- Capture train of thought: Document reasoning and decision paths
- After creating any script → Save its purpose and usage
- After fixing any error → Save problem + solution
- After file reorganization → Save what moved where
- After discovering pattern → Save the insight
- After making decision → Save the rationale
- After solving problem → Save approach + result
# 1. Restore context from last session
mcp__mcp-memory__searchMCPMemory "bingo last session state"
mcp__mcp-memory__searchMCPMemory "bingo open tasks TODO"
mcp__mcp-memory__searchMCPMemory "Jonathan workflow guidelines best practices"
# 2. Rebuild mental model
tree . -I 'node_modules' -L 2
cat CLAUDE.md
# 3. Load comprehensive project memory
mcp__mcp-memory__searchMCPMemory "bingo current state"
mcp__mcp-memory__searchMCPMemory "bingo where I left off"
mcp__mcp-memory__searchMCPMemory "bingo blockers questions"
mcp__mcp-memory__searchMCPMemory "bingo solutions patterns"
mcp__mcp-memory__searchMCPMemory "bingo nicegui patterns"
mcp__mcp-memory__searchMCPMemory "bingo state persistence"
mcp__mcp-memory__searchMCPMemory "bingo testing infrastructure"
# 4. Check work state
git status
git diff
git log --oneline -10
gh pr list --assignee @me --state open-
mcp-memory (Always Active - External Brain)
mcp__mcp-memory__searchMCPMemory "[query]"- Search stored knowledgemcp__mcp-memory__addToMCPMemory "content"- Save new knowledge- Always prefix with "bingo:" for project isolation
-
sequentialthinking - For complex reasoning (especially with Sonnet 4)
- Use for architectural decisions and complex debugging
- Saves reasoning process to memory automatically
-
context7 (Documentation lookup)
mcp__context7__resolve-library-id: Find library IDs (e.g., NiceGUI)mcp__context7__get-library-docs: Get library documentation
-
serena (Code intelligence)
- Activate with:
mcp__serena__activate_project "bingo" - Provides symbol search, refactoring, and code analysis
- Activate with:
Project: bingo
Error: [exact error message]
Context: [NiceGUI version, test environment, etc.]
Solution: [step-by-step fix]
Code Before: [relevant code showing issue]
Code After: [corrected code]
Validation: [how verified it worked]
Tags: bingo, error-fix, [component], [technology]
Project: bingo
Component: [StateManager/UI/Testing]
Issue: [what needed testing/fixing]
Approach: [testing strategy used]
Implementation: [specific test code/patterns]
Results: [coverage/performance metrics]
Patterns: [reusable testing patterns discovered]
Tags: bingo, testing, [unit/integration/e2e], [component]
Project: bingo
NiceGUI Pattern: [state management/UI/timers/etc.]
Problem: [what was challenging]
Solution: [NiceGUI-specific approach]
Code Example: [working implementation]
Gotchas: [things to watch out for]
Performance: [any performance considerations]
Tags: bingo, nicegui, [pattern-type], [version]
Project: bingo
Architecture Decision: [what was decided]
Previous Approach: [old way - app.storage.general]
New Approach: [StateManager pattern]
Implementation: [key code/patterns]
Benefits: [persistence, thread-safety, etc.]
Testing Strategy: [how we verified it works]
Tags: bingo, architecture, state-persistence, statemanager
# Starting work
mcp__mcp-memory__searchMCPMemory "bingo session startup protocol"
mcp__mcp-memory__searchMCPMemory "bingo current priorities"
# Debugging
mcp__mcp-memory__searchMCPMemory "bingo [error-type] solutions"
mcp__mcp-memory__searchMCPMemory "bingo nicegui [issue-type]"
mcp__mcp-memory__searchMCPMemory "bingo testing [test-type] patterns"
# Development
mcp__mcp-memory__searchMCPMemory "bingo statemanager patterns"
mcp__mcp-memory__searchMCPMemory "bingo ci optimization"
mcp__mcp-memory__searchMCPMemory "bingo deployment troubleshooting"- Every StateManager fix/enhancement with before/after code
- NiceGUI UI patterns that work well for this app
- Testing strategies that prove effective (unit/integration/e2e)
- CI/CD optimizations and performance improvements
- Docker/Helm deployment issues and their solutions
- Performance bottlenecks and optimization approaches
- User experience improvements and their impact
- Architecture decisions with reasoning and alternatives considered