Seed the dev PocketBase with example content on a fresh volume
This commit is contained in:
1 parent
47d9841532
commit
d5372963bb
3 files changed
+65
-1
No files matched your search
+6
-1
@@ -13,4 +13,9 @@ riderModule.iml
|
||||
/backup/
|
||||
|
||||
# Secrets (Gitea-Token o.ae.) -- niemals ins Repo. Vorlage: .env.example
|
||||
.env
|
||||
.env
|
||||
|
||||
# PocketBase runtime data (SQLite DB, uploads) -- may hold personal data and is
|
||||
# per-environment state, not source. The dev seed lives in pb/pb_migrations/ and
|
||||
# IS checked in; only the data folder is ignored.
|
||||
/pb/pb_data/
|
||||
@@ -24,6 +24,12 @@ services:
|
||||
# tag clears the inherited bind mount so only this volume applies.
|
||||
- !reset null
|
||||
- pb_data_dev:/pb_data
|
||||
# Dev-only seed: PocketBase runs the JS migrations in this folder on start.
|
||||
# On a fresh pb_data_dev volume it creates the content collections and fills
|
||||
# them with example records (see pb/pb_migrations). Guarded to be a no-op on
|
||||
# a populated volume. Deliberately NOT in the base file -- production is
|
||||
# seeded by hand, never from this repo.
|
||||
- ./pb/pb_migrations:/pb_migrations
|
||||
|
||||
eb-web:
|
||||
# Build from local source instead of pulling the registry image, so local code
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/// <reference path="../pb_data/types.d.ts" />
|
||||
|
||||
// Dev-only seed: creates the four content collections and fills them with example
|
||||
// records, so a fresh local stack shows a populated site on the first
|
||||
// `docker compose up`. Mounted into the container ONLY by compose.dev.yaml (bind
|
||||
// `./pb/pb_migrations:/pb_migrations`), so it never runs against production.
|
||||
//
|
||||
// Two guarded phases, both idempotent:
|
||||
// 1. Schema -- a collection is created only if it does not exist yet.
|
||||
// 2. Records -- a collection is filled only while it is still empty.
|
||||
// So editing content locally, or pointing this at a populated volume, is safe:
|
||||
// existing collections and existing data are left untouched.
|
||||
//
|
||||
// Generated from the local dev database. To refresh the seed, re-export and
|
||||
// regenerate this file rather than hand-editing the schema blocks.
|
||||
migrate((app) => {
|
||||
const schema = {"posts":{"id":"pbc_1125843985","listRule":"","viewRule":"","createRule":null,"updateRule":null,"deleteRule":null,"name":"posts","type":"base","fields":[{"autogeneratePattern":"[a-z0-9]{15}","help":"","hidden":false,"id":"text3208210256","max":15,"min":15,"name":"id","pattern":"^[a-z0-9]+$","presentable":false,"primaryKey":true,"required":true,"system":true,"type":"text"},{"help":"","hidden":false,"id":"date2862495610","max":"","min":"","name":"date","presentable":false,"required":false,"system":false,"type":"date"},{"autogeneratePattern":"","help":"","hidden":false,"id":"text724990059","max":0,"min":0,"name":"title","pattern":"","presentable":false,"primaryKey":false,"required":true,"system":false,"type":"text"},{"autogeneratePattern":"","help":"","hidden":false,"id":"text3685223346","max":0,"min":0,"name":"body","pattern":"","presentable":false,"primaryKey":false,"required":false,"system":false,"type":"text"},{"autogeneratePattern":"","help":"","hidden":false,"id":"text2560465762","max":0,"min":0,"name":"slug","pattern":"","presentable":false,"primaryKey":false,"required":true,"system":false,"type":"text"},{"help":"","hidden":false,"id":"bool1001664029","name":"public","presentable":false,"required":false,"system":false,"type":"bool"}],"indexes":[],"created":"2026-09-23 10:38:12.035Z","updated":"2026-09-23 11:25:30.698Z","system":false},"events":{"id":"pbc_1687431684","listRule":"","viewRule":"","createRule":null,"updateRule":null,"deleteRule":null,"name":"events","type":"base","fields":[{"autogeneratePattern":"[a-z0-9]{15}","help":"","hidden":false,"id":"text3208210256","max":15,"min":15,"name":"id","pattern":"^[a-z0-9]+$","presentable":false,"primaryKey":true,"required":true,"system":true,"type":"text"},{"help":"","hidden":false,"id":"date2675529103","max":"","min":"","name":"start","presentable":false,"required":true,"system":false,"type":"date"},{"help":"","hidden":false,"id":"date16528305","max":"","min":"","name":"end","presentable":false,"required":false,"system":false,"type":"date"},{"autogeneratePattern":"","help":"","hidden":false,"id":"text724990059","max":0,"min":0,"name":"title","pattern":"","presentable":false,"primaryKey":false,"required":true,"system":false,"type":"text"},{"autogeneratePattern":"","help":"","hidden":false,"id":"text1587448267","max":0,"min":0,"name":"location","pattern":"","presentable":false,"primaryKey":false,"required":false,"system":false,"type":"text"},{"autogeneratePattern":"","help":"","hidden":false,"id":"text3485334036","max":0,"min":0,"name":"note","pattern":"","presentable":false,"primaryKey":false,"required":false,"system":false,"type":"text"},{"help":"","hidden":false,"id":"bool1001664029","name":"public","presentable":false,"required":false,"system":false,"type":"bool"}],"indexes":[],"created":"2026-09-23 10:38:12.110Z","updated":"2026-09-23 10:38:12.110Z","system":false},"pages":{"id":"pbc_3945946014","listRule":"","viewRule":"","createRule":null,"updateRule":null,"deleteRule":null,"name":"pages","type":"base","fields":[{"autogeneratePattern":"[a-z0-9]{15}","help":"","hidden":false,"id":"text3208210256","max":15,"min":15,"name":"id","pattern":"^[a-z0-9]+$","presentable":false,"primaryKey":true,"required":true,"system":true,"type":"text"},{"autogeneratePattern":"","help":"","hidden":false,"id":"text724990059","max":0,"min":0,"name":"title","pattern":"","presentable":false,"primaryKey":false,"required":true,"system":false,"type":"text"},{"autogeneratePattern":"","help":"","hidden":false,"id":"text3685223346","max":0,"min":0,"name":"body","pattern":"","presentable":false,"primaryKey":false,"required":false,"system":false,"type":"text"},{"help":"","hidden":false,"id":"select1587448267","maxSelect":1,"name":"location","presentable":false,"required":false,"system":false,"type":"select","values":["header","footer"]},{"help":"","hidden":false,"id":"number4113142680","max":null,"min":null,"name":"order","onlyInt":false,"presentable":false,"required":false,"system":false,"type":"number"},{"autogeneratePattern":"","help":"","hidden":false,"id":"text2560465762","max":0,"min":0,"name":"slug","pattern":"","presentable":false,"primaryKey":false,"required":true,"system":false,"type":"text"},{"help":"","hidden":false,"id":"select1203373331","maxSelect":3,"name":"embed","presentable":false,"required":false,"system":false,"type":"select","values":["posts","events","faqs"]},{"help":"","hidden":false,"id":"bool1001664029","name":"public","presentable":false,"required":false,"system":false,"type":"bool"}],"indexes":[],"created":"2026-09-23 11:25:35.648Z","updated":"2026-09-23 11:25:35.648Z","system":false},"faqs":{"id":"pbc_2923026773","listRule":"","viewRule":"","createRule":null,"updateRule":null,"deleteRule":null,"name":"faqs","type":"base","fields":[{"autogeneratePattern":"[a-z0-9]{15}","help":"","hidden":false,"id":"text3208210256","max":15,"min":15,"name":"id","pattern":"^[a-z0-9]+$","presentable":false,"primaryKey":true,"required":true,"system":true,"typeLine truncated
|
||||
|
||||
const records = {
|
||||
pages: [{"body":"# Vorstandsteam\n\nDer Elternbeirat der IGMH vertritt die Interessen aller Eltern gegenüber der Schulleitung und dem Kollegium. Wir treffen uns regelmäßig, bringen Anliegen aus der Elternschaft ein und begleiten das Schulleben aktiv.\n\n## Vorstand\n\n- **Vorsitz** — Anke Berger\n- **Stellvertretung** — Murat Yılmaz\n- **Kasse** — Sabine Krause\n- **Schriftführung** — Thomas Heinrich\n\n## So erreichen Sie uns\n\nAm schnellsten per Mail über unsere [Kontaktseite](/contact). Zu unseren öffentlichen Sitzungen sind alle Eltern herzlich eingeladen — die Termine finden Sie unter [Termine](/events).","embed":[],"location":"header","order":2,"public":true,"slug":"board","title":"Vorstandsteam"},{"body":"# Förderverein\n\nDer Förderverein der IGMH unterstützt Projekte, für die im regulären Schulhaushalt kein Geld vorgesehen ist: von der Ausstattung der Bibliothek über Pausenspielgeräte bis zu Zuschüssen für Klassenfahrten, damit kein Kind aus finanziellen Gründen zurückbleibt.\n\n## Mitglied werden\n\nDer Jahresbeitrag beträgt 24 € — jeder Euro fließt direkt in die Arbeit an der Schule. Den Aufnahmeantrag finden Sie unter [Downloads](/downloads).\n\n## Spenden\n\nSpenden sind jederzeit willkommen und werden auf Wunsch mit einer Zuwendungsbestätigung quittiert. Sprechen Sie uns über die [Kontaktseite](/contact) an.","embed":[],"location":"header","order":3,"public":true,"slug":"patrons","title":"Förderverein"},{"body":"# Häufige Fragen\n\nHier beantworten wir die Fragen, die uns am häufigsten erreichen. Ausführliche Antworten gibt es auf den Unterseiten:\n\n- [Mensa und Mittagessen](/faq-mensa)\n- [Schließfächer](/faq-schliessfach)\n- [Eltern-Euro](/faq-elterneuro)\n- [Elternarbeit und Mitmachen](/faq-elternarbeit)\n\nIhre Frage ist nicht dabei? Schreiben Sie uns über die [Kontaktseite](/contact).","embed":[],"location":"header","order":6,"public":true,"slug":"faqs","title":"FAQ"},{"body":"# Downloads\n\nFormulare und Dokumente zum Herunterladen:\n\n- Aufnahmeantrag Förderverein\n- Einzugsermächtigung\n- Erstattungsformular Klassenkasse\n\nFehlt ein Dokument? Melden Sie sich über die [Kontaktseite](/contact).","embed":[],"location":"header","order":7,"public":true,"slug":"downloads","title":"Downloads"},{"body":"# Kontakt\n\nSie erreichen den Elternbeirat der IGMH per E-Mail:\n\n**elternbeirat@igmh.example**\n\nWir antworten in der Regel innerhalb weniger Tage. Bei dringenden schulischen Angelegenheiten wenden Sie sich bitte direkt an das Sekretariat der Schule.","embed":[],"location":"footer","order":1,"public":true,"slug":"contact","title":"Kontakt"},{"body":"# Impressum\n\nAngaben gemäß § 5 DDG\n\n**Elternbeirat der IGMH**\nVertreten durch den Vorstand\n\nKontakt: siehe [Kontaktseite](/contact)\n\nVerantwortlich für den Inhalt nach § 18 Abs. 2 MStV: der Vorstand des Elternbeirats.","embed":[],"location":"footer","order":2,"public":true,"slug":"imprint","title":"Impressum"},{"body":"# Datenschutz\n\nDer Schutz Ihrer Daten ist uns wichtig. Diese Website kommt ohne externe Dienste aus: keine Analysewerkzeuge, keine eingebundenen Karten oder Videos, keine Schriften von fremden Servern.\n\n## Server-Logs\n\nBeim Aufruf werden technisch notwendige Zugriffsdaten (IP-Adresse, Zeitpunkt, aufgerufene Seite) kurzzeitig verarbeitet, um den Betrieb sicherzustellen. Eine Zusammenführung mit anderen Daten findet nicht statt.\n\n## Ihre Rechte\n\nFragen zum Datenschutz richten Sie bitte an die [Kontaktseite](/contact).","embed":[],"location":"footer","order":3,"public":true,"slug":"privacy","title":"Datenschutz"},{"body":"# Mensa und Mittagessen\n\n## Wie melde ich mein Kind zum Mittagessen an?\n\nDie Anmeldung läuft über das Bestellsystem der Schule. Die Zugangsdaten erhalten Sie zu Schuljahresbeginn über die Klassenleitung.\n\n## Was kostet ein Essen?\n\nEin Mittagessen kostet aktuell 4,20 €. Für Familien mit Anspruch auf Leistungen nach dem Bildungs- und Teilhabepaket ist das Essen kostenfrei — sprechen Sie das Sekretariat an.\n\n## Gibt es vegetarische Gerichte?\n\nJa, täglich steht mindestens ein vegetarisches Gericht zur Wahl.\n\nWeitere Fragen? [Schreiben Sie uns.](/contact)","embed":[],"location":"","order":0,"public":true,"slug":"faq-mensa","title":"Mensa und Mittagessen"},{"body":"# Schließfächer\n\n## Wie bekommt mein Kind ein Schließfach?\n\nSchließfächer werden über einen externen Anbieter gemietet. Das Anmeldeformular liegt bei den [Downloads](/downloads).\n\n## Was kostet die Miete?\n\nDie Miete beträgt rund 15 € pro Schuljahr zuzüglich einer Kaution, die bei Rückgabe erstattet wird.\n\n## Der Schlüssel ist weg — was nun?\n\nWenden Sie sich an den Anbieter; die Kontaktdaten stehen auf dem Mietvertrag. Bei Fragen hilft auch der [Elternbeirat](/contact).","embed":[],"location":"","order":0,"public":true,"slug":"faq-schliessfach","title":"Schließfächer"},{"body":"# Eltern-Euro\n\n## Was ist der Eltern-Euro?\n\nDer ElterLine truncated
|
||||
,
|
||||
posts: [{"body":"## Neuer Vorstand gewählt\n\nAuf der Mitgliederversammlung wurde der Vorstand des Elternbeirats für das Schuljahr **2026/27** neu gewählt. Wir danken dem bisherigen Team für sein Engagement und freuen uns auf die gemeinsame Arbeit.\n\nDie neuen Ansprechpartnerinnen und Ansprechpartner finden Sie auf der Seite [Vorstandsteam](/board).","date":"2026-09-24 18:00:00.000Z","public":true,"slug":"new-board-2026","title":"Neuer Vorstand für das Schuljahr 2026/27 gewählt"},{"body":"## Herbstbasar am 22. November\n\nAm **22. November** findet wieder unser beliebter Herbstbasar statt. Es gibt selbst gebackene Kuchen, Bastelstände und ein Bühnenprogramm der Klassen.\n\nWer einen Stand betreuen oder etwas beisteuern möchte, meldet sich bitte bis zum 10. November über das [Kontaktformular](/contact) an. Wir freuen uns über jede helfende Hand!","date":"2026-09-18 09:30:00.000Z","public":true,"slug":"herbstbasar-2026","title":"Herbstbasar am 22. November – jetzt anmelden"},{"body":"## Mehr Auswahl beim Mittagessen\n\nAb den Herbstferien erweitert der Caterer das Angebot in der Mensa: Es gibt künftig **täglich ein zusätzliches vegetarisches Gericht** sowie eine größere Salatauswahl.\n\nRückmeldungen zum Essen nehmen wir gerne über den Elternbeirat auf – sprechen Sie uns an.","date":"2026-09-10 12:15:00.000Z","public":true,"slug":"mensa-mehr-auswahl","title":"Mehr Auswahl beim Mittagessen ab den Herbstferien"},{"body":"## Besuchen Sie unseren Stand\n\nAm kommenden **Elternsprechtag** ist der Elternbeirat mit einem Info-Stand im Foyer vertreten. Kommen Sie vorbei – wir beantworten Fragen rund um die Elternarbeit und freuen uns über neue Mitstreiterinnen und Mitstreiter.\n\nAlle Termine finden Sie unter [Termine](/events).","date":"2026-09-02 08:00:00.000Z","public":true,"slug":"elternsprechtag-stand","title":"Elternbeirat am Elternsprechtag – besuchen Sie unseren Stand"},{"body":"## Neue Spielgeräte für den Pausenhof\n\nDank der Einnahmen aus dem letzten Basar und der Unterstützung des [Fördervereins](/patrons) konnten neue Spielgeräte für den Pausenhof angeschafft werden.\n\nDie Kinder haben die Klettergerüste bereits begeistert in Beschlag genommen.","date":"2026-08-28 16:45:00.000Z","public":true,"slug":"neue-spielgeraete","title":"Neue Spielgeräte für den Pausenhof"}]
|
||||
,
|
||||
events: [{"end":"","location":"Aula","note":"Gäste sind willkommen. Um Anmeldung im Sekretariat wird gebeten.","public":true,"start":"2026-10-08 19:30:00.000Z","title":"Elternbeiratssitzung"},{"end":"2026-10-20 18:30:00.000Z","location":"Klassenräume","note":"Terminvergabe über das Schulportal.","public":true,"start":"2026-10-20 16:00:00.000Z","title":"Elternsprechtag"},{"end":"2026-11-22 13:00:00.000Z","location":"Schulhof","note":"Kuchenspenden willkommen.","public":true,"start":"2026-11-22 09:00:00.000Z","title":"Herbstbasar"},{"end":"2027-01-06 00:00:00.000Z","location":"","note":"","public":true,"start":"2026-12-19 00:00:00.000Z","title":"Weihnachtsferien"},{"end":"","location":"Mensa","note":"Kennenlernen bei Butterbrezeln und Kaffee.","public":true,"start":"2026-09-10 18:00:00.000Z","title":"Willkommensabend der neuen Fünftklässler"}]
|
||||
,
|
||||
faqs: [{"answer":"Die Anmeldung läuft über das Bestellsystem der Schule. Die Zugangsdaten erhalten Sie zu Schuljahresbeginn über die Klassenleitung.","public":true,"question":"Wie melde ich mein Kind zum Mittagessen an?","topic":"mensa"},{"answer":"Ein Mittagessen kostet aktuell **4,20 €**. Für Familien mit Anspruch auf Leistungen nach dem Bildungs- und Teilhabepaket ist das Essen kostenfrei – sprechen Sie das Sekretariat an.","public":true,"question":"Was kostet ein Mittagessen?","topic":"mensa"},{"answer":"Ja, täglich steht mindestens ein vegetarisches Gericht zur Wahl.","public":true,"question":"Gibt es vegetarische Gerichte?","topic":"mensa"},{"answer":"Schließfächer werden über einen externen Anbieter gemietet. Das Anmeldeformular liegt bei den [Downloads](/downloads).","public":true,"question":"Wie bekommt mein Kind ein Schließfach?","topic":"schliessfach"},{"answer":"Die Miete beträgt rund 15 € pro Schuljahr zuzüglich einer Kaution, die bei Rückgabe erstattet wird.","public":true,"question":"Was kostet die Miete?","topic":"schliessfach"},{"answer":"Wenden Sie sich an den Anbieter; die Kontaktdaten stehen auf dem Mietvertrag. Bei Fragen hilft auch der [Elternbeirat](/contact).","public":true,"question":"Der Schlüssel ist verloren – was nun?","topic":"schliessfach"},{"answer":"Der Eltern-Euro ist ein **freiwilliger** Beitrag, mit dem kleinere Anschaffungen für die Klassen unkompliziert finanziert werden – etwa Bastelmaterial oder Ausflüge.","public":true,"question":"Was ist der Eltern-Euro?","topic":"elterneuro"},{"answer":"Nein. Der Beitrag ist ausdrücklich freiwillig, und niemand wird bei Nichtzahlung benachteiligt.","public":true,"question":"Ist der Beitrag verpflichtend?","topic":"elterneuro"},{"answer":"Ob Schulfest, Basar oder eine helfende Hand bei Ausflügen – über jede Unterstützung freuen wir uns. Melden Sie sich einfach über die [Kontaktseite](/contact).","public":true,"question":"Wie kann ich mich engagieren?","topic":"elternarbeit"},{"answer":"Nein. Viele Aufgaben erledigen Eltern, die einfach mithelfen möchten, ganz ohne Amt.","public":true,"question":"Muss ich in den Elternbeirat gewählt sein, um zu helfen?","topic":"elternarbeit"}]
|
||||
,
|
||||
}
|
||||
|
||||
// Phase 1: schema. Create any collection that is not present yet.
|
||||
for (const name of Object.keys(schema)) {
|
||||
try {
|
||||
app.findCollectionByNameOrId(name)
|
||||
} catch {
|
||||
app.save(new Collection(schema[name]))
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 2: records. Fill a collection only while it is still empty, so a
|
||||
// populated volume (or, should this ever run there, production) is untouched.
|
||||
for (const [name, rows] of Object.entries(records)) {
|
||||
if (app.countRecords(name) > 0) continue
|
||||
const collection = app.findCollectionByNameOrId(name)
|
||||
for (const data of rows) {
|
||||
const record = new Record(collection)
|
||||
record.load(data)
|
||||
app.save(record)
|
||||
}
|
||||
}
|
||||
}, (app) => {
|
||||
// Down: intentionally a no-op. This seed is a dev convenience; to start over,
|
||||
// drop the whole dev volume: `docker volume rm eb-stack_pb_data_dev`.
|
||||
})
|
||||
Reference in new issue
Block a user