This repo holds the code for the Frontend of the "TKD Registration Project".
graph TB
User((User))
Admin((Admin))
subgraph "Main System"
subgraph "Frontend (This Repo)"
FrontendApp["Frontend App<br/>(Flask)"]
subgraph "Frontend Components"
UIBlueprint["UI Blueprint<br/>(app.py — HTMX routes)"]
APIBlueprint["API Blueprint<br/>(api.py — JSON REST /api/v1)"]
Models["Models<br/>(models.py — SQLAlchemy)<br/>School · Coach · Competitor"]
end
end
subgraph "Data Storage"
subgraph Supabase["Supabase (Postgres)"]
SchoolsTable[("schools")]
CoachesTable[("coaches")]
CompetitorsTable[("competitors")]
end
S3[("S3 Buckets")]
end
EmailService["Email Service"]
end
User --> FrontendApp
Admin --> FrontendApp
FrontendApp --> UIBlueprint
FrontendApp --> APIBlueprint
UIBlueprint --> Models
APIBlueprint --> Models
Models --> SchoolsTable
Models --> CoachesTable
Models --> CompetitorsTable
APIBlueprint --> EmailService
Admin --> SupabaseAuth
FrontendApp --> SupabaseAuth
APIBlueprint --> Stripe
EmailService ~~~ Stripe
S3 ~~~ SupabaseAuth
subgraph "External Services"
Stripe["Stripe API"]
SupabaseAuth["Supabase Auth"]
end
classDef frontend fill:#1168bd,stroke:#0b4884,color:#ffffff
classDef frontendComponent fill:#4682b4,stroke:#315b7e,color:#ffffff
classDef backend fill:#2694ab,stroke:#1a6d7d,color:#ffffff
classDef database fill:#2b78e4,stroke:#1a4d91,color:#ffffff
classDef legacy fill:#888888,stroke:#555555,color:#ffffff
classDef external fill:#999999,stroke:#666666,color:#ffffff
class FrontendApp frontend
class UIBlueprint,APIBlueprint,Models frontendComponent
class SchoolsTable,CoachesTable,CompetitorsTable,S3 database
class Stripe,SupabaseAuth external
- Setup Stripe Account
- Create a Supabase project (for Postgres DB and Auth)
- Deploy base infrastructure using the tkd-registration Terraform Module. This must be done first.
- Deploy the Backend. This can be done before or after.
- Python 3.13+
- uv package manager
app.py # UI Blueprint — all page and HTMX partial routes (Flask)
api.py # API Blueprint — JSON REST endpoints at /api/v1
models.py # SQLAlchemy models (School, Coach, Competitor)
templates/ # Jinja2 HTML templates
static/ # Static assets (CSS, images, etc.)
tests/ # pytest test suite
envs/ # Zappa deployment config YAML files (one per environment)
pyproject.toml
-
Install
uvand sync dependencies:curl -LsSf https://astral.sh/uv/install.sh | sh uv sync --all-extras --dev -
Create a
.envfile with the necessary environment variables (see table below). -
Initialize the database (first time only):
set -a && source .env && set +a uv run python scripts/init_db.py
If you need to recreate the local database from scratch, use:
set -a && source .env && set +a uv run python scripts/reset_db.py
-
Run the local development server:
set -a && source .env && set +a flask --app app --debug run
Or use the VSCode debugger via the existing
launch.json.
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | Supabase Postgres connection string (postgresql+psycopg://...) |
SUPABASE_URL |
Yes | Supabase project URL (e.g. https://xxxx.supabase.co) |
SUPABASE_ANON_KEY |
Yes | Supabase anon public key |
SUPABASE_SERVICE_ROLE_KEY |
Yes | Supabase service role key (for admin operations) |
SUPABASE_JWT_SECRET |
Yes | Supabase JWT secret (for verifying API tokens) |
FLASK_SECRET_KEY |
Yes | Random secret for Flask session signing |
COMPETITION_NAME |
Yes | Name to use for the competition |
COMPETITION_YEAR |
No | Year of the competition |
CONTACT_EMAIL |
Yes | Contact email shown to registrants |
ADMIN_EMAIL |
Yes | Email address that receives admin alerts (e.g., unknown school notifications) |
EMAIL_SERVER |
Yes | SMTP server hostname used for outbound emails |
EMAIL_PORT |
Yes | SMTP server port (e.g., 465) |
FROM_EMAIL |
Yes | Sender email address used for outbound emails |
EMAIL_PASSWD |
Yes | SMTP password or app password for FROM_EMAIL |
EARLY_REG_DATE |
Yes | When the early registration discount ends (e.g. June 01, 2026) |
REG_CLOSE_DATE |
Yes | When to close registrations (e.g. July 01, 2026) |
CONFIG_BUCKET |
Yes | S3 bucket containing config files (schools.json, weight_classes.json, etc.) |
PUBLIC_MEDIA_BUCKET |
Yes | S3 bucket for public media (schedule, booklet) |
PROFILE_PIC_BUCKET |
No | S3 bucket for profile pictures |
STRIPE_API_KEY |
Yes | Stripe secret API key |
STRIPE_WEBHOOK_SECRET |
Yes | Stripe webhook signing secret (whsec_...) |
STRIPE_DEFAULT_UNIT_AMOUNT |
No | Stripe Checkout amount in cents used by /api/v1/registrations (default: 5000) |
REG_URL |
Yes | Public URL of the deployed app |
AWS_REGION |
No | AWS region for S3 (default: us-east-1) |
AWS_DEFAULT_REGION |
No | Alternative AWS region env var |
AWS_PROFILE |
No | AWS profile from ~/.aws/config for local dev |
LOCAL_TIMEZONE |
No | Timezone for date display (default: US/Central) |
MAPS_API_KEY |
No | Google Maps API key (required if ENABLE_ADDRESS=true) |
ENABLE_ADDRESS |
No | Set to true to show address field on registration form |
ENABLE_BADGES |
No | Set to true to enable badge generation feature |
BUTTON_STYLE |
No | Bootstrap button class (default: btn-primary) |
EVENT_CITY |
No | City name shown on event info page |
VISITOR_INFO_URL |
No | URL for the visitor info button |
VISITOR_INFO_TEXT |
No | Label for the visitor info button |
CONNECT_ACCT |
No | Stripe Connect account ID (for split payments) |
Admin users are managed in Supabase. After creating a user via the Supabase dashboard, set their app_metadata using the Supabase admin API:
curl -X PUT 'https://<your-project>.supabase.co/auth/v1/admin/users/<user-uuid>' \
-H "Authorization: Bearer <service_role_key>" \
-H "Content-Type: application/json" \
-d '{"app_metadata": {"role": "admin"}}'This project uses Zappa for deployments to AWS Lambda.
Each environment has a YAML file in the envs folder. Environment variables are loaded at runtime from a JSON file stored in S3 (configured via remote_env in the YAML).
- Ensure a yml file exists in envs for your target environment.
- Activate your virtual environment (
.venv) or rely onuv run. - First-time deploy:
uv run zappa deploy <env_name> -s envs/<env_file>.yml
- Subsequent updates:
uv run zappa update <env_name> -s envs/<env_file>.yml
- Optional — set up a custom domain TLS cert:
uv run zappa certify <env_name> -s envs/<env_file>.yml
The S3 env JSON must include all required variables from the table above. At minimum, ensure the following are set:
{
"DATABASE_URL": "postgresql+psycopg://...",
"SUPABASE_URL": "https://xxxx.supabase.co",
"SUPABASE_ANON_KEY": "...",
"SUPABASE_SERVICE_ROLE_KEY": "...",
"SUPABASE_JWT_SECRET": "...",
"FLASK_SECRET_KEY": "...",
"COMPETITION_NAME": "...",
"COMPETITION_YEAR": "...",
"CONTACT_EMAIL": "...",
"ADMIN_EMAIL": "...",
"EMAIL_SERVER": "...",
"EMAIL_PORT": "...",
"FROM_EMAIL": "...",
"EMAIL_PASSWD": "...",
"CONFIG_BUCKET": "...",
"STRIPE_API_KEY": "...",
"STRIPE_WEBHOOK_SECRET": "whsec_..."
}Use Stripe CLI to forward events to your local API webhook endpoint:
stripe listen --forward-to localhost:5001/api/v1/webhooks/stripe
stripe trigger checkout.session.completed
stripe trigger checkout.session.expiredSet the signing secret printed by stripe listen in your .env as STRIPE_WEBHOOK_SECRET.
Run Flask-Migrate against your Supabase Postgres instance:
# First time only — generates the migrations/ directory
uv run flask --app app db init
# Generate the initial schema migration
uv run flask --app app db migrate -m "initial schema"
# Apply to Supabase
uv run flask --app app db upgradeSubsequent schema changes: run flask db migrate + flask db upgrade after changing models.py.