# BilHej / Bilhälsning.se Send a physical letter to a Swedish car owner — just by knowing their license plate. The user enters a registration number, composes a letter (from a template or free text), pays, and BilHej handles the rest: owner address lookup via Transportstyrelsen, printing and mailing via PostNord. The sender never sees the recipient's name or address. --- ## Tech Stack | Layer | Technology | |-------------|-----------------------------------------| | Frontend | Vue.js 3 (Composition API), Vite, Pinia | | Backend | Java 21, Spring Boot 4, Gradle | | Database | PostgreSQL 16 | | Auth | Spring Security + JWT | | Payments | Stripe (cards + Swish) | | Deployment | Docker, Docker Compose | --- ## Prerequisites - Docker & Docker Compose - Java 21 (for local IDE development) - Node.js 20+ (for local frontend dev) - A [Stripe](https://stripe.com) account (test mode for development) --- ## Quick Start ```bash git clone bilhej cd bilhej cp .env.example .env # fill in your keys docker compose up -d # or: ./gradlew up ``` The app will be available at: - Frontend: `http://localhost:3000` - Backend API: `http://localhost:8080` - PostgreSQL: `localhost:5432` ### Architecture inside Docker Compose ``` Browser Docker Compose network ─────── ───────────────────── │ ┌──────────────────┐ │ http://localhost:3000 │ frontend (Vite) │ ├────────────────────────→│ :3000 │ │ │ proxy: /api → │ │ GET /api/orders │ backend:8080 │ │ └────────┬─────────┘ │ │ │ ┌────────▼─────────┐ │ │ backend (Spring) │ │ │ :8080 │ │ │ profile: docker │ │ └────────┬─────────┘ │ │ │ ┌────────▼─────────┐ │ │ postgres (16) │ │ │ :5432 │ │ └──────────────────┘ ``` **Vite proxy:** The Vite dev server proxies `/api/*` requests to the backend container. No CORS configuration needed in development — the browser never calls the backend directly. **Spring profiles:** | Profile | Datasource | Use | |---------|-----------|-----| | default | H2 in-memory | Local IDE dev (`./gradlew :backend:bootRun`) | | `docker` | PostgreSQL via `docker-compose.yml` | Docker Compose dev | | `prod` | PostgreSQL (production config) | Deploy (`docker-compose.prod.yml`) | --- ## Environment Variables Copy `.env.example` to `.env` and fill in: | Variable | Description | |---------------------------|--------------------------------------| | `POSTGRES_DB` | Database name (default: `bilhej`) | | `POSTGRES_USER` | Database user | | `POSTGRES_PASSWORD` | Database password | | `JWT_SECRET` | Secret key for JWT signing | | `STRIPE_SECRET_KEY` | Stripe secret key | | `STRIPE_WEBHOOK_SECRET` | Stripe webhook signing secret | | `STRIPE_PRICE_ID` | Stripe price ID for single letter | --- ## Project Structure ``` bilhej/ ├── frontend/ # Vue.js 3 SPA │ ├── src/ │ │ ├── components/ # Reusable UI components │ │ ├── composables/ # Shared composition functions │ │ ├── layouts/ # Page layouts │ │ ├── pages/ # Route-level page components │ │ ├── router/ # Vue Router config │ │ ├── stores/ # Pinia stores │ │ ├── api/ # API client and endpoints │ │ ├── assets/ # Static assets, CSS │ │ ├── App.vue │ │ └── main.ts │ ├── index.html │ ├── vite.config.ts │ └── package.json ├── backend/ # Spring Boot 4 │ ├── src/main/java/se/bilhalsning/ │ │ ├── BilHejApplication.java │ │ ├── config/ # Security, CORS, Stripe config │ │ ├── controller/ # REST controllers │ │ ├── dto/ # Data transfer objects │ │ ├── entity/ # JPA entities │ │ ├── repository/ # Spring Data repositories │ │ ├── service/ # Business logic │ │ └── security/ # JWT filter, user details │ └── src/main/resources/ │ ├── application.yml # default profile (H2) │ ├── application-docker.yml # docker profile (PostgreSQL) │ └── db/migration/ # Flyway migrations ├── docker-compose.yml # dev: postgres + backend (bootRun) + frontend (Vite HMR) ├── docker-compose.prod.yml # prod: multi-stage builds, no source mounts, restart: unless-stopped ├── docker/ │ ├── backend.Dockerfile # dev: JDK + gradle :backend:bootRun │ ├── backend.prod.Dockerfile # prod: multi-stage (Gradle → JRE Alpine, non-root) │ ├── frontend.Dockerfile # dev: Node + vite dev server │ ├── frontend.prod.Dockerfile # prod: multi-stage (Node → nginx) │ ├── nginx.conf # prod: SPA fallback + /api proxy │ └── entrypoint.sh # prod: self-signed cert generation ├── gradlew # Gradle wrapper (run from repo root) ├── gradle/ │ └── wrapper/ ├── settings.gradle # rootProject.name + include 'backend' ├── build.gradle # convenience tasks: check, up, down, reset ├── .env.example ├── README.md ├── REQUIREMENTS.md └── CODING_GUIDELINES.md ``` --- ## Development vs Production | Aspect | `docker compose up -d` | `docker compose -f docker-compose.prod.yml up -d` | |--------|------------------------|---------------------------------------------------| | Backend | `./gradlew :backend:bootRun` (compiles on change) | Multi-stage build → `java -jar app.jar` | | Backend image | `eclipse-temurin:21-jdk` (~400 MB) | `eclipse-temurin:21-jre-alpine` (~200 MB) | | Backend user | root | `bilhej` (non-root) | | Frontend | Vite dev server (HMR, `--host 0.0.0.0`) | nginx serving static `dist/` | | API proxy | Vite built-in proxy (`/api` → `backend:8080`) | nginx `proxy_pass` | | SSL | None | Self-signed cert auto-generated on first start (`.certs/` volume) | | Source mounts | Yes (live edit) | No (files baked into image) | | Restart policy | Manual | `unless-stopped` | | Purpose | Write code, instant feedback | Verify production build | --- ## Development ### All-in-one (from repo root) ```bash ./gradlew check # lint → frontend test → backend test → integration test ./gradlew up # docker compose up -d ./gradlew down # docker compose down ./gradlew reset # docker compose down -v && docker compose up -d (full DB reset) ``` ### Frontend (dev server with HMR) ```bash cd frontend npm install # first time only npm run dev # :3000 with HMR ``` ### Backend (IDE or CLI) ```bash ./gradlew :backend:bootRun # :8080, profile: default (H2) ``` ### Stripe Webhooks (local testing) ```bash stripe listen --forward-to localhost:8080/api/webhooks/stripe ``` ### Database reset ```bash ./gradlew reset # wipes DB volume and restarts containers ``` --- ## Related Documents - [REQUIREMENTS.md](./REQUIREMENTS.md) — Full product requirements and business model - [CODING_GUIDELINES.md](./CODING_GUIDELINES.md) — Code conventions and standards