An open API service indexing awesome lists of open source software.

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

Awesome Lists containing this project

README

          

# 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](https://deepwiki.com/badge.svg)](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 |