A comprehensive Django-based management system for endurance go-kart races and championships with advanced race control features, penalty management, and hardware integration for stop-and-go penalty stations.
- Championship Management: Create and manage multi-round championships with customizable settings
- Round Configuration: Flexible race setup with duration, pit lane timing, weight penalties, and driver change requirements
- Team & Driver Management: Comprehensive driver registration, team formation, and participant management
- Real-time Race Control: Live race monitoring with start/pause/resume controls and false start control.
- Multiple Penalty Types:
- Stop & Go: Traditional stop-and-go penalties with victim assignment
- Self Stop & Go: No-victim penalties for self-imposed infractions
- Laps Penalties: Deduct laps from teams
- Post Race Laps: Apply penalties after race completion
- Penalty Configuration: Championship-specific penalty setup with fixed/variable/per-hour options
- Penalty Tracking: Complete audit trail of imposed and served penalties
- Transponder Management: Dedicated CRUD interface for registering and managing transponders
- Add/edit/delete transponders with descriptions and active status
- Live scan detection: click "Scan" to listen for a transponder passing the loop and auto-fill its ID
- Delete protection: transponders assigned to active races cannot be removed
- Transponder Matching: Assign transponders to teams for each race
- Kart number auto-defaults to team number (user can override)
- Scan button for quick transponder detection during assignment
- Assignments auto-clone to dependent races (Q1 assignments carry forward to Q2, Q3, MAIN)
- Redundant transponders: assign multiple transponders per team for hardware redundancy — a 7-second deduplication window ensures only one crossing per lap is counted; if all transponders miss a lap, the resulting suspicious lap is flagged in race control with a one-click split option
- Qualifying Race Configuration: Multi-session qualifying support
- Configure 0-3 qualifying sessions (Q1, Q2, Q3) before the main race
- Two qualifying ending modes: standard (before time) and F1-style (last lap after time)
- Two grid methods: Best Time (combined best lap across sessions) and Elimination (knockout with cutoffs)
- Per-session duration and cutoff configuration
- Automatic creation of Race objects with correct dependencies (Q2 depends on Q1, MAIN depends on last Q)
- Stop & Go Station: Raspberry Pi-based penalty station with:
- Physical button and sensor integration
- Electronic fence control via I2C relays
- Real-time display with countdown timers
- HMAC-secured WebSocket communication
- Automatic penalty completion detection
- Timing Station: Transponder timing system with:
- Plugin-based hardware support (TAG Heuer serial, Chronelec NetTag, simulator)
- Multiple timing modes (interval, duration, time of day, decoder own time)
- SQLite disk buffer with at-least-once delivery and ACK protocol
- Native systemd service deployment
- HMAC-secured WebSocket communication
- Transponder scan broadcast: raw detections are forwarded to management/matching pages via WebSocket
- WebSocket Integration: Live updates across all interfaces
- Pit Lane Monitoring: Real-time pit lane status and driver changes
- Session Management: Automatic driver session tracking and queue management
- Live Dashboards: Team carousels, penalty displays, and race information
- Race Control Dashboard: Comprehensive race director interface
- Team Monitoring: Individual team status and multi-team views
- Driver Queue Management: Real-time pending driver tracking
- Penalty Management: Intuitive penalty assignment and monitoring
- Mobile-Responsive: Works on all devices
- RESTful API: Token-based authentication for external systems
- QR Code Integration: Driver and team scanning capabilities
- Data Export: Comprehensive race results and statistics
- Multi-user Support: Role-based access control (Race Directors, Queue Scanners, etc.)
- Web Config UI (no CLI required): an HTTPS browser interface to edit
.env, manage per-venue Location profiles, configure the decoder proxy, manage SSL, and run service/deploy commands with live output — see Config UI. Locked automatically while a race is live. race-managerCLI: one script for service control, SSL, secrets, station config, backups, and native-service deployment.
- Docker and Docker Compose
- Git
- Domain name (optional, for SSL/HTTPS)
# 1. Clone and navigate
git clone https://github.com/frawau/endurance-go-kart.git
cd endurance-go-kart
# 2. Create and configure .env file
cp .env.example .env # Create .env from template
./race-manager generate-secret # Generate and add secure secrets to .env
# Edit .env: Set APP_HOSTNAME, configure timezone, adjust other settings
# 3. Start the application (prompts for an admin username/password on first run)
./race-manager startThat's it! Access at http://your-domain:5085
Log in with the admin credentials you set when start first ran
(or run ./race-manager create-admin to create/recreate it).
Prefer a browser over the CLI? Install the web configurator once with
sudo ./race-manager deploy-configui and manage everything (.env, locations,
proxy, SSL, service control) from https://your-domain:7443/ — see
Config UI.
./race-manager enable-letsencrypt # Configure Let's Encrypt
./race-manager generate-cert # Generate certificate
# Now available at https://your-domain.com
# Certificates auto-renew - zero maintenance!By default this uses the HTTP-01 challenge (needs port 80 reachable from the
internet). For hosts behind NAT/firewall, or for wildcard certificates, set
ACME_CHALLENGE=dns plus an acme.sh DNS provider (ACME_DNS_PROVIDER=dns_cf,
…) and that provider's API credentials in .env — see the
acme.sh dnsapi list.
The Config UI exposes both under SSL settings.
For production deployment, Docker provides easier setup and consistent environment:
- Docker and Docker Compose
- Git
-
Clone the repository
git clone https://github.com/frawau/endurance-go-kart.git cd endurance-go-kart -
Configure environment variables
Create your
.envfile from the template:cp .env.example .env
Edit the
.envfile to match your setup:# Database settings POSTGRES_USER=gokart POSTGRES_PASSWORD=gokart POSTGRES_DB=gokart # Admin user: created after first start with `./race-manager create-admin` # (it prompts for username/password), so it is not stored in .env. # Security keys (generate your own - see examples below!) SECRET_KEY=your-django-secret-key-change-this-to-something-random-and-secure STOPANDGO_HMAC_SECRET=your-hmac-secret-for-station-security-also-change-this # Your domain APP_HOSTNAME=host.your-domain.com # HTTP port (optional, default: 5085 for HTTP-only, 80 for SSL modes) APP_PORT=5085 # Timezone for all containers TZ=Asia/Bangkok
Port Configuration:
- HTTP-only mode (
SSL_MODE=none): UsesAPP_PORT(default: 5085) - good for development - SSL modes (
letsencrypt,acme,manual): Automatically uses port 80 (required for Let's Encrypt) and 443 - The race-manager script handles port assignment automatically
Generate Secure Keys:
Use the race-manager script (recommended):
./race-manager generate-secret
This will generate three secure random secrets, update your
.envfile, and propagate the values into the station TOML config files automatically.SECRET_KEY- Django's cryptographic signing keySTOPANDGO_HMAC_SECRET- Hardware station authenticationTIMING_HMAC_SECRET- Timing daemon authentication (optional)
If you later change
.envvalues manually (e.g.APP_HOSTNAME), re-run:./race-manager configure-stations
Alternative manual methods:
# Using OpenSSL openssl rand -base64 64 # Using Python python -c "import secrets; print(secrets.token_urlsafe(64))" # Using online generator # Visit: https://djecrety.ir/ (Django-specific secret generator)
Important Security Notes:
SECRET_KEY: Django's secret key for cryptographic signing. Generate a unique 50+ character random stringSTOPANDGO_HMAC_SECRET: Used for secure communication with hardware penalty stations. This same secret must be configured on your Stop & Go station hardware- The first
./race-manager startprompts you to set the admin username and password (or run./race-manager create-admin) — choose a strong password - Use strong, unique passwords for production deployments
.envfile is NOT tracked by git - it's in.gitignoreto protect your secrets- On production servers,
git pullwill never overwrite your.envfile
- HTTP-only mode (
-
Start the application
./race-manager start
On a fresh install,
startdetects that no admin user exists yet and prompts you for an admin username and password (skipped automatically when run non-interactively, e.g. from a deploy script). You can also create or recreate it any time with./race-manager create-admin.The application will be available at
http://your-domain:5085. -
Initial setup and configuration
a. Log in with the admin credentials you set during
startb. Create additional users (optional)
- In Django admin, go to Users
- Add a new user with your preferred credentials
- Assign the user to groups:
AdminandRace Director - You can now start configuring championships and races
Using race-manager (recommended):
# View logs
./race-manager logs
# Stop the application
./race-manager stop
# Restart with current configuration
./race-manager restart
# Check SSL and service status
./race-manager status
# Update application after git pull
git pull
./race-manager rebuild # Rebuild container with new codeUsing Docker Compose directly (advanced):
# View logs
docker compose logs -f
# Stop the application
docker compose down
# Reset database (removes all data)
docker compose down
docker volume rm endurance-go-kart_postgres_data
docker compose up -d
# Update application
git pull
docker compose down
docker compose up -d --build# Connect to PostgreSQL container
docker exec -it postgres psql -U gokart -d gokart
# Backup database
docker exec postgres pg_dump -U gokart gokart > backup.sql
# Restore database
docker exec -i postgres psql -U gokart gokart < backup.sqlWhen to use rebuild vs restart:
-
rebuild- Use aftergit pullor when you modify:- Python code (views.py, models.py, etc.)
- Templates (HTML files)
- Static files
- requirements.txt
- Any application code
-
restart- Use when you only change:- .env file (environment variables)
- Configuration settings (SSL_MODE, APP_HOSTNAME, etc.)
The Dockerfile copies code into the image at build time, so code changes require rebuilding the container.
For local development or if you prefer not to use Docker:
- Python 3.8+
- Django 4.2+
- Redis (for WebSocket support)
- PostgreSQL or SQLite
# Clone the repository
git clone https://github.com/frawau/endurance-go-kart.git
cd endurance-go-kart
# Create virtual environment
python -m venv env
source env/bin/activate # On Windows: env\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Create .env file from template
cp .env.example .env
# Generate secrets (automatically updates .env)
./race-manager generate-secret
# Set up database
python manage.py makemigrations
python manage.py migrate
# Create superuser
python manage.py createsuperuser
# Initialize database with sample data (optional)
python manage.py initialisedb
# Start the development server
python manage.py runserverThe application will be available at http://127.0.0.1:8000
The application supports four SSL modes controlled by the SSL_MODE environment variable:
none(Default) - HTTP only, no SSLletsencrypt- Automatic SSL with Let's Encrypt (recommended)- Fully automated certificate generation and renewal
- Certificates renew automatically every 60 days (90-day validity)
- Zero maintenance required
acme- Automatic SSL with ZeroSSL (requires email registration)- Same automated renewal as Let's Encrypt
manual- Manual SSL (provide your own certificates)- You manage renewal yourself
Use the included race manager script for easy SSL management:
# Start application (HTTP mode)
./race-manager start
# Check current SSL status
./race-manager status
# Enable automatic SSL with Let's Encrypt (recommended)
./race-manager enable-letsencrypt # Updates .env to SSL_MODE=letsencrypt
./race-manager generate-cert # Generates and installs certificate
# Your site is now available at https://your-domain.com
# Alternative: Enable automatic SSL with ZeroSSL
./race-manager enable-acme # Updates .env to SSL_MODE=acme
./race-manager generate-cert # Generates and installs certificate
# Enable manual SSL (provide your own certificates)
./race-manager enable-manual # Updates .env to SSL_MODE=manual
# Place certificates in ./ssl/fullchain.pem and ./ssl/privkey.pem
./race-manager install-cert # Installs certificates
# Disable SSL (back to HTTP only)
./race-manager disable-ssl # Updates .env to SSL_MODE=none
./race-manager restart # Applies changes
# Other useful commands
./race-manager stop # Stop all services
./race-manager restart # Restart with current configuration
./race-manager logs # View logsIf you prefer to configure SSL manually without using race-manager:
For Automatic SSL (Let's Encrypt):
-
Edit
.env:SSL_MODE=letsencrypt APP_HOSTNAME=host.your-domain.com SSL_EMAIL=admin@your-domain.com
-
Start services with acme.sh profile:
docker compose --profile ssl-acme up -d
-
The race-manager script handles certificate generation automatically, but if running manually:
docker compose exec acme-sh acme.sh --set-default-ca --server letsencrypt docker compose exec acme-sh acme.sh --register-account -m admin@your-domain.com docker compose exec acme-sh acme.sh --issue -d your-domain.com --webroot /var/www/certbot docker compose exec acme-sh acme.sh --install-cert -d your-domain.com \ --cert-file /etc/ssl/certs/cert.pem \ --key-file /etc/ssl/certs/privkey.pem \ --fullchain-file /etc/ssl/certs/fullchain.pem docker compose restart nginx
For Automatic SSL (ZeroSSL):
-
Edit
.env:SSL_MODE=acme APP_HOSTNAME=host.your-domain.com SSL_EMAIL=admin@your-domain.com
-
Follow the same steps as Let's Encrypt, but ZeroSSL doesn't require setting default CA
-
For manual certificates, place your files in
./ssl/:fullchain.pem- Full certificate chainprivkey.pem- Private key (MUST be unencrypted/no passphrase)
- Private key must be unencrypted - nginx cannot handle password-protected keys
- Domain must point to your server - required for Let's Encrypt validation
- Port 80 must be accessible - needed for HTTP ACME challenge
# SSL Configuration (uncomment to enable)
# SSL_MODE=none # none|acme|manual
# SSL_EMAIL=admin@your-domain.com
#
# For manual mode
# SSL_CERT_PATH=./ssl/fullchain.pem
# SSL_KEY_PATH=./ssl/privkey.pem
#
# For acme.sh mode
# ACME_CHALLENGE=http # http|dns-cloudflare|dns-route53Important: The application automatically detects HTTP vs HTTPS and uses the appropriate WebSocket protocol (ws:// or wss://).
- Create Championship: Define championship parameters and rounds
- Configure Penalties: Set up penalty types with values and options
- Register Teams: Add teams and assign numbers
- Add Drivers: Register drivers with photos and details
- Setup Rounds: Configure race parameters and ready the round
- Race Control: Use the race control interface to manage live races
For the Stop & Go penalty station:
# On Raspberry Pi
cd stations/
python stopandgo-station.py --button 18 --fence 36 --server your-domain.com -port 443- Raspberry Pi with GPIO access (Tested on RPi Zero 2 W)
- Physical button (normally open)
- Fence sensor (optional, can be disabled) for area breach detections (e.g. early start)
- I2C relay board (optional) for, for example, flashing lights control
- Display (Required for status and countdown)
The timing station relays transponder crossing events from decoder hardware to the Django app via WebSocket. It runs as a native systemd service on the host (not in Docker) because it needs direct LAN access to the timing decoder hardware.
# Configure timing settings in .env
TIMING_PLUGIN_TYPE=nettag # simulator|tag|nettag
TIMING_MODE=own_time # interval|duration|time_of_day|own_time
TIMING_NETTAG_HOST=192.168.0.11 # NetTag: decoder IP address
TIMING_NETTAG_PORT=2009 # NetTag: decoder port
TIMING_NETTAG_PROTOCOL=udp # NetTag: udp or tcp
TIMING_TAG_DEVICE=/dev/ttyUSB0 # TAG: serial device
TIMING_TAG_BAUD=9600 # TAG: baud rate
# Deploy as systemd service (creates venv, installs deps, generates config)
sudo ./race-manager deploy-timing
# Management
sudo ./race-manager timing-status # Check service status
sudo ./race-manager undeploy-timing # Stop and remove service
journalctl -u timing-station -f # View logsThe deploy-timing command:
- Creates a Python venv at
stations/timing/venv/ - Installs dependencies (websockets, toml, pyserial-asyncio)
- Generates
timing-station.tomlfrom.envvalues viaconfigure-stations - Installs and starts the systemd service
See stations/timing/README.md for detailed configuration and protocol documentation.
When using a Chronelec decoder via a Lantronix serial-to-UDP converter, the Lantronix only supports a single remote endpoint. The NetTag proxy sits on the host machine, maintains the single upstream connection to the decoder, and fans out frames to multiple downstream clients (e.g., timing station and a test/logging system).
Each client gets its own buffered queue backed by SQLite (WAL mode). If a client falls behind or disconnects, frames accumulate and are replayed rapidly on reconnect.
Port layout when proxy and timing station are co-located:
:2009— proxy upstream (receives from decoder):2010— proxy downstream (sends frames to clients, receives ACKs):2011— timing station (receives frames from proxy)
-
Edit
proxy/nettag-proxy.tomlwith your decoder address and client list:[upstream] decoder_host = "192.168.0.11" decoder_port = 2009 [downstream] listen_port = 2010 resend_interval = 1.0 [[client]] host = "127.0.0.1" port = 2011
The client on
127.0.0.1is the co-located timing station. (You can edit all of this from the Decoder Proxy page in the Config UI instead of by hand — it also lets you add/remove extra clients.) -
Deploy and start:
sudo ./race-manager deploy-proxy
deploy-proxynow also couples the timing station to the proxy: it reads the local (127.0.0.1) client port from the proxy config, repoints the timing station at it (TIMING_NETTAG_HOST=127.0.0.1,TIMING_NETTAG_PORT=<that port>, moving the real decoder address into the proxy's[upstream]), runsconfigure-stations, and deploys the timing station if it isn't already — because a proxy is pointless without one. Conversely,undeploy-proxyreverts the timing station to talk to the decoder directly.
sudo ./race-manager deploy-proxy # Install and start systemd service
./race-manager proxy-status # Check service status
sudo ./race-manager undeploy-proxy # Stop and remove service
journalctl -u nettag-proxy -f # View logsFor operators who would rather not touch the CLI, the Config UI is a small
HTTPS web service that edits .env, saves/switches named Location profiles,
configures the decoder proxy (including its client list), and runs the
race-manager commands above with live output. It runs as a native systemd
service (it needs to edit the host .env and call the host race-manager, so it
cannot live in Docker).
A Location snapshots both .env and the decoder-proxy config, so per-venue
settings travel together. Switching a Location restores both (keeping the
configurator's own login/port intact), then automatically reconfigures the
stations and restarts the services so the change takes effect.
Race-day lock: while a round is live — from the moment its pre-race check
passes (Round.ready) until the round is ended — the Config UI refuses all
configuration changes and service commands (read-only views and status commands
stay available), so nobody can disturb a running event. It learns the state from
a read-only /api/config_lock/ endpoint on the app; if the app is unreachable it
fails open (assumes no race is running). This needs the app rebuilt once
(race-manager rebuild) after pulling, for the endpoint to exist.
# Install once (creates venv, installs deps, generates a login password,
# installs a least-privilege sudoers rule, starts the HTTPS service)
sudo ./race-manager deploy-configuideploy-configui:
- Creates
configui/venvand installsconfigui/requirements.txt. - Generates
CONFIGUI_PASSWORDin.envif not already set (and prints it). - Installs
/etc/sudoers.d/configuiallowing the service user to run only therace-managerscript without a password (validated withvisudo -cf). - Installs and starts the
configuisystemd service.
It is HTTPS-only: it uses ssl/fullchain.pem + ssl/privkey.pem if present
(the same certificate the app uses), otherwise it generates a self-signed
certificate under /var/lib/configui/ssl/. Access it at
https://<APP_HOSTNAME>:7443/ (override with CONFIGUI_PORT). Keep it on a
trusted network — it can change configuration and run deployment commands.
In automatic SSL modes (letsencrypt/acme) the issued certificate lives in the
acme.sh Docker volume, not on the host. deploy-configui therefore exports it
into ./ssl/ and installs a daily cron job (/etc/cron.d/configui-cert-sync)
that re-copies it after each renewal and restarts the Config UI (only when it
changed) — so it serves the real certificate with no manual steps. You can run the
export on demand with ./race-manager sync-acme-cert.
Tip: run
deploy-configuias the final step of a fresh install — from then on the rest of the system can be configured entirely from the browser.
./race-manager configui-status # Check service status
sudo ./race-manager undeploy-configui # Stop and remove service + sudoers rule
journalctl -u configui -f # View logsRelevant .env keys:
# CONFIGUI_PORT=7443 # HTTPS port this service listens on
# CONFIGUI_BIND=0.0.0.0 # Bind address
# CONFIGUI_PASSWORD= # Login password (auto-generated by deploy-configui)# .env file
SECRET_KEY=your-django-secret-key
DEBUG=False
APP_HOSTNAME=host.your-domain.com
STOPANDGO_HMAC_SECRET=your-hmac-secret-for-station-security
# Database (if using PostgreSQL)
DATABASE_URL=postgresql://user:password@localhost/gokartraceThe system automatically detects internal vs external connections for the agent_login endpoint by checking if the client IP belongs to any local network interface. This ensures QR code URLs include the correct port:
- Internal connections: Return URLs without port (e.g.,
https://domain.com/driver_queue/) - External connections: Return URLs with external port (e.g.,
https://domain.com:8000/driver_queue/)
No additional nginx configuration is required - the system uses network interface detection to determine connection source.
The easiest way to run Django management commands:
# Generate complete test data (RECOMMENDED - all-in-one)
./race-manager manage generate_test_data
# This creates: 30 teams, 150 drivers, 1 championship, 4 rounds, and team assignments
# Customize the number of teams and drivers
./race-manager manage generate_test_data --teams 50 --people 200
# Individual commands (if you need granular control)
./race-manager manage generate_teams --number 30
./race-manager manage generate_people --number 150
./race-manager manage initialisedb # Requires teams and people first!
# Other useful commands
./race-manager manage roundreset # Reset round data
./race-manager manage clearcache # Clear Django cacheIf you prefer not to use race-manager:
# Generate complete test data
docker compose exec appseed-app python manage.py generate_test_data
# Customize the number of teams and drivers
docker compose exec appseed-app python manage.py generate_test_data --teams 50 --people 200
# Individual commands
docker compose exec appseed-app python manage.py generate_teams --number 30
docker compose exec appseed-app python manage.py generate_people --number 150
docker compose exec appseed-app python manage.py initialisedbIf running locally without Docker:
source env/bin/activate # Activate virtual environment first
# All-in-one test data generation
python manage.py generate_test_data
# Or individual commands
python manage.py generate_teams --number 30
python manage.py generate_people --number 150
python manage.py initialisedbImportant:
- Run these on the VM/server where Docker is deployed, not on your local machine
- Use
./race-manager managefor easiest execution - Use
generate_test_datafor easiest setup - it runs all commands in the correct order
A full end-to-end race simulator that exercises the entire stack. It runs three (or four) concurrent agents that manage the race lifecycle, transponder crossings, driver changes and penalties.
./race-manager manage simulate_timed_race
./race-manager manage simulate_timed_race --speed 20 --avg-lap 60Runs at accelerated speed (default 10x). The simulator handles everything: transponder crossings via the timing WebSocket, driver changes via the HTTP API, and penalties with automatic serving. It will auto-create transponder assignments if none exist.
Prerequisites: a round with teams, drivers (weight > 10 kg) and team members assigned. The simulator takes care of pre-race check, driver registration, grid and transponder setup.
| Option | Default | Description |
|---|---|---|
--speed |
10.0 | Race-seconds per wall-second |
--avg-lap |
90.0 | Average lap time in race-seconds |
--lap-variance |
5.0 | Lap time variability |
--penalty-prob |
0.1 | Penalty probability per team per race-hour |
--timing-mode |
duration | Raw timing value mode (interval, duration, time_of_day, own_time) |
--race-id |
(auto) | Specific Race.id to simulate |
--verbose |
off | Detailed logging |
./race-manager manage simulate_timed_race --no-lapsUse this when a real timing station (or the timing station with the
simulator plugin) is handling transponder crossings. The --no-laps flag:
- Forces speed to 1x (real time)
- Disables the decoder agent (no simulated transponder crossings)
- Enables a simulated Stop & Go station that listens for actual crossings via the leaderboard WebSocket and serves penalties realistically (1-3 crossings after the penalty is given, then 8-12 s pit entry, then the countdown)
The simulator still manages:
- Race lifecycle (pre-race check, start, end)
- Initial driver registration (one random driver per team)
- Driver changes throughout the race
- Penalty creation and queueing (through the proper
PenaltyQueueflow)
Prerequisites (must be done via the UI before running):
- Teams and members assigned to the round with driver weights > 10 kg
- Transponder assignments confirmed (the real timing station needs them)
- Grid positions set (via Grid Management or auto-assign from qualifying)
- Timing station running and connected
The simulator handles pre-race check and driver registration automatically.
- Live Timing Displays: Real-time lap time leaderboards
- Automatic Position Calculation: Based on completed laps and timing
The main race control dashboard provides:
- Pre-race checks and validation
- Race start/pause/resume controls
- Live penalty assignment (Stop & Go, Laps)
- Real-time driver queue monitoring
- Pit lane status monitoring
- System message logging
- Token-based API authentication
- HMAC-signed hardware communication
- Role-based access control
- CSRF protection
- Secure WebSocket connections
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
For support and questions:
- Create an issue on GitHub
- Check existing documentation
- Review the management commands for database operations
This system has been designed and tested for real endurance go-kart championships, providing the reliability and features needed for professional race management while remaining accessible for smaller events.
Note: This system handles race management, team coordination, penalty administration, and transponder-based lap timing with support for TAG Heuer and Chronelec hardware.
