diff --git a/Makefile b/Makefile index c543f39..43cbc7b 100644 --- a/Makefile +++ b/Makefile @@ -144,7 +144,7 @@ pb-admin: # ============================================================== # STAGING # ============================================================== -.PHONY: staging-deploy staging-seed staging-logs staging-status staging-stop +.PHONY: staging-deploy staging-reset staging-seed staging-logs staging-status staging-stop staging-deploy: check-ssh @echo "→ Sync zu DS (Staging)..." @@ -153,22 +153,18 @@ staging-deploy: check-ssh @if [ -f .env ]; then \ cat .env | ssh $(DS_HOST) "cat > $(STAGING_PATH)/.env"; \ fi - @echo "→ Hooks synchronisieren (Staging)..." + @echo "→ Hooks synchronisieren (Staging, vollständig)..." @ssh $(DS_HOST) "mkdir -p $(STAGING_HOOKS)" @if ls $(HOOKS_SRC)/*.pb.js 2>/dev/null | grep -q .; then \ for f in $(HOOKS_SRC)/*.pb.js; do \ cat "$$f" | ssh $(DS_HOST) "cat > $(STAGING_HOOKS)/$$(basename $$f)"; \ done; \ fi - @echo "→ Migrations synchronisieren (Staging, nur neue)..." + @echo "→ Migrations synchronisieren (Staging, immer aktuell)..." @ssh $(DS_HOST) "mkdir -p $(STAGING_MIGRATIONS)" @if ls $(MIGRATIONS_SRC)/*.js 2>/dev/null | grep -q .; then \ for f in $(MIGRATIONS_SRC)/*.js; do \ - fname=$$(basename "$$f"); \ - if ! ssh $(DS_HOST) "test -f $(STAGING_MIGRATIONS)/$$fname" 2>/dev/null; then \ - cat "$$f" | ssh $(DS_HOST) "cat > $(STAGING_MIGRATIONS)/$$fname"; \ - echo " ✓ $$fname"; \ - fi; \ + cat "$$f" | ssh $(DS_HOST) "cat > $(STAGING_MIGRATIONS)/$$(basename $$f)"; \ done; \ fi @echo "→ Docker rebuild + restart (Staging)..." @@ -181,6 +177,20 @@ staging-deploy: check-ssh @echo " App: https://staging.vereins.haus" @echo " PocketBase: https://api-staging.vereins.haus/_/" +# Löscht alle PB-Daten auf Staging → Migrations laufen frisch durch +# Danach: make staging-deploy && make staging-seed +staging-reset: check-ssh staging-stop + @echo "→ PocketBase-Daten auf Staging löschen..." + @ssh $(DS_HOST) "rm -rf \ + $(STAGING_PATH)/pocketbase/data/storage \ + '$(STAGING_PATH)/pocketbase/data/data.db' \ + '$(STAGING_PATH)/pocketbase/data/data.db-wal' \ + '$(STAGING_PATH)/pocketbase/data/data.db-shm' \ + $(STAGING_PATH)/pocketbase/migrations" + @echo "→ Alle Hooks auf Staging löschen (werden via staging-deploy neu geschrieben)..." + @ssh $(DS_HOST) "rm -f $(STAGING_HOOKS)/*.pb.js" + @echo " ✓ Reset fertig. Jetzt: make staging-deploy && make staging-seed" + staging-seed: @echo "→ Testdaten in Staging einfügen..." @echo " Voraussetzung: PB_EMAIL + PB_PASSWORD in .env gesetzt (Staging-Superuser)" diff --git a/pocketbase/pb_migrations/1779230900_neuigkeiten.js b/pocketbase/pb_migrations/1779230900_neuigkeiten.js index 9a7a236..210d69f 100644 --- a/pocketbase/pb_migrations/1779230900_neuigkeiten.js +++ b/pocketbase/pb_migrations/1779230900_neuigkeiten.js @@ -1,46 +1,188 @@ /// migrate((app) => { - // Neuigkeiten + Reaktionen via importCollections (korrekte Rule-Compilation in PocketBase v0.38) - app.importCollections([ - { - "createRule": "@request.auth.verein_id = verein_id", - "deleteRule": "@request.auth.verein_id = verein_id && autor_id = @request.auth.id", - "listRule": "@request.auth.verein_id = verein_id", - "viewRule": "@request.auth.verein_id = verein_id", - "updateRule": "@request.auth.verein_id = verein_id && autor_id = @request.auth.id", - "fields": [ - { "type": "relation", "name": "verein_id", "required": true, "cascadeDelete": true, "collectionId": "pbc_3589557411", "maxSelect": 1 }, - { "type": "text", "name": "autor_id", "required": true }, - { "type": "text", "name": "autor_name" }, - { "type": "text", "name": "text" }, - { "type": "file", "name": "medien", "maxSelect": 10, "maxSize": 15728640, "mimeTypes": ["image/jpeg","image/png","image/gif","image/webp","video/mp4","video/quicktime"] }, - { "type": "relation", "name": "gruppe_ids", "cascadeDelete": false, "collectionId": "pbc_3099069179", "maxSelect": 99 }, - { "type": "relation", "name": "termin_id", "cascadeDelete": false, "collectionId": "pbc_2279568741", "maxSelect": 1 } - ], - "name": "neuigkeiten", - "type": "base" - } - ], false) + // neuigkeiten: new Collection() + app.save() – genau wie nachrichten/mitglieder. + // importCollections() kompiliert Rules in PB v0.38 NICHT korrekt → HTTP 400. + const neuigkeiten = new Collection({ + "id": "pbc_1779230901", + "name": "neuigkeiten", + "type": "base", + "system": false, + "listRule": "@request.auth.verein_id = verein_id", + "viewRule": "@request.auth.verein_id = verein_id", + "createRule": "@request.auth.verein_id = verein_id", + "updateRule": "@request.auth.verein_id = verein_id && autor_id = @request.auth.id", + "deleteRule": "@request.auth.verein_id = verein_id && autor_id = @request.auth.id", + "indexes": [], + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "cascadeDelete": true, + "collectionId": "pbc_3589557411", + "hidden": false, + "id": "relation3100049688", + "maxSelect": 1, + "minSelect": 0, + "name": "verein_id", + "presentable": false, + "required": true, + "system": false, + "type": "relation" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text2300079512", + "max": 0, + "min": 0, + "name": "autor_id", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": true, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text1546895374", + "max": 0, + "min": 0, + "name": "autor_name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text1059453555", + "max": 0, + "min": 0, + "name": "text", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "file5103562148", + "maxSelect": 10, + "maxSize": 15728640, + "mimeTypes": ["image/jpeg","image/png","image/gif","image/webp","video/mp4","video/quicktime"], + "name": "medien", + "presentable": false, + "required": false, + "system": false, + "type": "file" + }, + { + "cascadeDelete": false, + "collectionId": "pbc_3099069179", + "hidden": false, + "id": "relation3177861730", + "maxSelect": 99, + "minSelect": 0, + "name": "gruppe_ids", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + }, + { + "cascadeDelete": false, + "collectionId": "pbc_2279568741", + "hidden": false, + "id": "relation2143897900", + "maxSelect": 1, + "minSelect": 0, + "name": "termin_id", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + } + ] + }); + app.save(neuigkeiten); - const neuigkeitenId = app.findCollectionByNameOrId("neuigkeiten").id + const neuigkeitenId = app.findCollectionByNameOrId("neuigkeiten").id; - app.importCollections([ - { - "createRule": "@request.auth.id != ''", - "deleteRule": "@request.auth.id = user_id", - "listRule": "@request.auth.verein_id = beitrag_id.verein_id", - "viewRule": "@request.auth.verein_id = beitrag_id.verein_id", - "updateRule": null, - "fields": [ - { "type": "relation", "name": "beitrag_id", "required": true, "cascadeDelete": true, "collectionId": neuigkeitenId, "maxSelect": 1 }, - { "type": "relation", "name": "user_id", "required": true, "cascadeDelete": true, "collectionId": "_pb_users_auth_", "maxSelect": 1 } - ], - "indexes": ["CREATE UNIQUE INDEX idx_reaktion_unique ON reaktionen (beitrag_id, user_id)"], - "name": "reaktionen", - "type": "base" - } - ], false) + const reaktionen = new Collection({ + "id": "pbc_1779230902", + "name": "reaktionen", + "type": "base", + "system": false, + "createRule": "@request.auth.id != ''", + "deleteRule": "@request.auth.id = user_id", + "listRule": "@request.auth.verein_id = beitrag_id.verein_id", + "viewRule": "@request.auth.verein_id = beitrag_id.verein_id", + "updateRule": null, + "indexes": ["CREATE UNIQUE INDEX idx_reaktion_unique ON reaktionen (beitrag_id, user_id)"], + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "cascadeDelete": true, + "collectionId": neuigkeitenId, + "hidden": false, + "id": "relation4196188140", + "maxSelect": 1, + "minSelect": 0, + "name": "beitrag_id", + "presentable": false, + "required": true, + "system": false, + "type": "relation" + }, + { + "cascadeDelete": true, + "collectionId": "_pb_users_auth_", + "hidden": false, + "id": "relation3255232538", + "maxSelect": 1, + "minSelect": 0, + "name": "user_id", + "presentable": false, + "required": true, + "system": false, + "type": "relation" + } + ] + }); + app.save(reaktionen); }, (app) => { try { app.delete(app.findCollectionByNameOrId("reaktionen")) } catch(_) {}