working 3 tier approach

This commit is contained in:
2026-06-11 22:34:55 -07:00
parent 4482a30793
commit e5fef8b181
47 changed files with 1288 additions and 200 deletions
+243
View File
@@ -0,0 +1,243 @@
# 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)