Staging: docker-compose.staging.yml, Makefile-Targets, Seed-Script (18 Mitglieder, Termine, Orte, Beitragsarten)
This commit is contained in:
parent
81f34905cf
commit
a4436d70c2
3 changed files with 379 additions and 0 deletions
69
Makefile
69
Makefile
|
|
@ -11,6 +11,13 @@ CONTAINER_PB := vereinshaus-pocketbase
|
|||
CONTAINER_APP := vereinshaus-app
|
||||
DOCKER := sudo /usr/local/bin/docker
|
||||
|
||||
STAGING_PATH := /volume1/docker/vereinshaus-staging
|
||||
CONTAINER_PB_STAGING := vereinshaus-staging-pocketbase
|
||||
CONTAINER_APP_STAGING:= vereinshaus-staging-app
|
||||
STAGING_PB_URL := http://localhost:8091
|
||||
STAGING_MIGRATIONS := $(STAGING_PATH)/pocketbase/migrations
|
||||
STAGING_HOOKS := $(STAGING_PATH)/pocketbase/data/pb_hooks
|
||||
|
||||
TAR_EXCLUDE := --exclude='.git' \
|
||||
--exclude='./app/node_modules' \
|
||||
--exclude='./app/.svelte-kit' \
|
||||
|
|
@ -133,3 +140,65 @@ shell-pb: check-ssh
|
|||
|
||||
pb-admin:
|
||||
@echo " PocketBase Admin: https://api.vereins.haus/_/"
|
||||
|
||||
# ==============================================================
|
||||
# STAGING
|
||||
# ==============================================================
|
||||
.PHONY: staging-deploy staging-seed staging-logs staging-status staging-stop
|
||||
|
||||
staging-deploy: check-ssh
|
||||
@echo "→ Sync zu DS (Staging)..."
|
||||
@COPYFILE_DISABLE=1 tar czf - $(TAR_EXCLUDE) . | ssh $(DS_HOST) "tar xzf - -C $(STAGING_PATH)/"
|
||||
@echo "→ .env auf DS (Staging)..."
|
||||
@if [ -f .env ]; then \
|
||||
cat .env | ssh $(DS_HOST) "cat > $(STAGING_PATH)/.env"; \
|
||||
fi
|
||||
@echo "→ Hooks synchronisieren (Staging)..."
|
||||
@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)..."
|
||||
@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; \
|
||||
done; \
|
||||
fi
|
||||
@echo "→ Docker rebuild + restart (Staging)..."
|
||||
@ssh $(DS_HOST) " \
|
||||
cd $(STAGING_PATH) && \
|
||||
$(DOCKER) compose -f docker-compose.staging.yml down && \
|
||||
$(DOCKER) compose -f docker-compose.staging.yml build app-staging && \
|
||||
$(DOCKER) compose -f docker-compose.staging.yml up -d"
|
||||
@echo " ✓ Staging bereit."
|
||||
@echo " App: https://staging.vereins.haus"
|
||||
@echo " PocketBase: https://api-staging.vereins.haus/_/"
|
||||
|
||||
staging-seed:
|
||||
@echo "→ Testdaten in Staging einfügen..."
|
||||
@echo " Voraussetzung: PB_EMAIL + PB_PASSWORD in .env gesetzt (Staging-Superuser)"
|
||||
@if [ -f .env ]; then \
|
||||
export $$(grep -v '^#' .env | xargs) && \
|
||||
PB_URL=https://api-staging.vereins.haus node scripts/seed.js; \
|
||||
else \
|
||||
PB_URL=https://api-staging.vereins.haus node scripts/seed.js; \
|
||||
fi
|
||||
|
||||
staging-logs: check-ssh
|
||||
@ssh $(DS_HOST) "$(DOCKER) logs $(CONTAINER_APP_STAGING) --tail=50"
|
||||
|
||||
staging-status: check-ssh
|
||||
@ssh $(DS_HOST) "$(DOCKER) ps \
|
||||
--filter name=vereinshaus-staging \
|
||||
--format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'"
|
||||
|
||||
staging-stop: check-ssh
|
||||
@ssh $(DS_HOST) "cd $(STAGING_PATH) && $(DOCKER) compose -f docker-compose.staging.yml down"
|
||||
@echo " ✓ Staging gestoppt."
|
||||
|
|
|
|||
46
docker-compose.staging.yml
Normal file
46
docker-compose.staging.yml
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
version: "3.8"
|
||||
|
||||
services:
|
||||
pocketbase-staging:
|
||||
image: ghcr.io/muchobien/pocketbase:latest
|
||||
container_name: vereinshaus-staging-pocketbase
|
||||
restart: unless-stopped
|
||||
command: ["--migrationsDir=/pb_data/migrations"]
|
||||
volumes:
|
||||
- /volume1/docker/vereinshaus-staging/pocketbase/data:/pb_data
|
||||
- /volume1/docker/vereinshaus-staging/pocketbase/storage:/pb_public
|
||||
- /volume1/docker/vereinshaus-staging/pocketbase/data/pb_hooks:/pb_hooks
|
||||
- /volume1/docker/vereinshaus-staging/pocketbase/migrations:/pb_data/migrations
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
- BREVO_KEY=${BREVO_KEY}
|
||||
- BREVO_SENDER=${BREVO_SENDER:-noreply@vereins.haus}
|
||||
networks:
|
||||
- default
|
||||
- npm_bridge
|
||||
|
||||
app-staging:
|
||||
build:
|
||||
context: ./app
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
VITE_PB_URL: https://api-staging.vereins.haus
|
||||
image: vereinshaus-staging-app
|
||||
container_name: vereinshaus-staging-app
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
- HOST=0.0.0.0
|
||||
- PORT=3000
|
||||
- PUBLIC_VAPID_KEY=${PUBLIC_VAPID_KEY}
|
||||
- VAPID_PRIVATE_KEY=${VAPID_PRIVATE_KEY}
|
||||
- VAPID_SUBJECT=${VAPID_SUBJECT:-mailto:info@vereins.haus}
|
||||
- PB_URL=http://pocketbase-staging:8090
|
||||
networks:
|
||||
- default
|
||||
- npm_bridge
|
||||
|
||||
networks:
|
||||
npm_bridge:
|
||||
external: true
|
||||
name: nginx-proxy-manager_bridge_net
|
||||
264
scripts/seed.js
Normal file
264
scripts/seed.js
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
#!/usr/bin/env node
|
||||
// Testdaten für vereins.haus – Staging
|
||||
// Aufruf: PB_URL=http://localhost:8090 PB_EMAIL=admin@test.de PB_PASSWORD=Test123456! node scripts/seed.js
|
||||
|
||||
const PB_URL = process.env.PB_URL || 'http://localhost:8090';
|
||||
const PB_EMAIL = process.env.PB_EMAIL || '';
|
||||
const PB_PWD = process.env.PB_PASSWORD || '';
|
||||
|
||||
if (!PB_EMAIL || !PB_PWD) {
|
||||
console.error('Fehler: PB_EMAIL und PB_PASSWORD setzen.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let token = '';
|
||||
|
||||
async function pb(method, path, body) {
|
||||
const res = await fetch(`${PB_URL}/api/${path}`, {
|
||||
method,
|
||||
headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: token } : {}) },
|
||||
body: body ? JSON.stringify(body) : undefined,
|
||||
});
|
||||
const json = await res.json().catch(() => ({}));
|
||||
if (!res.ok) throw new Error(`${method} /${path} → ${res.status}: ${JSON.stringify(json)}`);
|
||||
return json;
|
||||
}
|
||||
|
||||
async function find(collection, filter) {
|
||||
const r = await pb('GET', `collections/${collection}/records?filter=${encodeURIComponent(filter)}&perPage=1`);
|
||||
return r.items?.[0] ?? null;
|
||||
}
|
||||
|
||||
async function create(collection, data) {
|
||||
return pb('POST', `collections/${collection}/records`, data);
|
||||
}
|
||||
|
||||
async function update(collection, id, data) {
|
||||
return pb('PATCH', `collections/${collection}/records/${id}`, data);
|
||||
}
|
||||
|
||||
// ── 1. Admin-Login ──────────────────────────────────────────────────────────
|
||||
console.log('→ Admin-Login…');
|
||||
const auth = await pb('POST', 'collections/_superusers/auth-with-password', {
|
||||
identity: PB_EMAIL, password: PB_PWD,
|
||||
});
|
||||
token = auth.token;
|
||||
console.log(' ✓ Eingeloggt als', PB_EMAIL);
|
||||
|
||||
// ── 2. Verein ────────────────────────────────────────────────────────────────
|
||||
console.log('→ Verein anlegen…');
|
||||
let verein = await find('vereine', 'name = "TSV Musterstadt 1983 e.V."');
|
||||
if (!verein) {
|
||||
verein = await create('vereine', {
|
||||
name: 'TSV Musterstadt 1983 e.V.',
|
||||
adresse: 'Vereinsstraße 12',
|
||||
plz: '80333',
|
||||
ort: 'Musterstadt',
|
||||
bundesland: 'BY',
|
||||
plan: 'starter',
|
||||
dosb_mitglied: true,
|
||||
email: 'info@tsv-musterstadt.de',
|
||||
telefon: '089 123456',
|
||||
website: 'https://tsv-musterstadt.de',
|
||||
glaeubigerid: 'DE98ZZZ09999999999',
|
||||
iban: 'DE89370400440532013000',
|
||||
bic: 'COBADEFFXXX',
|
||||
});
|
||||
}
|
||||
console.log(' ✓ Verein:', verein.name, `(${verein.id})`);
|
||||
|
||||
// ── 3. Admin-User ────────────────────────────────────────────────────────────
|
||||
console.log('→ Admin-User…');
|
||||
let adminUser = await find('users', 'email = "vorstand@tsv-musterstadt.de"');
|
||||
if (!adminUser) {
|
||||
adminUser = await create('users', {
|
||||
email: 'vorstand@tsv-musterstadt.de',
|
||||
password: 'Test123456!', passwordConfirm: 'Test123456!',
|
||||
name: 'Max Mustermann', verein_id: verein.id, rolle: null, // null = admin
|
||||
emailVisibility: true,
|
||||
});
|
||||
}
|
||||
console.log(' ✓ Admin:', adminUser.email);
|
||||
|
||||
// ── 4. Gruppen ───────────────────────────────────────────────────────────────
|
||||
console.log('→ Gruppen…');
|
||||
const gruppenDef = ['Vorstand', 'Aktive Mitglieder', 'Jugend U15', 'Senioren'];
|
||||
const gruppen = {};
|
||||
for (const name of gruppenDef) {
|
||||
let g = await find('gruppen', `name = "${name}" && verein_id = "${verein.id}"`);
|
||||
if (!g) g = await create('gruppen', { verein_id: verein.id, name });
|
||||
gruppen[name] = g.id;
|
||||
}
|
||||
console.log(' ✓', Object.keys(gruppen).join(', '));
|
||||
|
||||
// ── 5. Mitglieder ────────────────────────────────────────────────────────────
|
||||
console.log('→ Mitglieder (18)…');
|
||||
const mitgliederDef = [
|
||||
// Vorstand
|
||||
{ vorname: 'Max', nachname: 'Mustermann', email: 'max.mustermann@example.de', telefon: '0170 1111111', geburtsdatum: '1975-03-15', eintrittsdatum: '2000-01-01', strasse: 'Hauptstraße 1', plz: '80333', ort: 'Musterstadt', iban: 'DE89370400440532013000', bic: 'COBADEFFXXX', status: 'aktiv', gruppe: 'Vorstand', mandatsreferenz: 'MANDAT-001', mandatsdatum: '2020-01-10' },
|
||||
{ vorname: 'Sabine', nachname: 'Richter', email: 'sabine.richter@example.de', telefon: '0171 2222222', geburtsdatum: '1980-07-22', eintrittsdatum: '2005-03-01', strasse: 'Birkenweg 5', plz: '80334', ort: 'Musterstadt', iban: 'DE27100777770209299700', bic: 'SSKMDEMMXXX', status: 'aktiv', gruppe: 'Vorstand', mandatsreferenz: 'MANDAT-002', mandatsdatum: '2020-01-10' },
|
||||
// Aktive mit IBAN
|
||||
{ vorname: 'Anna', nachname: 'Schmidt', email: 'anna.schmidt@example.de', telefon: '0172 3333333', geburtsdatum: '1990-11-05', eintrittsdatum: '2015-09-01', strasse: 'Rosenstraße 8', plz: '80333', ort: 'Musterstadt', iban: 'DE61500105179767440929', bic: 'BELADEBEXXX', status: 'aktiv', gruppe: 'Aktive Mitglieder', mandatsreferenz: 'MANDAT-003', mandatsdatum: '2021-04-15' },
|
||||
{ vorname: 'Peter', nachname: 'Wagner', email: 'peter.wagner@example.de', telefon: '0173 4444444', geburtsdatum: '1985-02-28', eintrittsdatum: '2010-01-15', strasse: 'Gartenweg 12', plz: '80334', ort: 'Musterstadt', iban: 'DE24500105171911148770', bic: 'BELADEBEXXX', status: 'aktiv', gruppe: 'Aktive Mitglieder', mandatsreferenz: 'MANDAT-004', mandatsdatum: '2021-04-15' },
|
||||
{ vorname: 'Thomas', nachname: 'Fischer', email: 'thomas.fischer@example.de', telefon: '0174 5555555', geburtsdatum: '1978-06-10', eintrittsdatum: '2008-04-01', strasse: 'Lindenallee 3', plz: '80335', ort: 'Musterstadt', iban: 'DE12500105176228935005', bic: 'BELADEBEXXX', status: 'aktiv', gruppe: 'Aktive Mitglieder', mandatsreferenz: 'MANDAT-005', mandatsdatum: '2021-04-15' },
|
||||
{ vorname: 'Claudia', nachname: 'König', email: 'claudia.koenig@example.de', telefon: '0175 6666666', geburtsdatum: '1992-09-17', eintrittsdatum: '2018-06-01', strasse: 'Feldweg 7', plz: '80333', ort: 'Musterstadt', iban: 'DE67200501001234567890', bic: 'HASPDEHHXXX', status: 'aktiv', gruppe: 'Aktive Mitglieder', mandatsreferenz: 'MANDAT-006', mandatsdatum: '2022-01-20' },
|
||||
{ vorname: 'Michael', nachname: 'Koch', email: 'michael.koch@example.de', telefon: '0176 7777777', geburtsdatum: '1983-04-03', eintrittsdatum: '2012-02-01', strasse: 'Bergstraße 22', plz: '80336', ort: 'Musterstadt', iban: 'DE86200400600526015800', bic: 'COBADEFFXXX', status: 'aktiv', gruppe: 'Aktive Mitglieder', mandatsreferenz: 'MANDAT-007', mandatsdatum: '2021-04-15' },
|
||||
{ vorname: 'Lisa', nachname: 'Zimmermann', email: 'lisa.zimm@example.de', telefon: '0177 8888888', geburtsdatum: '1995-12-25', eintrittsdatum: '2020-10-01', strasse: 'Blumenstraße 4', plz: '80333', ort: 'Musterstadt', iban: 'DE21700519950021267002', bic: 'BYLADEM1AUG', status: 'aktiv', gruppe: 'Aktive Mitglieder', mandatsreferenz: 'MANDAT-008', mandatsdatum: '2022-03-05' },
|
||||
{ vorname: 'Petra', nachname: 'Schreiber', email: 'petra.schreiber@example.de', telefon: '0178 9999999', geburtsdatum: '1988-08-14', eintrittsdatum: '2014-07-01', strasse: 'Weinbergweg 9', plz: '80334', ort: 'Musterstadt', iban: 'DE36200400600532013004', bic: 'COBADEFFXXX', status: 'aktiv', gruppe: 'Aktive Mitglieder', mandatsreferenz: 'MANDAT-009', mandatsdatum: '2021-04-15' },
|
||||
// Aktive ohne IBAN
|
||||
{ vorname: 'Maria', nachname: 'Becker', email: 'maria.becker@example.de', telefon: '0179 1010101', geburtsdatum: '1987-01-30', eintrittsdatum: '2016-03-01', strasse: 'Kirchgasse 6', plz: '80335', ort: 'Musterstadt', iban: null, bic: null, status: 'aktiv', gruppe: 'Aktive Mitglieder', mandatsreferenz: null, mandatsdatum: null },
|
||||
{ vorname: 'Julia', nachname: 'Müller', email: 'julia.mueller@example.de', telefon: '0151 1111222', geburtsdatum: '1993-05-19', eintrittsdatum: '2019-01-01', strasse: 'Parkstraße 11', plz: '80333', ort: 'Musterstadt', iban: null, bic: null, status: 'aktiv', gruppe: 'Aktive Mitglieder', mandatsreferenz: null, mandatsdatum: null },
|
||||
{ vorname: 'Markus', nachname: 'Schäfer', email: 'markus.schaefer@example.de', telefon: '0152 3333444', geburtsdatum: '1991-07-07', eintrittsdatum: '2021-05-01', strasse: 'Schulweg 2', plz: '80336', ort: 'Musterstadt', iban: null, bic: null, status: 'aktiv', gruppe: 'Aktive Mitglieder', mandatsreferenz: null, mandatsdatum: null },
|
||||
// Jugend
|
||||
{ vorname: 'Lena', nachname: 'Bauer', email: null, telefon: '0160 1234567', geburtsdatum: '2012-03-22', eintrittsdatum: '2023-09-01', strasse: 'Schulstraße 14', plz: '80333', ort: 'Musterstadt', iban: 'DE47200400600128491600', bic: 'COBADEFFXXX', status: 'aktiv', gruppe: 'Jugend U15', mandatsreferenz: 'MANDAT-013', mandatsdatum: '2023-09-01' },
|
||||
{ vorname: 'Kevin', nachname: 'Hoffmann', email: null, telefon: '0160 7654321', geburtsdatum: '2013-11-08', eintrittsdatum: '2023-09-01', strasse: 'Waldweg 3', plz: '80334', ort: 'Musterstadt', iban: null, bic: null, status: 'aktiv', gruppe: 'Jugend U15', mandatsreferenz: null, mandatsdatum: null },
|
||||
{ vorname: 'Emma', nachname: 'Klein', email: null, telefon: '0160 1122334', geburtsdatum: '2011-06-15', eintrittsdatum: '2022-09-01', strasse: 'Seeweg 7', plz: '80335', ort: 'Musterstadt', iban: null, bic: null, status: 'aktiv', gruppe: 'Jugend U15', mandatsreferenz: null, mandatsdatum: null },
|
||||
// Senioren
|
||||
{ vorname: 'Gertrude', nachname: 'Neumann', email: 'g.neumann@example.de', telefon: '089 9876543', geburtsdatum: '1948-04-12', eintrittsdatum: '1990-01-01', strasse: 'Ahornweg 1', plz: '80333', ort: 'Musterstadt', iban: 'DE43500105176118506698', bic: 'BELADEBEXXX', status: 'aktiv', gruppe: 'Senioren', mandatsreferenz: 'MANDAT-016', mandatsdatum: '2019-06-01' },
|
||||
// Passiv / Ausgetreten
|
||||
{ vorname: 'Hans', nachname: 'Schneider', email: 'hans.schneider@example.de', telefon: '0173 0000001', geburtsdatum: '1965-10-20', eintrittsdatum: '1995-04-01', strasse: 'Bergblick 5', plz: '80334', ort: 'Musterstadt', iban: null, bic: null, status: 'passiv', gruppe: 'Senioren', mandatsreferenz: null, mandatsdatum: null },
|
||||
{ vorname: 'Horst', nachname: 'Braun', email: 'horst.braun@example.de', telefon: null, geburtsdatum: '1960-02-14', eintrittsdatum: '1988-01-01', strasse: 'Alte Gasse 3', plz: '80336', ort: 'Musterstadt', iban: null, bic: null, status: 'ausgetreten', gruppe: 'Aktive Mitglieder', mandatsreferenz: null, mandatsdatum: null, austrittsdatum: '2024-12-31' },
|
||||
];
|
||||
|
||||
let mitgliederIds = [];
|
||||
for (const m of mitgliederDef) {
|
||||
let rec = await find('mitglieder', `vorname = "${m.vorname}" && nachname = "${m.nachname}" && verein_id = "${verein.id}"`);
|
||||
if (!rec) {
|
||||
rec = await create('mitglieder', {
|
||||
verein_id: verein.id,
|
||||
vorname: m.vorname,
|
||||
nachname: m.nachname,
|
||||
email: m.email || null,
|
||||
telefon: m.telefon || null,
|
||||
geburtsdatum: m.geburtsdatum,
|
||||
eintrittsdatum: m.eintrittsdatum,
|
||||
austrittsdatum: m.austrittsdatum || null,
|
||||
strasse: m.strasse,
|
||||
plz: m.plz,
|
||||
ort: m.ort,
|
||||
iban: m.iban || null,
|
||||
bic: m.bic || null,
|
||||
mandatsreferenz:m.mandatsreferenz || null,
|
||||
mandatsdatum: m.mandatsdatum || null,
|
||||
status: m.status,
|
||||
gruppe_ids: [gruppen[m.gruppe]].filter(Boolean),
|
||||
});
|
||||
}
|
||||
mitgliederIds.push(rec.id);
|
||||
}
|
||||
console.log(` ✓ ${mitgliederIds.length} Mitglieder`);
|
||||
|
||||
// ── 6. Veranstaltungsorte ────────────────────────────────────────────────────
|
||||
console.log('→ Veranstaltungsorte…');
|
||||
const orteDef = [
|
||||
{ name: 'Turnhalle Grundschule Muster', adresse: 'Schulstraße 1, 80333 Musterstadt', typ: 'halle', aktiv: true },
|
||||
{ name: 'Vereinsheim TSV', adresse: 'Vereinsstraße 12, 80333 Musterstadt', typ: 'gebaeude', aktiv: true },
|
||||
{ name: 'Sportplatz West', adresse: 'Weststraße 99, 80335 Musterstadt', typ: 'platz', aktiv: true },
|
||||
];
|
||||
const orte = {};
|
||||
for (const o of orteDef) {
|
||||
let rec = await find('veranstaltungsorte', `name = "${o.name}" && verein_id = "${verein.id}"`);
|
||||
if (!rec) rec = await create('veranstaltungsorte', { verein_id: verein.id, ...o });
|
||||
orte[o.name] = rec.id;
|
||||
}
|
||||
// Ausfall: Turnhalle gesperrt wegen Schulveranstaltung
|
||||
const turnhalleId = orte['Turnhalle Grundschule Muster'];
|
||||
const existingAusfall = await find('ort_ausfaelle', `ort_id = "${turnhalleId}"`);
|
||||
if (!existingAusfall) {
|
||||
const nextWeek = new Date(); nextWeek.setDate(nextWeek.getDate() + 7);
|
||||
const nextWeek2 = new Date(); nextWeek2.setDate(nextWeek2.getDate() + 9);
|
||||
await create('ort_ausfaelle', {
|
||||
ort_id: turnhalleId,
|
||||
von: nextWeek.toISOString().slice(0,10),
|
||||
bis: nextWeek2.toISOString().slice(0,10),
|
||||
grund: 'Schulveranstaltung – Halle nicht verfügbar',
|
||||
});
|
||||
}
|
||||
console.log(' ✓ Orte:', Object.keys(orte).join(', '));
|
||||
|
||||
// ── 7. Beitragsarten ─────────────────────────────────────────────────────────
|
||||
console.log('→ Beitragsarten…');
|
||||
const beitraegeDef = [
|
||||
{ name: 'Jahresbeitrag Erwachsene', betrag: 48, rhythmus: 'jaehrlich', beschreibung: 'Für Mitglieder ab 18 Jahren' },
|
||||
{ name: 'Jahresbeitrag Jugend', betrag: 24, rhythmus: 'jaehrlich', beschreibung: 'Für Mitglieder unter 18 Jahren' },
|
||||
{ name: 'Aufnahmegebühr', betrag: 20, rhythmus: 'einmalig', beschreibung: 'Einmalig bei Vereinseintritt' },
|
||||
{ name: 'Monatsbeitrag Fitness', betrag: 15, rhythmus: 'monatlich', beschreibung: 'Für die Fitnessgruppe (optional)' },
|
||||
];
|
||||
for (const b of beitraegeDef) {
|
||||
const ex = await find('beitraege', `name = "${b.name}" && verein_id = "${verein.id}"`);
|
||||
if (!ex) await create('beitraege', { verein_id: verein.id, ...b });
|
||||
}
|
||||
console.log(' ✓', beitraegeDef.map(b => b.name).join(', '));
|
||||
|
||||
// ── 8. Termine ───────────────────────────────────────────────────────────────
|
||||
console.log('→ Termine…');
|
||||
|
||||
const d = (offsetDays, h = 0, m = 0) => {
|
||||
const dt = new Date();
|
||||
dt.setDate(dt.getDate() + offsetDays);
|
||||
dt.setHours(h, m, 0, 0);
|
||||
return dt.toISOString();
|
||||
};
|
||||
|
||||
const termineDef = [
|
||||
// Vergangen
|
||||
{ titel: 'Jahreshauptversammlung 2026', beginn: d(-60, 19, 0), ende: d(-60, 21, 0), ort_id: orte['Vereinsheim TSV'], gruppe_ids: Object.values(gruppen), beschreibung: 'Jahresabrechnung, Vorstandswahl, Planung Sommerfest' },
|
||||
{ titel: 'Trainingssession', beginn: d(-14, 18, 0), ende: d(-14, 20, 0), ort_id: orte['Turnhalle Grundschule Muster'], gruppe_ids: [gruppen['Aktive Mitglieder']] },
|
||||
{ titel: 'Jugendtraining', beginn: d(-7, 16, 0), ende: d(-7, 17, 30), ort_id: orte['Turnhalle Grundschule Muster'], gruppe_ids: [gruppen['Jugend U15']] },
|
||||
// Upcoming
|
||||
{ titel: 'Vorstandssitzung', beginn: d(3, 19, 30), ende: d(3, 21, 0), ort_id: orte['Vereinsheim TSV'], gruppe_ids: [gruppen['Vorstand']], beschreibung: 'Vorbereitung Sommerfest, Kassenstand Q1' },
|
||||
{ titel: 'Sommerfest TSV', beginn: d(32, 14, 0), ende: d(32, 22, 0), ort_id: orte['Sportplatz West'], gruppe_ids: Object.values(gruppen), beschreibung: 'Für Mitglieder und Familien – Grillen, Spiele, Live-Musik' },
|
||||
{ titel: 'Auswärtsspiel Musterliga', beginn: d(18, 11, 0), ende: d(18, 13, 0), ort_id: null, gruppe_ids: [gruppen['Aktive Mitglieder']], ort: 'FC Gegner – Stadionstraße 1', beschreibung: 'Hinfahrt 10:00 Uhr am Vereinsheim' },
|
||||
];
|
||||
|
||||
// Wöchentliches Training als Serie
|
||||
const serie_id = 'seed-serie-dienstag-2026';
|
||||
const trainingsTermine = [];
|
||||
for (let i = 1; i <= 8; i++) {
|
||||
// Nächster Dienstag + i Wochen
|
||||
const dt = new Date();
|
||||
const daysToTue = (2 - dt.getDay() + 7) % 7 || 7;
|
||||
dt.setDate(dt.getDate() + daysToTue + (i - 1) * 7);
|
||||
dt.setHours(18, 30, 0, 0);
|
||||
trainingsTermine.push({
|
||||
titel: 'Dienstags-Training',
|
||||
beginn: dt.toISOString(),
|
||||
ende: new Date(dt.getTime() + 90 * 60 * 1000).toISOString(),
|
||||
ort_id: orte['Turnhalle Grundschule Muster'],
|
||||
gruppe_ids:[gruppen['Aktive Mitglieder']],
|
||||
rrule: 'FREQ=WEEKLY;BYDAY=TU',
|
||||
serie_id,
|
||||
});
|
||||
}
|
||||
|
||||
const allTermine = [...termineDef, ...trainingsTermine];
|
||||
let termineAngelegt = 0;
|
||||
for (const t of allTermine) {
|
||||
const ex = await find('termine', `titel = "${t.titel}" && verein_id = "${verein.id}" && beginn = "${t.beginn}"`);
|
||||
if (!ex) {
|
||||
await create('termine', { verein_id: verein.id, verfuegbarkeit: 'offen', ...t });
|
||||
termineAngelegt++;
|
||||
}
|
||||
}
|
||||
console.log(` ✓ ${termineAngelegt} Termine (inkl. ${trainingsTermine.length} in Dienstags-Serie)`);
|
||||
|
||||
// ── 9. Nachricht ─────────────────────────────────────────────────────────────
|
||||
console.log('→ Beispiel-Nachricht…');
|
||||
const exMsg = await find('nachrichten', `verein_id = "${verein.id}"`);
|
||||
if (!exMsg) {
|
||||
await create('nachrichten', {
|
||||
verein_id: verein.id,
|
||||
autor_id: adminUser.id,
|
||||
betreff: 'Willkommen bei vereins.haus!',
|
||||
text: 'Liebe Mitglieder,\n\nwir haben unsere Vereinsverwaltung auf vereins.haus umgestellt. Hier findet ihr alle Termine, Nachrichten und Informationen rund um unseren Verein.\n\nBei Fragen wendet euch an den Vorstand.\n\nEuer Vorstand\nTSV Musterstadt 1983 e.V.',
|
||||
gruppe_ids: Object.values(gruppen),
|
||||
gesendet_am: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
// ── Zusammenfassung ──────────────────────────────────────────────────────────
|
||||
console.log('\n✓ Seed abgeschlossen!\n');
|
||||
console.log(' Verein: ', verein.name);
|
||||
console.log(' Login: vorstand@tsv-musterstadt.de / Test123456!');
|
||||
console.log(' Mitglieder:', mitgliederIds.length);
|
||||
console.log(' PocketBase:', PB_URL);
|
||||
Loading…
Add table
Add a link
Reference in a new issue