Home
Softono

Pb Ext

Open source MIT Go
113
Stars
8
Forks
0
Issues
4
Watchers
3 months
Last Commit

 About Pb Ext

pocketbase boilerplate

Platforms

Web Self-hosted

Languages

Go

Need Help Installing Pb Ext?

We provide expert installation service for this software. Our team will install, configure, and secure Pb Ext on your server. plans start at just $30.

pb-ext

Enhanced PocketBase server with monitoring, logging & API docs.

pb-ext Screenshot_2026-02-10_14-42-37 Screenshot_2026-02-20_18-19-39

Ask DeepWiki

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).
  • _analytics and _analytics_sessions store 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