Files
libnovel/backend/migrations/20260414000002_missing_fields.go
Admin fd0f2afe16 feat: replace pb-init-v3.sh with PocketBase Go migrations
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>
2026-04-14 19:30:42 +05:00

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
})
}