nathanb d024bf7fa3 stuff changed:
- ui has been made 'kinda better' (after making it worse for a while lol
- ESP rfid readers are now supported [ill upload the code for them in another repo later]
- admin system has been secured a bit better and seems to be working well
2026-05-08 20:46:58 +01:00
2026-05-08 20:46:58 +01:00
2026-04-26 09:43:02 +00:00
2026-05-08 20:46:58 +01:00
2026-04-26 09:43:02 +00:00
2026-04-26 09:43:02 +00:00

Swansea Airport Stakeholders' Alliance Membership Management System

A membership management system for Swansea Airport Stakeholders' Alliance, built with FastAPI, React, MySQL-compatible storage, Square payments, SMTP2GO email services, and Docker Compose.

Features

  • Authentication and accounts: Registration, JSON/form login, JWT sessions, password reset, password change, and role-based access for members, admins, and super admins.
  • Member portal: Dashboard with membership status, payment history, membership setup, account settings, profile editing, configurable profile questions, cookie notice, privacy policy, and terms of service pages.
  • Admin operations: User listing/editing, admin-triggered member password reset emails, membership tier CRUD, manual payment recording, Square refunds, email template editing with escaped previews, SMTP2GO bounce management, profile-question management, and super-admin feature-flag reloads.
  • Membership tiers: Configurable Personal, Aircraft Owners, Corporate, and custom tiers with annual fees, descriptions, active/inactive state, and benefits.
  • Memberships and payments: Membership lifecycle tracking, Square card payments, cash/check/manual payments, dummy test payments, payment history, transaction IDs, refund state, and payment-to-membership linking.
  • Events and RSVPs: Event CRUD, upcoming event listing, member RSVP updates, RSVP status tracking, attendance fields, and admin RSVP visibility.
  • Volunteer and profile data: Volunteer flag/level support, configurable member profile questions, conditional questions, admin-only answers, seeded aviation/volunteering questions, and data models for volunteer roles, assignments, schedules, and certificates.
  • Email system: SMTP2GO-backed email sending, default database templates, editable templates, welcome/password-reset/test emails, bounce webhooks, bounce stats, cleanup, and manual deactivation.
  • Feature flags: Backend feature-flag service with frontend context and admin status/reload controls.
  • Testing: Fast frontend Vitest unit tests and backend pytest unit tests wired into restart.sh.

Tech Stack

  • Backend: FastAPI (Python 3.11)
  • Frontend: React 18, TypeScript, Vite, Tailwind CSS
  • Database: MySQL 8.0
  • Authentication: JWT tokens with OAuth2
  • Containerization: Docker & Docker Compose
  • ORM: SQLAlchemy
  • Migrations: Alembic
  • Payments: Square Web Payments SDK and Square API
  • Email: SMTP2GO
  • Tests: Vitest and pytest

Project Structure

membership/
├── backend/
│   ├── alembic/                     # Database migration scripts
│   │   ├── versions/                # Migration files
│   │   ├── env.py                   # Migration environment
│   │   └── script.py.mako           # Migration template
│   ├── alembic.ini                  # Alembic configuration
│   ├── app/
│   │   ├── api/
│   │   │   ├── v1/
│   │   │   │   ├── auth.py          # Authentication endpoints
│   │   │   │   ├── users.py         # User management
│   │   │   │   ├── tiers.py         # Membership tiers
│   │   │   │   ├── memberships.py   # Membership management
│   │   │   │   ├── payments.py      # Payment processing
│   │   │   │   ├── email.py         # SMTP2GO email and bounces
│   │   │   │   ├── email_templates.py
│   │   │   │   ├── events.py        # Events and RSVPs
│   │   │   │   └── feature_flags.py
│   │   │   └── dependencies.py       # Auth dependencies
│   │   ├── core/
│   │   │   ├── config.py            # Configuration
│   │   │   ├── database.py          # Database setup
│   │   │   └── security.py          # Security utilities
│   │   ├── models/
│   │   │   └── models.py            # Database models
│   │   ├── schemas/
│   │   │   └── schemas.py           # Pydantic schemas
│   │   └── main.py                  # Application entry point
│   ├── Dockerfile
│   └── requirements.txt
├── frontend/
│   ├── src/
│   │   ├── components/              # Dashboard, payment, admin, profile components
│   │   ├── contexts/                # Feature flag context
│   │   ├── pages/                   # Login, register, dashboard, policy pages
│   │   ├── services/                # API clients
│   │   └── utils/                   # Tested frontend logic
├── docker-compose.yml
├── .env.example
└── README.md

Getting Started

Prerequisites

  • Docker
  • Docker Compose

Installation

  1. Navigate to the project directory

  2. The .env file is already configured with default settings. You can customize:

    • Square API credentials (for payment processing)
    • SMTP2GO API key (for email notifications)
    • Database password (if desired)
  3. Start the services:

    # Development mode (gateway + Vite hot reload)
    docker compose up -d
    
    # Production static frontend mode
    docker compose --profile prod up -d frontend-prod backend
    
  4. Wait for services to be ready (about 30 seconds for MySQL initialization):

    docker compose logs -f
    

    Press Ctrl+C when you see "Application startup complete"

  5. Access the application:

Restart and Test Gate

restart.sh rebuilds images with cache, runs the fast frontend and backend unit tests, then restarts the stack only if tests pass:

./restart.sh

The current fast test suite covers:

  • frontend profile-question visibility and editability rules with Vitest
  • backend profile-question option parsing, answer normalization/deserialization, select validation, and volunteer flag normalization with pytest

You can also run them individually:

docker compose run --rm frontend npm test
docker compose run --rm backend pytest -q

Frontend Development vs Production

Development Mode (Vite)

docker compose up -d
  • Single entry point on port 8050
  • Nginx gateway routes /api/* to backend and all other traffic to Vite
  • Hot reloading and development features
  • Access at: http://localhost:8050

Production Mode (Nginx)

docker compose --profile prod up -d frontend-prod backend
  • Frontend served by Nginx on port 8050
  • Optimized static files, production-ready
  • Access at: http://localhost:8050

Configuration

Set your preferred defaults in .env:

# Deployment mode (for reference only)
MODE=dev

# Single host entrypoint port
APP_PORT=8050

# HTTPS entrypoint port for self-signed TLS in dev
APP_TLS_PORT=8443
DEV_CERT_CN=localhost
DEV_CERT_SANS=DNS:localhost,IP:127.0.0.1,IP:::1

# Frontend allowed hosts (comma-separated)
VITE_ALLOWED_HOSTS=sasaprod,localhost,members.sasalliance.org

If you access via a LAN hostname or IP, add it to VITE_ALLOWED_HOSTS. If you change APP_PORT, use that port instead of 8050 in URLs. If you change APP_TLS_PORT, use that port for HTTPS URLs. If you change hostnames, update DEV_CERT_CN and DEV_CERT_SANS accordingly.

Stopping Services

# Stop all services
docker compose down

# Stop production profile services
docker compose --profile prod down

Default Credentials

Admin Account:

  • Email: admin@swanseaairport.org
  • Password: admin123

⚠️ IMPORTANT: Change the admin password immediately after first login!

API Endpoints

Authentication

  • POST /api/v1/auth/register - Register new user
  • POST /api/v1/auth/login - Login (OAuth2 form)
  • POST /api/v1/auth/login-json - Login (JSON)

Users

  • GET /api/v1/users/me - Get current user profile
  • PUT /api/v1/users/me - Update current user profile
  • GET /api/v1/users/ - List all users (admin)
  • GET /api/v1/users/{id} - Get user by ID (admin)
  • DELETE /api/v1/users/{id} - Delete user (admin)

Membership Tiers

  • GET /api/v1/tiers/ - List all tiers
  • GET /api/v1/tiers/{id} - Get tier by ID
  • POST /api/v1/tiers/ - Create tier (admin)
  • PUT /api/v1/tiers/{id} - Update tier (admin)
  • DELETE /api/v1/tiers/{id} - Delete tier (admin)

Memberships

  • GET /api/v1/memberships/my-memberships - Get current user's memberships
  • POST /api/v1/memberships/ - Create membership
  • GET /api/v1/memberships/{id} - Get membership by ID
  • PUT /api/v1/memberships/{id} - Update membership (admin)
  • GET /api/v1/memberships/ - List all memberships (admin)
  • DELETE /api/v1/memberships/{id} - Delete membership (admin)

Payments

  • GET /api/v1/payments/my-payments - Get current user's payments
  • POST /api/v1/payments/ - Create payment
  • GET /api/v1/payments/{id} - Get payment by ID
  • PUT /api/v1/payments/{id} - Update payment (admin)
  • GET /api/v1/payments/ - List all payments (admin)
  • POST /api/v1/payments/manual-payment - Record manual payment (admin)
  • GET /api/v1/payments/config/square - Get frontend Square config
  • POST /api/v1/payments/square/process - Process Square card payment
  • POST /api/v1/payments/square/refund - Refund Square payment (admin)

Profile Questions

  • GET /api/v1/users/me/profile-questions - List active questions with current answers
  • PUT /api/v1/users/me/profile-answers - Update editable answers
  • GET /api/v1/users/admin/profile-questions - List all profile questions (admin)
  • POST /api/v1/users/admin/profile-questions - Create profile question (admin)
  • PUT /api/v1/users/admin/profile-questions/{id} - Update profile question (admin)
  • DELETE /api/v1/users/admin/profile-questions/{id} - Deactivate profile question (admin)
  • GET /api/v1/users/admin/users/{id}/profile-answers - View user answers (admin)
  • PUT /api/v1/users/admin/users/{id}/profile-answers - Update user answers (admin)

Events

  • GET /api/v1/events/ - List events
  • GET /api/v1/events/upcoming - List upcoming events
  • POST /api/v1/events/ - Create event (admin)
  • PUT /api/v1/events/{id} - Update event (admin)
  • DELETE /api/v1/events/{id} - Delete event (admin)
  • GET /api/v1/events/{id}/rsvps - List RSVPs (admin)
  • POST /api/v1/events/{id}/rsvp - Create or update current user's RSVP

Email and Feature Flags

  • POST /api/v1/email/test-email - Send test email
  • POST /api/v1/email/test-welcome-email - Send test welcome email
  • POST /api/v1/email/webhooks/smtp2go/bounce - Receive SMTP2GO bounce webhook
  • GET /api/v1/email/bounces - List bounces
  • GET /api/v1/email/bounces/stats - Bounce statistics
  • GET /api/v1/email-templates/ - List templates
  • PUT /api/v1/email-templates/{template_key} - Update template
  • GET /api/v1/feature-flags/flags - List flags
  • POST /api/v1/feature-flags/flags/reload - Reload flags (super admin)

Docker Compose Commands

Basic Operations

# Start all services
docker compose up -d

# View logs (all services)
docker compose logs -f

# View logs (specific service)
docker compose logs -f backend
docker compose logs -f gateway

# Stop services
docker compose down

# Stop and remove volumes (clean slate)
docker compose down -v

# Restart services
docker compose restart

# Rebuild after code changes
docker compose up -d --build

# Check service status
docker compose ps

Database Operations

# Access MySQL CLI (using environment variables)
docker exec -it membership_mysql mysql -u "${DATABASE_USER}" -p"${DATABASE_PASSWORD}" "${DATABASE_NAME}"

# Create backup
docker exec membership_mysql mysqldump -u "${DATABASE_USER}" -p"${DATABASE_PASSWORD}" "${DATABASE_NAME}" > backup_$(date +%Y%m%d_%H%M%S).sql

# Restore database
docker exec -i membership_mysql mysql -u "${DATABASE_USER}" -p"${DATABASE_PASSWORD}" "${DATABASE_NAME}" < backup.sql

Database Migrations

The application uses Alembic for database schema migrations. Migrations are automatically run when the backend container starts.

# Create a new migration (after making model changes)
sudo docker compose exec backend alembic revision --autogenerate -m "Description of changes"

# Apply migrations
sudo docker compose exec backend alembic upgrade head

# View migration status
sudo docker compose exec backend alembic current

# View migration history
sudo docker compose exec backend alembic history

Note: The database/init.sql file is deprecated. All schema changes should now be made through Alembic migrations.

API Testing

You can use the interactive API documentation at http://localhost:8050/docs to test endpoints:

  1. Register a new user
  2. Login to get access token
  3. Click "Authorize" button and enter: Bearer <your_token>
  4. Test protected endpoints

Or use curl:

# Register
curl -X POST "http://localhost:8050/api/v1/auth/register" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "password123",
    "first_name": "John",
    "last_name": "Doe"
  }'

# Login
curl -X POST "http://localhost:8050/api/v1/auth/login-json" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "password123"
  }'

# Get profile (replace TOKEN with actual token)
curl -X GET "http://localhost:8050/api/v1/users/me" \
  -H "Authorization: Bearer TOKEN"

Default Membership Tiers

The system comes with three pre-configured tiers:

  1. Personal - £5/year

    • Access to member portal
    • Meeting notifications
    • Event participation
  2. Aircraft Owners - £25/year

    • All Personal benefits
    • Priority event registration
    • Aircraft owner resources
  3. Corporate - £100/year

    • All benefits
    • Corporate recognition
    • Promotional opportunities
    • File access

Security

  • Passwords are hashed using bcrypt
  • JWT tokens for authentication
  • Role-based access control (Member, Admin, Super Admin)
  • CORS protection
  • Environment-based configuration

Troubleshooting

Services not starting

# Check status of all services
docker compose ps

# View all logs
docker compose logs

# View specific service logs
docker compose logs gateway
docker compose logs backend

# Restart all services
docker compose restart

# Full restart with rebuild
docker compose down
docker compose up -d --build

Database connection issues

# Check backend connectivity and status
docker compose ps

# View backend logs for DB errors
docker compose logs backend

Clean slate restart

# Stop everything and remove volumes
docker compose down -v

# Start fresh
docker compose up -d

# Wait for initialization
docker compose logs -f

Remaining Roadmap

  • Add member file upload/repository endpoints and UI
  • Add richer volunteer role, assignment, schedule, and certificate screens on top of the existing models
  • Implement automated renewal reminder batch jobs
  • Add reporting and analytics
  • Expand test coverage around authenticated API flows and payment/email service boundaries

License

Copyright © 2024 Swansea Airport Stakeholders' Alliance

Support

For issues or questions, please contact the development team.

S
Description
No description provided
Readme 460 KiB
Languages
TypeScript 56%
Python 40.2%
CSS 2.8%
Dockerfile 0.4%
Mako 0.2%
Other 0.3%