# 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:** 1. Create `web_app/.vscode/` directory with shared workspace settings 2. Create `web_app/.vscode/workspace.code-workspace` listing both roots: ```json { "folders": [ { "path": "." }, { "path": "backend" } ], "settings": {} } ``` 3. VS Code: File → Open Workspace from File → select `workspace.code-workspace` 4. 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 1. Create `.vscode/` directory with `workspace.code-workspace`, `settings.json`, `tasks.json`, `launch.json` 2. Create `backend/.vscode/settings.json` (Python language settings) 3. Open `workspace.code-workspace` in VS Code — both roots visible, each with its own language server 4. `tasks.json` provides 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](src/app/schedule/schedule.component.ts). ### 1.2 Angular service layer Modify: - [src/app/app.config.ts](src/app/app.config.ts) -- add `provideHttpClient()` to providers - [src/environments/environment.ts](src/environments/environment.ts) -- **new**: `apiBaseUrl` for dev/prod Create: - [src/app/interfaces/program.ts](src/app/interfaces/program.ts) -- `Program` interface mirroring backend - [src/app/services/program.service.ts](src/app/services/program.service.ts) -- `getPrograms()`, `getProgram()`, `createProgram()`, etc. ### 1.3 Convert schedule component Modify [src/app/schedule/schedule.component.ts](src/app/schedule/schedule.component.ts): - Remove `readonly programs: Program[]` array - `inject(ProgramService)` in class body - Add `programs: Program[] = []` and `loading = true` - Load data in `ngOnInit()` via service - Template: add loading/empty states, keep `*ngFor` structure ### 1.4 Docker skeleton Create: - [docker-compose.yml](docker-compose.yml) -- db + api services, healthcheck on db, depends_on ordering, named `pgdata` volume - [backend/Dockerfile](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](backend/app/models.py) -- add `Event` and `DonationTier` models - 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)` - [schemas.py](backend/app/schemas.py) -- add Pydantic schemas for both - [api/events.py](backend/app/api/events.py) -- GET/POST/PUT/DELETE with `?active` filter - [api/tiers.py](backend/app/api/tiers.py) -- GET/POST/PUT/DELETE ordered by `display_order` - [seed.py](backend/seed.py) -- add events and tiers data (from [events.component.ts](src/app/events/events.component.ts) and [donate.component.ts](src/app/donate/donate.component.ts)) ### 2.2 Angular additions Create: - [src/app/interfaces/event.ts](src/app/interfaces/event.ts) - [src/app/interfaces/tier.ts](src/app/interfaces/tier.ts) - [src/app/services/event.service.ts](src/app/services/event.service.ts) -- `getEvents()`, `createEvent()`, etc. - [src/app/services/tier.service.ts](src/app/services/tier.service.ts) -- `getTiers()` ordered Modify: - [src/app/events/events.component.ts](src/app/events/events.component.ts) -- remove readonly array, inject EventService, load in ngOnInit - [src/app/donate/donate.component.ts](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 output - `nginx.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: ```yaml 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)