pb-ext
March 3, 2026 ยท View on GitHub
Enhanced PocketBase server with monitoring, logging & API docs.
Core Features
- API Schema: Auto-generates OpenAPI docs UI for your endpoints
- Cron Tracking: Logs and monitors scheduled cron jobs
- System Monitoring: Real-time CPU, memory, disk, network, and runtime metrics
- Structured Logging: Complete logging with error tracking and request tracing
- Visitor Analytics: Track GDPR compliant visitors, page views, device types, and browsers
- PocketBase Integration: Uses PocketBase's auth system and styling
Access
- Admin panel:
127.0.0.1:8090/_
- pb-ext dashboard:
127.0.0.1:8090/_/_
Quick Start
๐ New to Golang and/or PocketBase? Read this beginner tutorial.
package main
import (
"flag"
"log"
app "github.com/magooney-loon/pb-ext/core"
"github.com/pocketbase/pocketbase/core"
)
func main() {
devMode := flag.Bool("dev", false, "Run in developer mode")
generateSpecsDir := flag.String("generate-specs-dir", "", "Generate OpenAPI specs into the provided directory and exit")
generateSpecVersion := flag.String("generate-spec-version", "", "Optional API version to generate (requires --generate-specs-dir)")
validateSpecsDir := flag.String("validate-specs-dir", "", "Validate OpenAPI specs from the provided directory and exit")
flag.Parse()
if *generateSpecsDir != "" {
gen := app.NewSpecGeneratorWithInitializer(func() (*app.APIVersionManager, error) {
return initVersionedSystem(), nil
})
if err := gen.Generate(*generateSpecsDir, *generateSpecVersion); err != nil {
log.Fatal(err)
}
return
}
if *validateSpecsDir != "" {
gen := app.NewSpecGeneratorWithInitializer(func() (*app.APIVersionManager, error) {
return initVersionedSystem(), nil
})
if err := gen.Validate(*validateSpecsDir); err != nil {
log.Fatal(err)
}
return
}
initApp(*devMode)
}
func initApp(devMode bool) {
var opts []app.Option
if devMode {
opts = append(opts, app.InDeveloperMode())
} else {
opts = append(opts, app.InNormalMode())
}
// Option 1: Use a custom PocketBase config
// pbConfig := &pocketbase.Config{
// DefaultDev: true,
// DefaultDataDir: "./custom_pb_data",
// }
// opts = append(opts, app.WithConfig(pbConfig))
// Option 2: Use an existing PocketBase instance
// pb := pocketbase.New()
// opts = append(opts, app.WithPocketbase(pb))
// Set custom port programmatically
// os.Args = []string{"app", "serve", "--http=127.0.0.1:9090"}
// Note: WithConfig and WithPocketbase cannot be used together
srv := app.New(opts...)
app.SetupLogging(srv)
registerCollections(srv.App())
registerRoutes(srv.App())
registerJobs(srv.App())
srv.App().OnServe().BindFunc(func(e *core.ServeEvent) error {
app.SetupRecovery(srv.App(), e)
return e.Next()
})
if err := srv.Start(); err != nil {
srv.App().Logger().Error("Fatal application error",
"error", err,
"uptime", srv.Stats().StartTime,
"total_requests", srv.Stats().TotalRequests.Load(),
"active_connections", srv.Stats().ActiveConnections.Load(),
"last_request_time", srv.Stats().LastRequestTime.Load(),
)
log.Fatal(err)
}
}
// Example models in cmd/server/collections.go
// Example routes in cmd/server/routes.go
// Example handlers in cmd/server/handlers.go
// Example cron jobs in cmd/server/jobs.go
//
// You can restructure Your project as You wish,
// just keep this main.go in cmd/server/main.go
//
// Build toolchain (pb-cli):
// go install github.com/magooney-loon/pb-ext/cmd/pb-cli@latest
//
// Need a pre-built Svelte5Kit starter template?
// https://github.com/magooney-loon/svelte-gui
//
// Ready for a production build deployment?
// https://github.com/magooney-loon/pb-deployer
go mod tidy
go install github.com/magooney-loon/pb-ext/cmd/pb-cli@latest
pb-cli --run-only
See **/*/README.md for detailed docs.
OpenAPI Spec Generation
Dev vs Production
- Development: Specs are generated at runtime via AST parsing - no disk files needed
- Production: Specs are generated at build time and read from disk (
dist/specs/)
Build pipeline
The pb-cli toolchain runs OpenAPI generation automatically for production builds:
pb-cli # Development mode (no spec generation)
pb-cli --build-only # Build frontend + generate specs
pb-cli --production # Production build with specs
For programmatic usage, see pkg/scripts/README.md.
Having issues with Your API Docs?
127.0.0.1:8090/api/docs/debug/ast
Reserved Collections
pb-ext creates the following PocketBase system collections automatically on startup. Do not create collections with these names in your own code.
| Collection | Purpose |
|---|---|
_analytics | Daily aggregated page view counters (one row per path/date/device/browser). Retention: 90 days. |
_analytics_sessions | Ring buffer of the 50 most recent visits for the Recent Activity display. No PII stored. |
_job_logs | Cron job execution logs (start time, end time, duration, status, output). Retention: 72 hours. |
Schema notes:
- All three collections are system collections (hidden from the PocketBase Collections UI).
_analyticsand_analytics_sessionsstore no personal data โ no IP, no user agent, no visitor ID. GDPR-compliant by design.- On upgrade from an old pb-ext version, incompatible schemas are automatically migrated at startup with no manual steps required.
Reserved Routes
pb-ext registers the following routes. Do not register your own routes at these paths.
Dashboard
| Method | Path | Auth | Description |
|---|---|---|---|
GET | /_/_ | Superuser | pb-ext health, analytics & jobs dashboard |
Cron Job API
All routes require superuser authentication.
| Method | Path | Description |
|---|---|---|
GET | /api/cron/jobs | List registered cron jobs |
POST | /api/cron/jobs/{id}/run | Trigger a job manually |
DELETE | /api/cron/jobs/{id} | Remove a job from the scheduler |
GET | /api/cron/status | Cron scheduler status |
POST | /api/cron/config/timezone | Update scheduler timezone |
GET | /api/cron/logs | Paginated job execution logs |
GET | /api/cron/logs/{job_id} | Logs for a specific job |
GET | /api/cron/logs/analytics | Aggregated job log statistics |
API Docs
| Method | Path | Description |
|---|---|---|
GET | /api/docs/versions | List registered API versions |
GET | /api/docs/debug/ast | AST parsing debug info |
GET | /api/docs/v{n} | Version metadata |
GET | /api/docs/v{n}/openapi.json | OpenAPI 3.0 spec |
GET | /api/docs/v{n}/swagger | Swagger UI |
Internal System Jobs
pb-ext registers these cron jobs automatically. They appear in the dashboard with the "System" badge.
| Job ID | Schedule | Description |
|---|---|---|
__pbExtLogClean__ | 0 0 * * * (daily midnight) | Purge _job_logs records older than 72 hours |
__pbExtAnalyticsClean__ | 0 3 * * * (daily 3 AM) | Purge _analytics rows older than 90 days |