Files
mc_cars_gmbh_infraestructure/README.md
T

131 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MC Cars Dockerized Supabase CRM
Self-hosted Supabase stack + bilingual (DE/EN) public website + lead-management admin panel. Designed for Portainer deployment — no `build:` steps, all services use pre-built images with bind mounts. The host deployment root is `/mnt/user/appdata/mc-cars`.
## 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 `:55521` |
| `studio` | `supabase/studio` | Supabase dashboard (`:55530`) |
| `web` | `nginx:1.27-alpine` | Public site + admin panel (`:55580`) |
## Requirements
- Docker Engine with Compose v2 (or Portainer with Stacks)
- Free ports: `55521`, `55530`, `55532`, `55543`, `55580`
## Run
### Via Portainer (recommended)
1. Clone the repo onto the host: `git clone <repo> /mnt/user/appdata/mc-cars`
2. `chmod +x /mnt/user/appdata/mc-cars/frontend/99-config.sh /mnt/user/appdata/mc-cars/supabase/migrations/00-run-init.sh`
3. `mkdir -p /mnt/user/appdata/mc-cars/data/{db,storage}`
4. Portainer → Stacks → Add stack → paste `docker-compose.yml` → paste `.env` into Environment variables → Deploy.
### Via CLI
```bash
cd /mnt/user/appdata/mc-cars
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
```bash
docker compose down # stop, keep data
rm -rf /mnt/user/appdata/mc-cars/data/db # FULL DB wipe (re-runs first-boot migrations)
```
## URLs
| Purpose | URL |
| ------------------------------- | --------------------------------- |
| Public website | http://\<host\>:55580 |
| Admin panel | http://\<host\>:55580/admin.html |
| Supabase Studio | http://\<host\>:55530 |
| API gateway (Kong) | http://\<host\>:55521 |
| Postgres | `<host>:55532` |
> 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.
## Deployment & portability
Runtime state under `/mnt/user/appdata/mc-cars/data/`:
```
data/
├── db/ # Postgres cluster (bind mount)
└── storage/ # vehicle-photos bucket content
```
All bind mounts in `docker-compose.yml` use absolute paths under `/mnt/user/appdata/mc-cars`. Clone the repo there, deploy as a Portainer stack, done. No `build:` steps — every service pulls a pre-built image.
To put behind **Nginx Proxy Manager** with a single public domain (`cars.yourdomain.com`):
- Proxy `/``mccars-web:80` (or `<host>:55580`)
- Custom locations `/auth/v1/`, `/rest/v1/`, `/realtime/v1/`, `/storage/v1/``mccars-kong:8000` (or `<host>:55521`)
- Do **not** expose `/pg/` or Studio publicly.
- Update `.env` URLs to `https://cars.yourdomain.com`.
## 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 # (legacy, not used in Portainer deploy)
│ ├── 99-config.sh # entrypoint: injects config.js with anon key
│ ├── 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 (generated at boot)
│ ├── i18n.js
│ ├── styles.css
│ ├── impressum.html
│ └── datenschutz.html
├── .gitattributes # enforces LF on .sh files
├── AGENT.md # findings, conventions, traps
└── ARQUITECTURE.md # architecture deep-dive
```
See [AGENT.md](AGENT.md) and [ARQUITECTURE.md](ARQUITECTURE.md) for everything deeper.