Initial commit: SvelteKit PWA + PocketBase Setup für checkflo.de
- Landing Page mit Logo, Hero, Features, Steps, CTA - QR-Scan Checklisten-Flow (/s/[id]) - PocketBase Client (pb.ts) - Makefile für DS-Deployment (SSH) - Setup-Scripts: setup-db.sh, seed-demo.sh
This commit is contained in:
commit
f2615c9e07
26 changed files with 2745 additions and 0 deletions
93
scripts/seed-demo.sh
Executable file
93
scripts/seed-demo.sh
Executable file
|
|
@ -0,0 +1,93 @@
|
|||
#!/bin/bash
|
||||
# Legt den Demo-Tenant mit Stationen an.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PB_URL="${PB_URL:-https://api.checkflo.de}"
|
||||
|
||||
if [ -z "${PB_EMAIL:-}" ] || [ -z "${PB_PASSWORD:-}" ]; then
|
||||
echo "Aufruf: PB_EMAIL=... PB_PASSWORD=... ./seed-demo.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Authentifizierung
|
||||
TOKEN=$(curl -sf -X POST "$PB_URL/api/collections/_superusers/auth-with-password" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"identity\":\"$PB_EMAIL\",\"password\":\"$PB_PASSWORD\"}" | jq -r '.token')
|
||||
|
||||
echo "✓ Eingeloggt"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Tenant: Musterküche GmbH
|
||||
# ----------------------------------------------------------
|
||||
echo "→ Erstelle Demo-Tenant..."
|
||||
TENANT=$(curl -sf -X POST "$PB_URL/api/collections/tenants/records" \
|
||||
-H "Authorization: $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "Musterküche GmbH",
|
||||
"slug": "musterkueche",
|
||||
"primary_color": "#e85d04",
|
||||
"plan": "basic",
|
||||
"active": true
|
||||
}')
|
||||
TENANT_ID=$(echo "$TENANT" | jq -r '.id')
|
||||
echo "✓ Tenant: Musterküche GmbH ($TENANT_ID)"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Stationen
|
||||
# ----------------------------------------------------------
|
||||
create_station() {
|
||||
local name=$1
|
||||
local type=$2
|
||||
local min=$3
|
||||
local max=$4
|
||||
local qr_id
|
||||
qr_id=$(uuidgen | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
curl -sf -X POST "$PB_URL/api/collections/stations/records" \
|
||||
-H "Authorization: $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"tenant\": \"$TENANT_ID\",
|
||||
\"name\": \"$name\",
|
||||
\"type\": \"$type\",
|
||||
\"target_temp_min\": $min,
|
||||
\"target_temp_max\": $max,
|
||||
\"qr_id\": \"$qr_id\",
|
||||
\"active\": true
|
||||
}" | jq -r '"✓ Station: \(.name) — QR: \(.qr_id)"'
|
||||
}
|
||||
|
||||
echo "→ Erstelle Stationen..."
|
||||
create_station "Kühlschrank 1 (Küche)" "kuehlschrank" 1 7
|
||||
create_station "Kühlschrank 2 (Getränke)" "kuehlschrank" 1 8
|
||||
create_station "Tiefkühlzelle" "tiefkuehl" -22 -18
|
||||
create_station "Warmhaltebehälter" "warmhalte" 65 80
|
||||
create_station "Wochenhygiene-Check" "hygiene" 0 0
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Demo-User (Admin des Tenants)
|
||||
# ----------------------------------------------------------
|
||||
echo "→ Erstelle Demo-User..."
|
||||
curl -sf -X POST "$PB_URL/api/collections/users/records" \
|
||||
-H "Authorization: $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"email\": \"chef@musterkueche.de\",
|
||||
\"password\": \"Demo1234567!\",
|
||||
\"passwordConfirm\": \"Demo1234567!\",
|
||||
\"name\": \"Chef Demo\",
|
||||
\"tenant\": \"$TENANT_ID\",
|
||||
\"role\": \"admin\",
|
||||
\"verified\": true
|
||||
}" | jq -r '"✓ User: \(.email)"'
|
||||
|
||||
echo ""
|
||||
echo " ✓ Demo-Daten angelegt:"
|
||||
echo " Tenant: Musterküche GmbH ($TENANT_ID)"
|
||||
echo " Login: chef@musterkueche.de / Demo1234567!"
|
||||
echo " Stationen: 5"
|
||||
echo ""
|
||||
echo " QR-Scan URL: https://checkflo.de/s/{qr_id}"
|
||||
echo ""
|
||||
144
scripts/setup-db
Executable file
144
scripts/setup-db
Executable file
|
|
@ -0,0 +1,144 @@
|
|||
#!/bin/bash
|
||||
# Legt das PocketBase-Datenmodell für checkflo an.
|
||||
# Aufruf: PB_EMAIL=... PB_PASSWORD=... ./scripts/setup-db.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PB_URL="${PB_URL:-https://api.checkflo.de}"
|
||||
|
||||
if [ -z "${PB_EMAIL:-}" ] || [ -z "${PB_PASSWORD:-}" ]; then
|
||||
echo "Aufruf: PB_EMAIL=admin@... PB_PASSWORD=... ./scripts/setup-db.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v jq &>/dev/null; then
|
||||
echo "✗ jq nicht gefunden. Installieren: brew install jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "→ Verbinde mit $PB_URL ..."
|
||||
|
||||
# Authentifizierung
|
||||
AUTH=$(curl -sf -X POST "$PB_URL/api/collections/_superusers/auth-with-password" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"identity\":\"$PB_EMAIL\",\"password\":\"$PB_PASSWORD\"}")
|
||||
|
||||
TOKEN=$(echo "$AUTH" | jq -r '.token')
|
||||
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
|
||||
echo "✗ Authentifizierung fehlgeschlagen"
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ Eingeloggt"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Helper: Collection erstellen
|
||||
# ----------------------------------------------------------
|
||||
create_collection() {
|
||||
local label=$1
|
||||
local json=$2
|
||||
RESP=$(curl -sf -X POST "$PB_URL/api/collections" \
|
||||
-H "Authorization: $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$json")
|
||||
ID=$(echo "$RESP" | jq -r '.id')
|
||||
echo "$ID"
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 1. tenants
|
||||
# ----------------------------------------------------------
|
||||
echo "→ Erstelle 'tenants'..."
|
||||
TENANTS_ID=$(create_collection "tenants" '{
|
||||
"name": "tenants",
|
||||
"type": "base",
|
||||
"fields": [
|
||||
{"name": "name", "type": "text", "required": true},
|
||||
{"name": "slug", "type": "text", "required": true},
|
||||
{"name": "primary_color", "type": "text"},
|
||||
{"name": "logo", "type": "file", "maxSelect": 1, "maxSize": 5242880},
|
||||
{"name": "plan", "type": "select", "values": ["basic","pro","enterprise"], "maxSelect": 1},
|
||||
{"name": "active", "type": "bool"}
|
||||
],
|
||||
"listRule": "@request.auth.id != \"\"",
|
||||
"viewRule": "@request.auth.id != \"\"",
|
||||
"createRule": null,
|
||||
"updateRule": null,
|
||||
"deleteRule": null
|
||||
}')
|
||||
echo "✓ tenants ($TENANTS_ID)"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 2. stations
|
||||
# ----------------------------------------------------------
|
||||
echo "→ Erstelle 'stations'..."
|
||||
STATIONS_ID=$(create_collection "stations" "{
|
||||
\"name\": \"stations\",
|
||||
\"type\": \"base\",
|
||||
\"fields\": [
|
||||
{\"name\": \"tenant\", \"type\": \"relation\", \"collectionId\": \"$TENANTS_ID\", \"required\": true, \"maxSelect\": 1, \"cascadeDelete\": true},
|
||||
{\"name\": \"name\", \"type\": \"text\", \"required\": true},
|
||||
{\"name\": \"type\", \"type\": \"select\", \"values\": [\"kuehlschrank\",\"tiefkuehl\",\"warmhalte\",\"hygiene\",\"sonstiges\"], \"maxSelect\": 1},
|
||||
{\"name\": \"target_temp_min\", \"type\": \"number\"},
|
||||
{\"name\": \"target_temp_max\", \"type\": \"number\"},
|
||||
{\"name\": \"qr_id\", \"type\": \"text\", \"required\": true},
|
||||
{\"name\": \"active\", \"type\": \"bool\"}
|
||||
],
|
||||
\"listRule\": \"@request.auth.tenant = tenant\",
|
||||
\"viewRule\": \"@request.auth.tenant = tenant\",
|
||||
\"createRule\": \"@request.auth.tenant = tenant && @request.auth.role = 'admin'\",
|
||||
\"updateRule\": \"@request.auth.tenant = tenant && @request.auth.role = 'admin'\",
|
||||
\"deleteRule\": null
|
||||
}")
|
||||
echo "✓ stations ($STATIONS_ID)"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 3. check_logs
|
||||
# ----------------------------------------------------------
|
||||
echo "→ Erstelle 'check_logs'..."
|
||||
LOGS_ID=$(create_collection "check_logs" "{
|
||||
\"name\": \"check_logs\",
|
||||
\"type\": \"base\",
|
||||
\"fields\": [
|
||||
{\"name\": \"station\", \"type\": \"relation\", \"collectionId\": \"$STATIONS_ID\", \"required\": true, \"maxSelect\": 1, \"cascadeDelete\": false},
|
||||
{\"name\": \"tenant\", \"type\": \"relation\", \"collectionId\": \"$TENANTS_ID\", \"required\": true, \"maxSelect\": 1, \"cascadeDelete\": false},
|
||||
{\"name\": \"temperature\", \"type\": \"number\"},
|
||||
{\"name\": \"status\", \"type\": \"select\", \"values\": [\"ok\",\"abweichung\",\"kritisch\"], \"maxSelect\": 1},
|
||||
{\"name\": \"notes\", \"type\": \"text\"},
|
||||
{\"name\": \"photo\", \"type\": \"file\", \"maxSelect\": 1, \"maxSize\": 5242880},
|
||||
{\"name\": \"checked_by\", \"type\": \"text\"}
|
||||
],
|
||||
\"listRule\": \"@request.auth.tenant = tenant\",
|
||||
\"viewRule\": \"@request.auth.tenant = tenant\",
|
||||
\"createRule\": \"\",
|
||||
\"updateRule\": null,
|
||||
\"deleteRule\": \"@request.auth.tenant = tenant && @request.auth.role = 'admin'\"
|
||||
}")
|
||||
echo "✓ check_logs ($LOGS_ID)"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 4. users — tenant + role hinzufügen
|
||||
# ----------------------------------------------------------
|
||||
echo "→ Erweitere 'users' (tenant + role)..."
|
||||
USERS_RESP=$(curl -sf "$PB_URL/api/collections/users" -H "Authorization: $TOKEN")
|
||||
EXISTING_FIELDS=$(echo "$USERS_RESP" | jq '.fields')
|
||||
|
||||
NEW_FIELDS=$(echo "$EXISTING_FIELDS" | jq ". + [
|
||||
{\"name\": \"tenant\", \"type\": \"relation\", \"collectionId\": \"$TENANTS_ID\", \"maxSelect\": 1, \"cascadeDelete\": false},
|
||||
{\"name\": \"role\", \"type\": \"select\", \"values\": [\"admin\",\"techniker\"], \"maxSelect\": 1}
|
||||
]")
|
||||
|
||||
curl -sf -X PATCH "$PB_URL/api/collections/users" \
|
||||
-H "Authorization: $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"fields\": $NEW_FIELDS}" > /dev/null
|
||||
echo "✓ users erweitert"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Zusammenfassung
|
||||
# ----------------------------------------------------------
|
||||
echo ""
|
||||
echo " ✓ Datenmodell angelegt:"
|
||||
echo " tenants $TENANTS_ID"
|
||||
echo " stations $STATIONS_ID"
|
||||
echo " check_logs $LOGS_ID"
|
||||
echo ""
|
||||
144
scripts/setup-db.sh
Executable file
144
scripts/setup-db.sh
Executable file
|
|
@ -0,0 +1,144 @@
|
|||
#!/bin/bash
|
||||
# Legt das PocketBase-Datenmodell für checkflo an.
|
||||
# Aufruf: PB_EMAIL=... PB_PASSWORD=... ./scripts/setup-db.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PB_URL="${PB_URL:-https://api.checkflo.de}"
|
||||
|
||||
if [ -z "${PB_EMAIL:-}" ] || [ -z "${PB_PASSWORD:-}" ]; then
|
||||
echo "Aufruf: PB_EMAIL=admin@... PB_PASSWORD=... ./scripts/setup-db.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v jq &>/dev/null; then
|
||||
echo "✗ jq nicht gefunden. Installieren: brew install jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "→ Verbinde mit $PB_URL ..."
|
||||
|
||||
# Authentifizierung
|
||||
AUTH=$(curl -sf -X POST "$PB_URL/api/collections/_superusers/auth-with-password" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"identity\":\"$PB_EMAIL\",\"password\":\"$PB_PASSWORD\"}")
|
||||
|
||||
TOKEN=$(echo "$AUTH" | jq -r '.token')
|
||||
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
|
||||
echo "✗ Authentifizierung fehlgeschlagen"
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ Eingeloggt"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Helper: Collection erstellen
|
||||
# ----------------------------------------------------------
|
||||
create_collection() {
|
||||
local label=$1
|
||||
local json=$2
|
||||
RESP=$(curl -sf -X POST "$PB_URL/api/collections" \
|
||||
-H "Authorization: $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$json")
|
||||
ID=$(echo "$RESP" | jq -r '.id')
|
||||
echo "$ID"
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 1. tenants
|
||||
# ----------------------------------------------------------
|
||||
echo "→ Erstelle 'tenants'..."
|
||||
TENANTS_ID=$(create_collection "tenants" '{
|
||||
"name": "tenants",
|
||||
"type": "base",
|
||||
"fields": [
|
||||
{"name": "name", "type": "text", "required": true},
|
||||
{"name": "slug", "type": "text", "required": true},
|
||||
{"name": "primary_color", "type": "text"},
|
||||
{"name": "logo", "type": "file", "maxSelect": 1, "maxSize": 5242880},
|
||||
{"name": "plan", "type": "select", "values": ["basic","pro","enterprise"], "maxSelect": 1},
|
||||
{"name": "active", "type": "bool"}
|
||||
],
|
||||
"listRule": "@request.auth.id != \"\"",
|
||||
"viewRule": "@request.auth.id != \"\"",
|
||||
"createRule": null,
|
||||
"updateRule": null,
|
||||
"deleteRule": null
|
||||
}')
|
||||
echo "✓ tenants ($TENANTS_ID)"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 2. stations
|
||||
# ----------------------------------------------------------
|
||||
echo "→ Erstelle 'stations'..."
|
||||
STATIONS_ID=$(create_collection "stations" "{
|
||||
\"name\": \"stations\",
|
||||
\"type\": \"base\",
|
||||
\"fields\": [
|
||||
{\"name\": \"tenant\", \"type\": \"relation\", \"collectionId\": \"$TENANTS_ID\", \"required\": true, \"maxSelect\": 1, \"cascadeDelete\": true},
|
||||
{\"name\": \"name\", \"type\": \"text\", \"required\": true},
|
||||
{\"name\": \"type\", \"type\": \"select\", \"values\": [\"kuehlschrank\",\"tiefkuehl\",\"warmhalte\",\"hygiene\",\"sonstiges\"], \"maxSelect\": 1},
|
||||
{\"name\": \"target_temp_min\", \"type\": \"number\"},
|
||||
{\"name\": \"target_temp_max\", \"type\": \"number\"},
|
||||
{\"name\": \"qr_id\", \"type\": \"text\", \"required\": true},
|
||||
{\"name\": \"active\", \"type\": \"bool\"}
|
||||
],
|
||||
\"listRule\": \"@request.auth.tenant = tenant\",
|
||||
\"viewRule\": \"@request.auth.tenant = tenant\",
|
||||
\"createRule\": \"@request.auth.tenant = tenant && @request.auth.role = 'admin'\",
|
||||
\"updateRule\": \"@request.auth.tenant = tenant && @request.auth.role = 'admin'\",
|
||||
\"deleteRule\": null
|
||||
}")
|
||||
echo "✓ stations ($STATIONS_ID)"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 3. check_logs
|
||||
# ----------------------------------------------------------
|
||||
echo "→ Erstelle 'check_logs'..."
|
||||
LOGS_ID=$(create_collection "check_logs" "{
|
||||
\"name\": \"check_logs\",
|
||||
\"type\": \"base\",
|
||||
\"fields\": [
|
||||
{\"name\": \"station\", \"type\": \"relation\", \"collectionId\": \"$STATIONS_ID\", \"required\": true, \"maxSelect\": 1, \"cascadeDelete\": false},
|
||||
{\"name\": \"tenant\", \"type\": \"relation\", \"collectionId\": \"$TENANTS_ID\", \"required\": true, \"maxSelect\": 1, \"cascadeDelete\": false},
|
||||
{\"name\": \"temperature\", \"type\": \"number\"},
|
||||
{\"name\": \"status\", \"type\": \"select\", \"values\": [\"ok\",\"abweichung\",\"kritisch\"], \"maxSelect\": 1},
|
||||
{\"name\": \"notes\", \"type\": \"text\"},
|
||||
{\"name\": \"photo\", \"type\": \"file\", \"maxSelect\": 1, \"maxSize\": 5242880},
|
||||
{\"name\": \"checked_by\", \"type\": \"text\"}
|
||||
],
|
||||
\"listRule\": \"@request.auth.tenant = tenant\",
|
||||
\"viewRule\": \"@request.auth.tenant = tenant\",
|
||||
\"createRule\": \"\",
|
||||
\"updateRule\": null,
|
||||
\"deleteRule\": \"@request.auth.tenant = tenant && @request.auth.role = 'admin'\"
|
||||
}")
|
||||
echo "✓ check_logs ($LOGS_ID)"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 4. users — tenant + role hinzufügen
|
||||
# ----------------------------------------------------------
|
||||
echo "→ Erweitere 'users' (tenant + role)..."
|
||||
USERS_RESP=$(curl -sf "$PB_URL/api/collections/users" -H "Authorization: $TOKEN")
|
||||
EXISTING_FIELDS=$(echo "$USERS_RESP" | jq '.fields')
|
||||
|
||||
NEW_FIELDS=$(echo "$EXISTING_FIELDS" | jq ". + [
|
||||
{\"name\": \"tenant\", \"type\": \"relation\", \"collectionId\": \"$TENANTS_ID\", \"maxSelect\": 1, \"cascadeDelete\": false},
|
||||
{\"name\": \"role\", \"type\": \"select\", \"values\": [\"admin\",\"techniker\"], \"maxSelect\": 1}
|
||||
]")
|
||||
|
||||
curl -sf -X PATCH "$PB_URL/api/collections/users" \
|
||||
-H "Authorization: $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"fields\": $NEW_FIELDS}" > /dev/null
|
||||
echo "✓ users erweitert"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Zusammenfassung
|
||||
# ----------------------------------------------------------
|
||||
echo ""
|
||||
echo " ✓ Datenmodell angelegt:"
|
||||
echo " tenants $TENANTS_ID"
|
||||
echo " stations $STATIONS_ID"
|
||||
echo " check_logs $LOGS_ID"
|
||||
echo ""
|
||||
Loading…
Add table
Add a link
Reference in a new issue