sailing_forms/README.md

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.yaml without 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 Dockerfile and docker-compose.yaml utilizing gunicorn for 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.json file 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

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:

  1. Create a virtual environment and activate it:
    python -m venv .venv
    source .venv/bin/activate
    
  2. Install the required dependencies:
    pip install -r requirements.txt
    
  3. 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)