Files
kmtnflower/README.md
T
2026-06-18 04:31:37 +00:00

9.9 KiB

KMountain Flower Radio Station

A three-tier web application for a community radio station: Angular 21 frontend, FastAPI backend, PostgreSQL database.

Renders a hero page, about page, broadcast schedule, donation tiers, upcoming events, and a contact form — styled with a warm mountain/nature aesthetic.

Quick Start

# Start all services
docker compose up --build

# Seed the database (first run only)
docker compose exec api python seed.py

Open http://localhost:4200.

Option B — Manual (frontend + backend separately)

# Database
createdb kmountain
export KMTN_DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/kmountain

# Backend
cd backend && pip install -r requirements.txt
uvicorn app.main:app --reload

# Frontend (new terminal)
npm install && ng serve

Open http://localhost:4200 and ensure the backend is running on http://localhost:8000.

Prerequisites

Requirement Version Notes
Docker + Docker Compose 24+ For the Docker Compose path
Node.js 20+ For manual frontend development
npm 11+
Python 3.12+ For manual backend development
PostgreSQL 16+ For manual backend development (Docker handles it)

Architecture

                    ┌──────────────┐
                    │    Browser   │
                    │   :4200 / :80│
                    └──────┬───────┘
                           │
              ┌────────────┴────────────┐
              │                         │
         ┌────▼─────┐            ┌──────▼─────┐
         │  Nginx   │   /api/*   │  FastAPI   │
         │ (static) │─ proxy ──▶ │  :8000     │
         └────┬─────┘            └──────┬─────┘
              │                          │
         ┌────▼─────┐            ┌──────▼─────┐
         │ Angular 21│            │ PostgreSQL │
         │    SPA    │            │   :5432    │
         └──────────┘            └────────────┘

Three tiers:

  1. Frontend — Angular 21 SPA built via multi-stage Dockerfile and served by Nginx. In production, Nginx serves the static files and proxies /api/* requests to the backend. In development, both run on separate ports and the browser talks directly to both.
  2. Backend — Python FastAPI with async SQLAlchemy. Provides CRUD REST endpoints for programs (broadcast schedule), events (upcoming events), and donation tiers. Auto-generates Swagger/OpenAPI docs at /docs.
  3. Database — PostgreSQL 16. Schema contains three tables: programs, events, donation_tiers. Initial data is loaded via seed.py.

Project Structure

.
├── docker-compose.yml          # 3-service stack (db, api, frontend)
├── Dockerfile                  # Multi-stage: Angular build → Nginx serve
├── nginx.conf                  # Static files + /api/* proxy
├── .env.example                # Environment variable template
├── .devcontainer/              # VS Code dev container
│
├── src/                        # Angular 21 frontend
│   ├── app/                    # Standalone components
│   │   ├── app.routes.ts       # Lazy-loaded route map
│   │   ├── hero/ about/ schedule/ donate/ events/ contact/ navbar/ footer/
│   │   ├── services/           # HTTP services (program, event, tier)
│   │   └── interfaces/         # TypeScript types (Program, Event, Tier)
│   ├── environments/           # dev/prod config (apiBaseUrl)
│   └── styles/                 # SCSS design tokens
│       ├── _variables.scss     # Colors, spacing, breakpoints
│       ├── _mixins.scss        # Card, button, responsive mixins
│       └── _themes.scss        # SCSS → CSS custom properties
│
└── backend/                    # FastAPI backend
    ├── Dockerfile              # Python gunicorn/uvicorn
    ├── requirements.txt
    ├── seed.py                 # Initial data for all models
    └── app/
        ├── main.py             # FastAPI app, CORS, router registration
        ├── config.py           # ENV-based settings (KMTN_* prefix)
        ├── database.py         # async engine + session factory
        ├── models.py           # SQLAlchemy ORM (Program, Event, DonationTier)
        ├── schemas.py          # Pydantic schemas (Create/Update/Response)
        └── api/
            ├── programs.py     # CRUD /api/programs
            ├── events.py       # CRUD /api/events
            └── tiers.py        # CRUD /api/tiers

Local Development

Docker Compose

docker compose up --build            # Start all services
docker compose exec api python seed.py # Seed database (first run)
docker compose logs -f api           # Stream backend logs
docker compose down                  # Stop and remove containers

The pgdata volume persists the database across container restarts.

Manual Development

Run all three layers in parallel:

# 1. Database (install PostgreSQL 16 locally)
createdb kmountain

# 2. Backend (new terminal)
cd backend
pip install -r requirements.txt
export KMTN_DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/kmountain
export KMTN_CORS_ORIGINS='["http://localhost:4200"]'
uvicorn app.main:app --reload

# 3. Frontend (another terminal)
npm install
ng serve

Configuration

Variable Default Where Description
KMTN_DATABASE_URL postgresql+asyncpg://postgres:postgres@localhost:5432/kmountain backend/app/config.py Async PostgreSQL connection string
KMTN_CORS_ORIGINS ["http://localhost:4200"] backend/app/config.py CORS allowlist (JSON array)
apiBaseUrl http://localhost:8000 (dev) / '' (prod) src/environments/ Where the Angular app finds the API

Environment variables are prefixed with KMTN_ in the backend. For production, set KMTN_DATABASE_URL to your managed PostgreSQL connection and update KMTN_CORS_ORIGINS to your actual domain.

Building

# Frontend (produces dist/radio-station/browser/)
ng build --configuration production

# Backend Docker image
docker build -t kmountain-api -f backend/Dockerfile backend/

# Full production stack
docker compose up --build -d

Testing

ng test              # Angular + Vitest

The backend API is self-documented at http://localhost:8000/docs (Swagger UI). Run docker compose exec api python seed.py and visit that URL to interactively test endpoints.

API Reference

The backend exposes CRUD endpoints for three models:

Method Endpoint Description
GET /api/programs List all programs (?day=1..7 to filter by day of week)
GET /api/programs/:id Single program
POST /api/programs Create program
PUT /api/programs/:id Update program
DELETE /api/programs/:id Delete program
GET /api/events List events (?active=true to filter active events)
GET /api/events/:id Single event
POST /api/events Create event
PUT /api/events/:id Update event
DELETE /api/events/:id Delete event
GET /api/tiers List donation tiers (ordered by display_order)
GET /api/tiers/:id Single tier
POST /api/tiers Create tier
PUT /api/tiers/:id Update tier
DELETE /api/tiers/:id Delete tier

Full interactive API docs at http://localhost:8000/docs.

Deployment

Production (Docker Compose on a VPS)

# 1. Clone repo on server
git clone <repo-url> kmountain
cd kmountain

# 2. Edit docker-compose.yml
#    - Change POSTGRES_PASSWORD to a strong value
#    - Update KMTN_CORS_ORIGINS to your domain
#    - Optionally set KMTN_DATABASE_URL to a managed PostgreSQL

# 3. Build and start
docker compose up --build -d

# 4. Seed the database
docker compose exec api python seed.py

Production hardening checklist

  • Change the default POSTGRES_PASSWORD in docker-compose.yml
  • Update KMTN_CORS_ORIGINS to your actual domain (not localhost)
  • Set KMTN_DATABASE_URL to a managed PostgreSQL connection (RDS, Cloud SQL, etc.)
  • Add a reverse proxy (Caddy, Traefik) in front of Nginx for HTTPS
  • Set up log rotation for Docker containers
  • Configure Docker image registry and push/pull workflow

Development Tools

  • Dev container — Open the repo in VS Code → "Reopen in Container" for a pre-configured environment with Angular CLI, Node.js, Python 3, and Git (.devcontainer/).
  • VS Code workspaceworkspace file in the repo root configures both Angular and Python extensions.
  • Prettier — Run npx prettier --write . to format the codebase.
  • Prettier config.prettierrc (100 char width, single quotes, Angular HTML parser).

Tech Stack

Layer Technology
Frontend Angular 21 (standalone components, signals-ready)
Backend FastAPI 0.115, Python 3.12
Database PostgreSQL 16 (async via SQLAlchemy 2.0)
Styling SCSS with design tokens (variables → mixins → CSS custom properties)
Routing Angular Router (lazy loaded) + Nginx SPA fallback
HTTP RxJS observables (frontend → FastAPI)
Containers Docker Compose (3 services: db, api, frontend)
CI/CD (not yet configured)
Testing Vitest (via Angular CLI)