// Package pocketbase — хранилище задач и файлов поверх встроенной PocketBase. // // Приложение поднимается библиотекой, а не её набором команд: разбор флагов и // мягкая остановка остаются нашими, а ключ `-c config.toml` — объявленный // контракт запуска. package pocketbase import ( "fmt" pb "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/core" ) // Имена коллекций. Они же — часть пути к файлу в раскладке хранилища и часть // адреса ссылки на него, поэтому меняются только новым шагом схемы. const ( FilesCollection = "files" JobsCollection = "transcribe_jobs" ) // New создаёт приложение хранилища на заданном каталоге данных и приводит его в // рабочее состояние: открывает базу, читает настройки и накатывает непринятые // шаги схемы. // // Схема накатывается **здесь**, а не оставляется серверу, хотя тот и гоняет // непринятые шаги сам. Причина в порядке: воркеры стартуют раньше сервера, и на // чистом каталоге их первые опросы приходились бы на несуществующую таблицу — // отказ в журнале и в счётчике на каждую секунду до конца накатки. func New(dataDir string) (*pb.PocketBase, error) { app := pb.NewWithConfig(pb.Config{ DefaultDataDir: dataDir, HideStartBanner: true, }) if err := app.Bootstrap(); err != nil { return nil, fmt.Errorf("failed to bootstrap storage: %w", err) } if err := app.RunAllMigrations(); err != nil { return nil, fmt.Errorf("failed to apply storage schema: %w", err) } return app, nil } // MustFindCollection достаёт коллекцию по имени. Отсутствие коллекции здесь — // не отказ окружения, а несделанный шаг схемы: сервис до этой точки не доходит, // потому что Serve накатывает схему прежде, чем поднять сервер. func findCollection(app core.App, name string) (*core.Collection, error) { collection, err := app.FindCollectionByNameOrId(name) if err != nil { return nil, fmt.Errorf("failed to find collection %s: %w", name, err) } return collection, nil }