No description
  • Python 52%
  • TypeScript 47.2%
  • JavaScript 0.2%
  • CSS 0.2%
  • Shell 0.2%
Find a file
Joerg Ziefle 36de5bf093
All checks were successful
CI / lint-backend (push) Successful in 1m34s
CI / test-backend (push) Successful in 6m19s
CI / lint-frontend (push) Successful in 4m18s
CI / build-backend (push) Successful in 10s
CI / build-frontend (push) Successful in 53s
fix: add dark mode styling and participant summary to bet resolution
- Add dark mode styling to bet resolution section (backgrounds, text, borders)
- Add dark mode styling to winner display section
- Add participant win/loss summary showing net gains/losses for each user
- Color-code participant results (green for wins, red for losses)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-02 11:44:24 +01:00
.claude feat: improve invitation system with automatic migrations 2025-12-30 16:25:25 +01:00
.forgejo/workflows fix: use docker socket instead of TCP for build jobs 2025-12-24 02:23:53 +00:00
.serena chore: add pre-commit hooks and fix linting issues 2025-12-30 16:36:41 +01:00
backend fix: stabilize SSE connections for real-time notifications 2025-12-31 01:09:43 +01:00
docs docs: update README to reflect v2.0 features and architecture 2025-12-31 15:01:33 +01:00
frontend fix: add dark mode styling and participant summary to bet resolution 2026-01-02 11:44:24 +01:00
presentations docs: add Git install and clone instructions to demo presentation 2025-12-19 15:22:10 +01:00
scripts chore: add pre-commit hooks and fix linting issues 2025-12-30 16:36:41 +01:00
.gitignore chore: initialize project with gitignore and README 2025-12-19 14:41:38 +01:00
.pre-commit-config.yaml chore: add pre-commit hooks and fix linting issues 2025-12-30 16:36:41 +01:00
docker-compose.prod.yml fix: update docker-compose.prod.yml with working config 2025-12-24 04:27:20 +01:00
docker-compose.yml feat: add Docker Compose for one-command startup 2025-12-19 14:42:01 +01:00
README.md docs: update README to reflect v2.0 features and architecture 2025-12-31 15:01:33 +01:00
SPECIFICATION.md feat: add v2.0 data models for multi-org support 2025-12-21 15:12:14 +01:00

Office Betting Platform v2.0

A multi-organization play-money pari-mutuel betting platform using OfficeCoins virtual currency.

DISCLAIMER: This application uses virtual play money only. No real money is wagered or paid out. For entertainment purposes only.

Screenshot

Office Betting Platform

TODO: Add screenshot of the current UI to docs/screenshot.png

Quick Start

docker-compose up --build

Then open http://localhost:3000 in your browser.

What's New in v2.0

  • Multi-Organization System: Create and manage multiple betting organizations
  • Organization Roles: Owner, Admin, and Member roles with different permissions
  • Invitations System: Invite users via email or shareable invite links
  • Real-Time Notifications: Server-Sent Events (SSE) for live updates
  • Comments & Discussions: Comment on bets with real-time updates
  • Achievements System: Gamification badges for user milestones
  • Seasons & Categories: Organize bets by season and category
  • Image Uploads: Custom avatars and organization logos
  • Dark Mode: Full dark mode support
  • Activity Feed: Track recent activity across your organization
  • Audit Logging: Complete admin action history
  • Transaction History: Full audit trail for all coin movements
  • Reports & Export: Moderation tools and data export
  • House Fees: Configurable house fee per organization

Features

Organizations

  • Create unlimited organizations with unique slugs
  • Customize settings per organization:
    • Initial balance for new members
    • Minimum wager amount
    • House fee percentage
    • Early bet bonus multiplier
    • Custom logo and branding
  • Three-tier permission system (Owner, Admin, Member)
  • Invite-only or open membership
  • Per-organization balances (not global)

Betting

  • Create bets with any number of outcomes (minimum 2)
  • Pari-mutuel odds that update in real-time after each wager
  • Early bet bonus: Wagers in the first 50% of the betting window get weight multiplier
  • Live countdown timers until betting closes
  • House fees: Configurable percentage taken from the pool
  • Categories: Organize bets by category (Sports, Politics, Office, etc.)
  • Seasons: Group bets into seasons for seasonal leaderboards
  • Comments: Discuss bets with other members
  • Zero-sum accounting: All payouts verified via transaction ledger

Users & Social

  • Register with email/password (email verification optional)
  • Custom avatars and user profiles
  • Personal wager history and statistics
  • Achievements and badges
  • Activity feed showing recent bets, wagers, and comments
  • Real-time notifications for:
    • New bets in your organization
    • Bet results and payouts
    • Comments on bets you've wagered on
    • New achievements

Administration

  • Admin dashboard for organization management
  • Invite members via email or shareable links
  • Approve/reject membership requests
  • Adjust member balances
  • View audit log of all admin actions
  • Moderation queue for reported content
  • Export data for analysis
  • View transaction history for zero-sum verification

Tech Stack

Component Technology
Backend FastAPI + Python 3.14
Database SQLite (file-based)
ORM SQLAlchemy 2.0
Frontend React 18 + TypeScript + Vite
Styling Tailwind CSS
Icons Lucide React
Auth JWT tokens
Real-time Server-Sent Events (SSE)
Testing Vitest + pytest
Container Docker Compose
Dependency Mgmt uv (backend), npm (frontend)

Project Structure

office-betting/
├── docker-compose.yml       # One-command startup
├── README.md
├── SPECIFICATION.md         # Full technical specification
│
├── backend/
│   ├── Dockerfile
│   ├── pyproject.toml
│   ├── data/                # SQLite database (created on startup)
│   ├── migrations/          # Alembic database migrations
│   └── src/mirustech/betting/
│       ├── main.py          # FastAPI app
│       ├── config.py        # Settings
│       ├── database.py      # SQLAlchemy setup
│       ├── models/          # Database models
│       ├── schemas/         # Pydantic schemas
│       ├── routers/         # API routes
│       │   ├── auth.py
│       │   ├── bets.py
│       │   ├── organizations.py
│       │   ├── members.py
│       │   ├── invitations.py
│       │   ├── notifications.py
│       │   ├── comments.py
│       │   ├── achievements.py
│       │   ├── activity.py
│       │   ├── categories.py
│       │   ├── seasons.py
│       │   ├── transactions.py
│       │   ├── uploads.py
│       │   ├── audit.py
│       │   ├── reports.py
│       │   ├── export.py
│       │   └── ...
│       ├── services/        # Business logic
│       └── seed.py          # Seed data
│
└── frontend/
    ├── Dockerfile
    ├── package.json
    └── src/
        ├── api/             # API client
        ├── components/      # React components
        ├── pages/           # Page components
        ├── hooks/           # Custom hooks
        ├── contexts/        # React contexts
        └── types/           # TypeScript types

API Endpoints

Authentication

  • POST /api/auth/register - Create account
  • POST /api/auth/login - Get JWT token
  • GET /api/auth/me - Current user info
  • PUT /api/auth/me - Update profile
  • POST /api/auth/forgot-password - Password reset request
  • POST /api/auth/reset-password - Reset password with token

Organizations

  • GET /api/organizations - List user's organizations
  • POST /api/organizations - Create organization
  • GET /api/organizations/{slug} - Get organization details
  • PUT /api/organizations/{slug} - Update organization (admin)
  • DELETE /api/organizations/{slug} - Delete organization (owner)
  • GET /api/organizations/{slug}/members - List members
  • POST /api/organizations/{slug}/invitations - Create invitation (admin)
  • POST /api/organizations/{slug}/join - Join via invite code

Bets

  • GET /api/bets - List all bets (filterable by status, category, season)
  • POST /api/bets - Create new bet
  • GET /api/bets/{id} - Get bet details with odds
  • POST /api/bets/{id}/wager - Place a wager
  • POST /api/bets/{id}/resolve - Resolve bet (creator only)
  • POST /api/bets/{id}/report - Report bet for moderation

Comments

  • GET /api/bets/{id}/comments - Get bet comments
  • POST /api/bets/{id}/comments - Post comment
  • PUT /api/comments/{id} - Edit comment
  • DELETE /api/comments/{id} - Delete comment

Notifications

  • GET /api/notifications/stream - SSE stream for real-time notifications
  • GET /api/notifications - List notifications
  • PUT /api/notifications/{id}/read - Mark as read
  • POST /api/notifications/read-all - Mark all as read

Other

  • GET /api/leaderboard - Organization leaderboard
  • GET /api/users/me/wagers - User's wager history
  • GET /api/activity - Recent activity feed
  • GET /api/achievements - List achievements
  • GET /api/transactions - Transaction history (admin)
  • GET /api/audit - Audit log (admin)
  • POST /api/uploads/avatar - Upload avatar
  • POST /api/uploads/org-logo - Upload org logo

Development Setup

Backend (without Docker)

cd backend
uv sync
source .venv/bin/activate  # or `.venv\Scripts\activate` on Windows

# Run migrations
alembic upgrade head

# Seed data
python -m mirustech.betting.seed

# Run development server
uvicorn mirustech.betting.main:app --reload --port 8000

# Run tests
pytest

# Type checking
mypy src/

# Linting
ruff check .

Frontend (without Docker)

cd frontend
npm install
npm run dev  # Starts on http://localhost:5173

# Run tests
npm test

# Build for production
npm run build

# Type checking
npx tsc --noEmit

# Linting
npm run lint

Configuration

Environment variables (can be set in docker-compose.yml or .env):

Variable Default Description
BETTING_DATABASE_URL sqlite+aiosqlite:///./data/betting.db Database connection
BETTING_JWT_SECRET_KEY dev-secret-key... JWT signing key (change in production!)
BETTING_DEBUG false Debug mode

Organization-level settings (configurable per org):

  • initial_balance - Starting coins for new members (default: 1000)
  • minimum_wager - Minimum wager amount (default: 50)
  • early_bet_bonus - Weight multiplier for early bets (default: 1.2)
  • house_fee_pct - House fee percentage (default: 0.05 = 5%)
  • allow_public_join - Allow anyone to join (default: false)

Zero-Sum Accounting

All coin movements are tracked via the Transaction model:

sum(payouts) + house_fee = sum(wagers)
house_fee = total_pool * house_fee_pct
distributable = total_pool - house_fee
payout_i = (weighted_wager_i / total_winning_weight) * distributable

Every bet resolution creates transactions that maintain zero-sum balance across the organization.

Testing

Backend Tests

cd backend
pytest                        # Run all tests
pytest -v                     # Verbose output
pytest --cov                  # With coverage report
pytest tests/integration/     # Integration tests only

Frontend Tests

cd frontend
npm test                      # Run in watch mode
npm run test:run              # Run once
npm run test:coverage         # With coverage report

Migration from v1.0

v2.0 is a complete rewrite with a different database schema. There is no automated migration path from v1.0. Key changes:

  • Balances: v1.0 had global balances, v2.0 has per-organization balances
  • Organizations: v2.0 introduces multi-tenancy
  • Transactions: v2.0 has complete audit trail
  • Notifications: v2.0 has real-time SSE notifications

Deployment Notes

For production deployment:

  1. Change the JWT secret: Set a strong random BETTING_JWT_SECRET_KEY
  2. Use a proper database: Consider PostgreSQL for production instead of SQLite
  3. Enable email verification: Configure email settings for user verification
  4. Set up reverse proxy: Use nginx or similar for SSL termination
  5. Configure file uploads: Set up proper file storage (S3, etc.)
  6. Monitor transactions: Regularly verify zero-sum accounting via /api/transactions
  7. Backup database: Regular backups of the SQLite file or database

License

MIT

Contributing

This is a personal/office project. Feel free to fork and adapt for your own use!