updated 3 tier structure
This commit is contained in:
@@ -1,132 +1,250 @@
|
||||
# RadioStation — KMountain Flower
|
||||
# KMountain Flower Radio Station
|
||||
|
||||
A static Angular boilerplate for a community radio station website. The app showcases a broadcast schedule, upcoming events, donation tiers, an about page, and a contact form — all styled with a warm mountain/nature aesthetic.
|
||||
A three-tier web application for a community radio station: Angular 21 frontend, FastAPI backend, PostgreSQL database.
|
||||
|
||||
## Architecture
|
||||
Renders a hero page, about page, broadcast schedule, donation tiers, upcoming events, and a contact form — styled with a warm mountain/nature aesthetic.
|
||||
|
||||
```
|
||||
src/
|
||||
├── app/ # Angular application root
|
||||
│ ├── app.ts # Root <app-root> component (shell layout)
|
||||
│ ├── app.config.ts # Application config: providers + router
|
||||
│ ├── app.html # Shell template: navbar + <router-outlet> + footer
|
||||
│ ├── app.routes.ts # Route definitions (lazy-loaded components)
|
||||
│ ├── app.scss # Root component styles
|
||||
│ ├── hero/ # Landing page (home route)
|
||||
│ ├── about/ # About the station page
|
||||
│ ├── schedule/ # Program schedule (data-driven table)
|
||||
│ ├── donate/ # Donation tiers (data-driven cards)
|
||||
│ ├── events/ # Upcoming events (data-driven cards)
|
||||
│ ├── contact/ # Contact form (two-way binding via FormsModule)
|
||||
│ ├── navbar/ # Top navigation bar (responsive hamburger menu)
|
||||
│ └── footer/ # Site footer
|
||||
├── styles/ # Global SCSS design tokens
|
||||
│ ├── _variables.scss # Color palette, spacing, breakpoints, z-index scale
|
||||
│ ├── _mixins.scss # Reusable SCSS mixins (cards, buttons, responsiveness)
|
||||
│ ├── _themes.scss # Maps SCSS vars → CSS custom properties on :root
|
||||
│ └── index.scss # Global entry: reset + utility classes + theme import
|
||||
├── assets/
|
||||
│ └── svg/ # Decorative SVGs (mountain dividers, floral accents)
|
||||
├── main.ts # App bootstrap entry point
|
||||
└── index.html # HTML shell (<app-root> mount point)
|
||||
```
|
||||
## Quick Start
|
||||
|
||||
### Key architectural decisions
|
||||
|
||||
- **Standalone components** — Every component is standalone (no NgModules). This is Angular 21's default and keeps imports explicit.
|
||||
- **Lazy-loaded routes** — Each page is code-splitted via `loadComponent()` in [app.routes.ts](src/app/app.routes.ts). The router imports each component on first navigation.
|
||||
- **Data-driven pages** — `ScheduleComponent`, `DonateComponent`, and `EventsComponent` all hold their content as readonly arrays (`readonly programs: Program[]`, etc.). To update content, edit these arrays in the component TypeScript files.
|
||||
- **Design tokens in SCSS** — All colors, spacing, breakpoints, and typography live in [src/styles/_variables.scss](src/styles/_variables.scss). Change these once and every component inherits the new values via [_themes.scss](src/styles/_themes.scss) (which exposes them as CSS custom properties) and the mixins in [_mixins.scss](src/styles/_mixins.scss).
|
||||
- **SCSS preprocessor paths** — [angular.json](angular.json) adds `src/styles/` to the include path, so any component can `@use 'variables'` without a relative path.
|
||||
|
||||
## Pages
|
||||
|
||||
| Route | Component | Description |
|
||||
| -------- | --------------- | -------------------------------------------- |
|
||||
| `/` | HeroComponent | Hero landing section |
|
||||
| `/about` | AboutComponent | Station mission & info |
|
||||
| `/schedule` | ScheduleComponent | Program schedule, rendered from `programs[]` |
|
||||
| `/donate` | DonateComponent | Donation tiers, rendered from `tiers[]` |
|
||||
| `/events` | EventsComponent | Upcoming events, rendered from `upcomingEvents[]` |
|
||||
| `/contact` | ContactComponent | Contact form with submission handler |
|
||||
|
||||
## Customization guide
|
||||
|
||||
### Re-skinning the color palette
|
||||
1. Edit the color variables in [src/styles/_variables.scss](src/styles/_variables.scss). The primary palette (blue) and accent palette (orange) control the entire site.
|
||||
2. That's it — [_themes.scss](src/styles/_themes.scss) automatically maps them to CSS custom properties used by every component.
|
||||
|
||||
### Changing typography
|
||||
Edit `$font-primary`, `$font-heading`, and `$font-mono` in [src/styles/_variables.scss](src/styles/_variables.scss).
|
||||
|
||||
### Adding a new page
|
||||
1. Create a new folder under `src/app/` with a `*.component.ts`, `*.component.html`, and `*.component.scss`.
|
||||
2. Export a `@Component` decorated class.
|
||||
3. Add a route in [app.routes.ts](src/app/app.routes.ts) using `loadComponent()` to lazy-load it.
|
||||
4. (Optional) Add a `RouterLink` in [navbar.component.html](src/app/navbar/navbar.component.html).
|
||||
|
||||
### Updating schedule / events / donation content
|
||||
Edit the `readonly` arrays directly in their respective component files:
|
||||
- [schedule.component.ts](src/app/schedule/schedule.component.ts) — `programs`
|
||||
- [events.component.ts](src/app/events/events.component.ts) — `upcomingEvents`
|
||||
- [donate.component.ts](src/app/donate/donate.component.ts) — `tiers`
|
||||
|
||||
Each interface (`Program`, `Event`, `Tier`) is defined in the component file. Modify the interfaces and data together.
|
||||
|
||||
## Getting started
|
||||
|
||||
### Prerequisites
|
||||
- Node.js 20+ (or use the dev container)
|
||||
- npm 11+
|
||||
|
||||
### Quick start
|
||||
### Option A — Docker Compose (recommended)
|
||||
|
||||
```bash
|
||||
npm install
|
||||
ng serve
|
||||
# Start all services
|
||||
docker compose up --build
|
||||
|
||||
# Seed the database (first run only)
|
||||
docker compose exec api python seed.py
|
||||
```
|
||||
|
||||
Open [http://localhost:4200](http://localhost:4200).
|
||||
|
||||
### Development server
|
||||
### Option B — Manual (frontend + backend separately)
|
||||
|
||||
```bash
|
||||
ng serve # Start dev server (hot reload enabled)
|
||||
ng serve --port 8080 # Custom port
|
||||
# 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
|
||||
```
|
||||
|
||||
### Building
|
||||
Open [http://localhost:4200](http://localhost:4200) and ensure the backend is running on [http://localhost:8000](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](backend/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
|
||||
|
||||
```bash
|
||||
ng build # Production build → dist/
|
||||
ng build --configuration development # With source maps
|
||||
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
|
||||
```
|
||||
|
||||
### Code style
|
||||
The `pgdata` volume persists the database across container restarts.
|
||||
|
||||
This project uses [Prettier](https://prettier.io/) (configured in [.prettierrc](.prettierrc)). Run:
|
||||
### Manual Development
|
||||
|
||||
Run all three layers in parallel:
|
||||
|
||||
```bash
|
||||
npx prettier --write .
|
||||
# 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
|
||||
```
|
||||
|
||||
### Testing
|
||||
## Configuration
|
||||
|
||||
| Variable | Default | Where | Description |
|
||||
|---|---|---|---|
|
||||
| `KMTN_DATABASE_URL` | `postgresql+asyncpg://postgres:postgres@localhost:5432/kmountain` | [backend/app/config.py](backend/app/config.py) | Async PostgreSQL connection string |
|
||||
| `KMTN_CORS_ORIGINS` | `["http://localhost:4200"]` | [backend/app/config.py](backend/app/config.py) | CORS allowlist (JSON array) |
|
||||
| `apiBaseUrl` | `http://localhost:8000` (dev) / `''` (prod) | [src/environments/](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
|
||||
|
||||
```bash
|
||||
ng test # Run unit tests (Vitest)
|
||||
# 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
|
||||
```
|
||||
|
||||
## Dev container
|
||||
## Testing
|
||||
|
||||
This project ships with a [.devcontainer/](.devcontainer/) for VS Code. Open the repo in VS Code → "Reopen in Container" to get a pre-configured environment with Angular CLI, Node.js, Python 3, and Git.
|
||||
```bash
|
||||
ng test # Angular + Vitest
|
||||
```
|
||||
|
||||
## Project tech stack
|
||||
The backend API is self-documented at [http://localhost:8000/docs](http://localhost:8000/docs) (Swagger UI). Run `docker compose exec api python seed.py` and visit that URL to interactively test endpoints.
|
||||
|
||||
- **Framework:** Angular 21 (standalone components, signals-ready)
|
||||
- **Language:** TypeScript 5.9
|
||||
- **Styling:** SCSS with design tokens (variables → mixins → CSS custom properties)
|
||||
- **Routing:** Angular Router with lazy loading
|
||||
- **Form handling:** FormsModule (two-way binding)
|
||||
- **Linting/formatting:** Prettier
|
||||
- **Testing:** Vitest (via Angular CLI)
|
||||
- **Package manager:** npm 11.11
|
||||
## 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](http://localhost:8000/docs).
|
||||
|
||||
## Deployment
|
||||
|
||||
### Production (Docker Compose on a VPS)
|
||||
|
||||
```bash
|
||||
# 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](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/](.devcontainer/)).
|
||||
- **VS Code workspace** — [workspace file](web_app.code-workspace) in the repo root configures both Angular and Python extensions.
|
||||
- **Prettier** — Run `npx prettier --write .` to format the codebase.
|
||||
- **Prettier config** — [**.prettierrc**](.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) |
|
||||
|
||||
Reference in New Issue
Block a user