https://github.com/magooney-loon/pb-ext
pocketbase boilerplate
https://github.com/magooney-loon/pb-ext
analytics openapi pocketbase sqlite web-server
Last synced: 8 days ago
JSON representation
pocketbase boilerplate
- Host: GitHub
- URL: https://github.com/magooney-loon/pb-ext
- Owner: magooney-loon
- License: mit
- Created: 2025-04-25T19:58:14.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2026-02-25T14:40:29.000Z (14 days ago)
- Last Synced: 2026-02-25T18:27:05.666Z (14 days ago)
- Topics: analytics, openapi, pocketbase, sqlite, web-server
- Language: Go
- Homepage: https://pkg.go.dev/github.com/magooney-loon/pb-ext
- Size: 1.56 MB
- Stars: 98
- Watchers: 4
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-pocketbase - pb-ext - Enhanced PocketBase server with monitoring, logging & API docs.  (Go Plugins)
README
# pb-ext
Enhanced PocketBase server with monitoring, logging & API docs.

[](https://deepwiki.com/magooney-loon/pb-ext)
## 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:
```bash
127.0.0.1:8090/_
```
- pb-ext dashboard:
```bash
127.0.0.1:8090/_/_
```
## Quick Start
> 🆕 New to Golang and/or PocketBase? [Read this beginner tutorial](TUTORIAL.md).
```go
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
```
```bash
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 & Embedding
### Build pipeline integration
The pb-cli toolchain runs OpenAPI generation + validation automatically before server compilation. First install it globally:
```bash
go install github.com/magooney-loon/pb-ext/cmd/pb-cli@latest
```
Then use it in your project:
```bash
pb-cli # Development mode
pb-cli --build-only # Build frontend only
pb-cli --production # Production build
```
For programmatic usage, see `pkg/scripts/README.md`.
Having issues with Your API Docs?
```bash
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 |