3.7 KiB
Sailing Forms
A self-hosted Flask-based custom signup application for managing sailing event registrations. It provides dynamically generated registration forms based on a YAML configuration and automatically saves submitted data to Google Sheets.
Features
- Dynamic Event Forms: Simply define new events in
events.yamlwithout touching the code. Each event gets a clean URL based on its slug (e.g.,domain.com/zomeravond). - Google Sheets Integration: Automatically appends participant details to specific Google Sheet tabs in real-time.
- Public Participant Lists: Securely displays public-safe participant data (e.g., class, sail number, boat name) at the bottom of the registration page, while keeping sensitive info (email, phone) private.
- CSRF Protection: Form submissions are protected against Cross-Site Request Forgery.
- Dockerized Base: Includes a
Dockerfileanddocker-compose.yamlutilizinggunicornfor simple and reliable production deployments.
Prerequisites
- Python 3.9+ (if running locally)
- Docker and Docker Compose (if deploying via containers)
- Google Service Account: You need a
credentials.jsonfile authorized for the Google Sheets API.
Setup & Configuration
1. Credentials
Place your Google Service Account credentials inside a file named credentials.json in the root of the project. This is required for the application to access the Google Sheets via the gspread library.
2. Environment Variables
Create a .env file in the root directory and add a secure, random string to be used as your Flask session secret key. This is required for CSRF protection and session management.
SECRET_KEY=your_very_secret_random_string_here
3. Events Configuration (events.yaml)
Define your sailing events in events.yaml. You can set a global master_sheet_id or specific sheet_id for each event. The tab_name specifies which worksheet inside the Google Sheet the data should append to.
master_sheet_id: "your_spreadsheet_id_here" # From the Google Sheets URL
events:
zomeravond: # The URL slug
title: "Zomeravondregatta 2026"
tab_name: "Zomeravond 2026" # Exact tab name in Google Sheets
description: "De gezelligste avondwedstrijd van het jaar."
Running the Application
Option A: Using Docker (Recommended for Production)
The easiest way to run the service is using Docker Compose. The docker-compose.yaml is configured to mount your configuration and credentials without rebuilding the container.
docker-compose up -d --build
The application will run on port 5000 (mapped to localhost:5000). Make sure your credentials.json, .env and events.yaml files are in the same directory as the docker-compose.yaml file so they are correctly mounted into the container as volumes.
Option B: Local Development
If you're making changes to the codebase and need to run it directly:
- Create a virtual environment and activate it:
python -m venv .venv source .venv/bin/activate - Install the required dependencies:
pip install -r requirements.txt - Run the development server:
python app.py
Automated Testing
The project uses pytest for unit and E2E testing (located in the tests/ directory).
To run the tests locally:
pytest
Note: The testing suite automatically bypasses the need for a real SECRET_KEY and passes TESTING_NO_APPEND=1 to prevent test submissions from cluttering the live Google Sheets.
Tech Stack Overview
- Backend Context: Flask (Web Framework), Gunicorn (Production WSGI server)
- Google Sheets Integration:
gspread - Data Configuration:
PyYAML - Frontend Context: Rendered via standard Jinja2
templates/(HTML)