Adds a custom PocketBase binary (cmd/pocketbase) that embeds PocketBase as a Go framework with version-controlled migrations, replacing the fragile 419-line shell script. Migrations apply automatically on every `serve` startup. Migration 1 (20260414000001): full baseline schema — all 21 collections, both indexes on chapters_idx, and initial superuser creation from env vars. Migration 2 (20260414000002): adds three fields found in code but missing from the old script — books.rating, app_users.notify_new_chapters_push, book_comments.chapter. docker-compose: pocketbase service now uses the custom kalekber/libnovel-pocketbase image; pb-init one-shot container removed (migrations replace it entirely). Existing installs: run `migrate history-sync` once to mark migration 1 as done, then restart — migration 2 will apply the three previously missing fields. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
72 lines
2.0 KiB
Go
72 lines
2.0 KiB
Go
// Migration 2 — add fields present in code but absent from pb-init-v3.sh.
|
|
//
|
|
// Discovered by auditing every PocketBase field access in the Go backend
|
|
// and SvelteKit UI against the collection definitions in pb-init-v3.sh:
|
|
//
|
|
// books.rating (number) — written by WriteMetadata but never defined.
|
|
// app_users.notify_new_chapters_push (bool) — used in UI push-notification opt-in.
|
|
// book_comments.chapter (number) — used to scope comments to a chapter (0 = book-level).
|
|
//
|
|
// The check for field existence makes this migration safe to re-apply on
|
|
// a fresh install where migration 1 already created the collections without
|
|
// these fields.
|
|
package migrations
|
|
|
|
import (
|
|
"github.com/pocketbase/pocketbase/core"
|
|
m "github.com/pocketbase/pocketbase/migrations"
|
|
)
|
|
|
|
func init() {
|
|
m.Register(func(app core.App) error {
|
|
type addition struct {
|
|
collection string
|
|
field core.Field
|
|
}
|
|
additions := []addition{
|
|
{"books", &core.NumberField{Name: "rating"}},
|
|
{"app_users", &core.BoolField{Name: "notify_new_chapters_push"}},
|
|
{"book_comments", &core.NumberField{Name: "chapter"}},
|
|
}
|
|
for _, a := range additions {
|
|
coll, err := app.FindCollectionByNameOrId(a.collection)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if coll.Fields.GetByName(a.field.GetName()) != nil {
|
|
continue // already present — idempotent
|
|
}
|
|
coll.Fields.Add(a.field)
|
|
if err := app.Save(coll); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}, func(app core.App) error {
|
|
type removal struct {
|
|
collection string
|
|
field string
|
|
}
|
|
removals := []removal{
|
|
{"books", "rating"},
|
|
{"app_users", "notify_new_chapters_push"},
|
|
{"book_comments", "chapter"},
|
|
}
|
|
for _, r := range removals {
|
|
coll, err := app.FindCollectionByNameOrId(r.collection)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
f := coll.Fields.GetByName(r.field)
|
|
if f == nil {
|
|
continue
|
|
}
|
|
coll.Fields.RemoveById(f.GetId())
|
|
if err := app.Save(coll); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|