11 KiB
Backend Infrastructure for KMountain Flower Radio Station
Context
The app currently has a polished frontend with zero backend — all dynamic content (schedule, events, donations) lives as hardcoded readonly arrays in components. The contact form just shows an alert. We need to add persistent data, a backend API, and Docker-based deployment while keeping things simple for a volunteer-run community radio station.
VS Code Workspace Setup
Use a multi-root workspace so both projects get their own IDE context, linting, and debugging configs:
web_app/ ← repo root (existing)
├── .vscode/
│ ├── settings.json ← workspace settings (shared)
│ ├── tasks.json ← common tasks (start backend, start frontend)
│ └── launch.json ← debug configs for both projects
├── .vscode/workspace.code-workspace ← multi-root workspace file (open this in VS Code)
├── src/ ← existing Angular frontend (unchanged structure)
├── backend/ ← new FastAPI backend
│ ├── .vscode/
│ │ ├── settings.json ← Python/Flake8/Pylance settings
│ │ └── launch.json ← FastAPI debug config
├── docker-compose.yml
├── Dockerfile ← Angular build + nginx serve (at repo root)
└── nginx.conf ← nginx config (at repo root)
Steps:
- Create
web_app/.vscode/directory with shared workspace settings - Create
web_app/.vscode/workspace.code-workspacelisting both roots:{ "folders": [ { "path": "." }, { "path": "backend" } ], "settings": {} } - VS Code: File → Open Workspace from File → select
workspace.code-workspace - Backend folder gets Python language server; frontend folder gets Angular TS language server — no conflict
Decisions (confirmed)
- Admin panel: Skip for now. Initial data via a seed script.
- Contact form: Leave as-is (alert only, unimplemented for now).
- Rollout: Phase by phase.
- Backend: FastAPI (Python 3 already in devcontainer, auto-docs, async).
- Database: PostgreSQL in Docker (production-ready, any managed host compatible).
- Frontend serve: nginx in Docker (build Angular → serve static).
Target Architecture
docker-compose.yml
├── db (postgres:16-alpine) -- data tier, persistent volume
├── api (FastAPI + uvicorn) -- middleware tier, CORS + all endpoints
└── frontend (nginx) -- frontend tier, Angular build + API proxy in prod
Phase 1: Backend + Schedule Page + Docker Skeleton
1.0 VS Code workspace setup
- Create
.vscode/directory withworkspace.code-workspace,settings.json,tasks.json,launch.json - Create
backend/.vscode/settings.json(Python language settings) - Open
workspace.code-workspacein VS Code — both roots visible, each with its own language server tasks.jsonprovides unified commands: "Start Backend" (uvicorn --reload), "Start Frontend" (ng serve), "Docker Up"
1.1 Backend skeleton
Create backend/ directory:
backend/
├── requirements.txt -- fastapi, uvicorn, psycopg2-binary, alembic, python-multipart
├── Dockerfile -- python:3.12-slim, copy requirements, copy app, CMD uvicorn
├── seed.py -- seed 10 weekday programs
└── app/
├── __init__.py
├── main.py -- FastAPI app, lifespan (DB init), CORS middleware
├── config.py -- DATABASE_URL, CORS_ORIGINS from env vars
├── database.py -- async SessionLocal engine
├── models.py -- Program SQLAlchemy model
├── schemas.py -- Program Pydantic schemas (read + create + update)
└── api/
├── __init__.py
└── programs.py -- GET /api/programs (with ?day filter), POST, PUT, DELETE
Program model: id, day_of_week (int), day_label (str), time (str), title (str), host (str), genre (str)
Seed data: The 10 existing weekday programs from schedule.component.ts:19-29.
1.2 Angular service layer
Modify:
- src/app/app.config.ts -- add
provideHttpClient()to providers - src/environments/environment.ts -- new:
apiBaseUrlfor dev/prod
Create:
- src/app/interfaces/program.ts --
Programinterface mirroring backend - src/app/services/program.service.ts --
getPrograms(),getProgram(),createProgram(), etc.
1.3 Convert schedule component
Modify src/app/schedule/schedule.component.ts:
- Remove
readonly programs: Program[]array inject(ProgramService)in class body- Add
programs: Program[] = []andloading = true - Load data in
ngOnInit()via service - Template: add loading/empty states, keep
*ngForstructure
1.4 Docker skeleton
Create:
- docker-compose.yml -- db + api services, healthcheck on db, depends_on ordering, named
pgdatavolume - backend/Dockerfile -- already covered in 1.1
Phase 1 verification
| Check | How |
|---|---|
| Backend runs locally | cd backend && uvicorn app.main:app --reload |
OpenAPI docs at /docs |
Browse http://localhost:8000/docs |
| Seed data present | curl http://localhost:8000/api/programs returns 10 items |
| Schedule page fetches from DB | DevTools Network tab shows GET to /api/programs, page renders |
| Docker stack | docker compose up -- db + api running, schedule renders on frontend |
Phase 2: Donate + Events Pages
2.1 Backend additions
Modify backend/app/:
- models.py -- add
EventandDonationTiermodels- Event:
id, date (DATE), title, description (TEXT), location, icon, rsvp_url (nullable), active (bool) - DonationTier:
id, name (UNIQUE), amount (NUMERIC), icon, benefits (TEXT[]), display_order (int)
- Event:
- schemas.py -- add Pydantic schemas for both
- api/events.py -- GET/POST/PUT/DELETE with
?activefilter - api/tiers.py -- GET/POST/PUT/DELETE ordered by
display_order - seed.py -- add events and tiers data (from events.component.ts and donate.component.ts)
2.2 Angular additions
Create:
- src/app/interfaces/event.ts
- src/app/interfaces/tier.ts
- src/app/services/event.service.ts --
getEvents(),createEvent(), etc. - src/app/services/tier.service.ts --
getTiers()ordered
Modify:
- src/app/events/events.component.ts -- remove readonly array, inject EventService, load in ngOnInit
- src/app/donate/donate.component.ts -- remove readonly array, inject TierService, load in ngOnInit
- Keep template structure identical, just swap the data source
Phase 2 verification
| Check | How |
|---|---|
| Events API | curl http://localhost:8000/api/events?active=true returns 4 events |
| Tiers API | curl http://localhost:8000/api/tiers returns 4 tiers ordered |
| Events page renders from DB | Navigate to /events, verify from DB not hardcoded |
| Donate page renders from DB | Navigate to /donate, verify from DB not hardcoded |
Phase 3: Frontend Docker + Full Stack
3.1 Dockerfile + nginx config
Create at repo root alongside src/ and backend/:
Dockerfile-- multi-stage: node:20-alpine build Angular → nginx:alpine serve the dist outputnginx.conf-- serve Angular static files; in production mode, proxy/api/*to api service (avoids CORS in prod)
3.2 Update docker-compose.yml
Add frontend service:
frontend:
build:
context: .
dockerfile: Dockerfile
ports:
- "4200:80"
depends_on:
- api
Phase 3 verification
| Check | How |
|---|---|
| Full stack up | docker compose up --build -- 3 containers, all healthy |
| Frontend accessible | Browse http://localhost:4200 -- all pages load |
| All data pages dynamic | schedule, donate, events all render from DB |
| Data persists | docker compose down && docker compose up -- data still present |
Files to Create (new)
| File | Purpose |
|---|---|
.vscode/workspace.code-workspace |
Multi-root workspace (frontend + backend) |
.vscode/settings.json |
Shared workspace settings |
.vscode/tasks.json |
Common tasks (start backend, start frontend, docker up) |
.vscode/launch.json |
Debug configs for both projects |
backend/.vscode/settings.json |
Python-specific VS Code settings |
backend/.vscode/launch.json |
FastAPI debug config |
backend/requirements.txt |
Python dependencies |
backend/Dockerfile |
API container image |
backend/seed.py |
Initial station data |
backend/app/main.py |
FastAPI app entry point |
backend/app/config.py |
Env-based config |
backend/app/database.py |
async session engine |
backend/app/models.py |
SQLAlchemy ORM models |
backend/app/schemas.py |
Pydantic schemas |
backend/app/api/programs.py |
Programs CRUD endpoints |
backend/app/api/events.py |
Events CRUD endpoints |
backend/app/api/tiers.py |
Tiers CRUD endpoints |
src/app/interfaces/program.ts |
Program TS type |
src/app/interfaces/event.ts |
Event TS type |
src/app/interfaces/tier.ts |
Tier TS type |
src/app/services/program.service.ts |
Program HTTP service |
src/app/services/event.service.ts |
Event HTTP service |
src/app/services/tier.service.ts |
Tier HTTP service |
src/environments/environment.ts |
Dev/prod API URL |
docker-compose.yml |
3-service compose |
Dockerfile |
Angular build + nginx serve (at repo root) |
nginx.conf |
nginx config with API proxy (at repo root) |
Files to Modify
| File | Change |
|---|---|
src/app/app.config.ts |
Add provideHttpClient() |
src/app/schedule/schedule.component.ts |
Remove readonly array, inject service |
src/app/events/events.component.ts |
Same pattern |
src/app/donate/donate.component.ts |
Same pattern |
docker-compose.yml |
Created in Phase 1, extended in Phase 3 |
Not In Scope (for now)
- Admin panel (mentioned as Phase 5 in analysis — will be a future addition)
- Contact form implementation (left as alert per user decision)
- Streaming status endpoint (can add later via same pattern)