feat: Add Supabase configuration and migrations for MC Cars application

- Create Kong declarative configuration for routing and authentication.
- Implement initialization script to set up the database.
- Add SQL migration for initializing roles, schemas, and seeding vehicle data.
- Create leads and customers tables with appropriate policies and functions for CRM.
- Seed admin user and configure storage bucket with RLS policies.
This commit is contained in:
Lago
2026-04-17 17:50:57 +02:00
commit 61517879e1
23 changed files with 3673 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
# MC Cars Dockerized Supabase CRM
Self-hosted Supabase stack + bilingual (DE/EN) public website + lead-management admin panel. Everything lives under this folder. Copying the folder to another machine and running `docker compose up -d` reproduces the stack bit-for-bit — all runtime state is under `./data/` bind mounts, no named volumes.
## What's inside
| Service | Image | Purpose |
| ------------- | ------------------------------------ | ----------------------------------------- |
| `db` | `postgres:15-alpine` | Postgres with `wal_level=logical` |
| `auth` | `supabase/gotrue:v2.158.1` | Email+password auth (signup disabled) |
| `rest` | `postgrest/postgrest:v12.2.0` | Auto-generated REST API |
| `storage` | `supabase/storage-api:v1.11.13` | S3-like bucket API (backed by `./data/storage`) |
| `imgproxy` | `darthsim/imgproxy:v3.8.0` | On-the-fly image transforms |
| `realtime` | `supabase/realtime:v2.30.23` | Live `postgres_changes` subscriptions |
| `meta` | `supabase/postgres-meta:v0.84.2` | Schema introspection for Studio |
| `post-init` | `postgres:15-alpine` | Idempotent bootstrap: seed admin + migrations |
| `kong` | `kong:2.8.1` | Single API gateway at `:54321` |
| `studio` | `supabase/studio` | Supabase dashboard (`:3000`) |
| `web` | local `nginx:alpine` build | Public site + admin panel (`:8080`) |
## Requirements
- Docker Desktop / Docker Engine with Compose v2
- Free ports: `3000`, `5432`, `8080`, `54321`, `54443`
## Run
```powershell
cd 'c:\Coding\MC Cars GmbH'
docker compose up -d
```
First boot pulls ~1.5 GB of images and runs migrations (`01-init.sql`, `post-boot.sql`, `02-leads.sql`). Give it 3060 s to settle.
### Stop / reset
```powershell
docker compose down # stop, keep data
docker compose down -v # stop + delete named volumes (there are none anymore)
Remove-Item -Recurse -Force .\data # FULL wipe (needed to re-run first-boot migrations)
```
## URLs
| Purpose | URL |
| ------------------------------- | -------------------------------- |
| Public website | http://localhost:8080 |
| Admin panel | http://localhost:8080/admin.html |
| Supabase Studio | http://localhost:3000 |
| API gateway (Kong) | http://localhost:54321 |
| Postgres | `localhost:5432` |
> Admin access is deliberately **not** linked from the public site. Bookmark it.
## Credentials (dev defaults rotate before any deployment)
| Account | Value |
| -------------------- | ---------------------------------------- |
| Admin bootstrap user | `admin@mccars.local` / `mc-cars-admin` |
| Postgres superuser | `postgres` / see `POSTGRES_PASSWORD` |
The admin is seeded with `must_change_password = true` in `raw_user_meta_data`. On first login the UI **forces** a rotation and refuses to reuse the bootstrap password. The real working password never equals `.env`.
## Data model
- `public.vehicles` — fleet, public-readable where `is_active`.
- `public.leads` — booking form submissions. `anon` may `INSERT` only; `authenticated` has full CRUD. Status: `new | qualified | disqualified`.
- `public.customers` — created **only** by qualifying a lead. Hard FK `lead_id` preserves the audit link to the originating lead.
- RPCs: `qualify_lead(uuid, text)`, `disqualify_lead(uuid, text)`, `reopen_lead(uuid)` — transactional, `SECURITY INVOKER`, `authenticated` only.
- Realtime: `supabase_realtime` publication broadcasts inserts/updates on leads, customers, vehicles.
## Portability
Runtime state under `./data/`:
```
data/
├── db/ # Postgres cluster (bind mount)
└── storage/ # vehicle-photos bucket content
```
Everything else (config, migrations, frontend) is in the repo. Zip the folder, scp it, `docker compose up -d` — you have the same stack.
## Project layout
```
MC Cars/
├── docker-compose.yml # full stack, bind-mount portability
├── .env # dev secrets / tunables
├── data/ # runtime state (git-ignored)
├── supabase/
│ ├── kong.yml # gateway routes (/auth, /rest, /realtime, /storage, /pg)
│ └── migrations/
│ ├── 00-run-init.sh # creates supabase service roles
│ ├── 01-init.sql # vehicles + bucket + seed cars
│ ├── post-boot.sql # admin user (must_change_password) + bucket row
│ └── 02-leads.sql # leads, customers, RPCs, realtime publication
├── frontend/
│ ├── Dockerfile # nginx + runtime anon-key injection
│ ├── nginx.conf
│ ├── index.html # public DE/EN site, booking form -> leads
│ ├── admin.html # auth-gated CRM
│ ├── app.js
│ ├── admin.js # realtime + qualify/disqualify + password change
│ ├── config.js # anon-only runtime config
│ ├── i18n.js
│ ├── styles.css
│ ├── impressum.html
│ └── datenschutz.html
├── AGENT.md # findings, conventions, traps
└── ARQUITECTURE.md # architecture deep-dive
```
See [AGENT.md](AGENT.md) and [ARQUITECTURE.md](ARQUITECTURE.md) for everything deeper.