PocketBase is an open source Go backend that features an embedded database and an admin dashboard UI. As part of this project, I developed an app to manage a piggy bank associated with the sale of products. With this app the users can register how many products they bought and also register the amount they left (charge) in the piggy bank by indicating the amount and taking a photo as proof.

Preview

gui arduino interface built with electron

For your knowledge

This App is based on PocketBase that is an open source Go backend, consisting of:

embedded database (SQLite) with realtime subscriptions
built-in files and users management
convenient Admin dashboard UI
and simple REST-ish API

and Vue with the Quasar framework.

Project

You can find the code for this project on my Github.

Getting started

To run this project, you have two options: you can either utilize docker or docker-compose to execute it:

Docker

docker build -t pocketbase-app .
docker run -d --name pocketbase-app -v ./pb_data:/pocketbase/pb_data/ -p 127.0.0.1:8090:8090 pocketbase-app

Docker Compose

docker-compose up --build

After that use the following paths to navigate:

Running

Dev

If you wish to modify this project or adapt it to a different use case, you can make changes to both the backend and frontend by following the next steps:

Develop the backend:

go run main.go serve

Develop the frontend:

cd ui
vue serve

PocketBase Collections

PocketBase collections refer to the organized structures within the PocketBase database. A collection is a table that holds related data records. Each record within a collection represents an individual data entry, often with multiple fields or attributes. In this project I have two collections: users and transactions

users collection transactions collection

PocketBase API Rules

API Rules define the access controls for collections. To restrict user permissions, the following rules are necessary:

users api rules transactions api rules

PocketBase Event hooks

The standard way to modify the default PocketBase behavior is through event hooks in the Go code. For instance, to ensure that the balance is set to zero upon user creation, it is essential to employ the following event hook for validating the request data:

main.gomain.go
1
2
3
4
5
6
app.OnRecordBeforeCreateRequest().Add(func(e *core.RecordCreateEvent) error {
  if e.Record.Collection().Name == "users" {
    e.Record.Set("balance", 0)
  }
  return nil
})

To illustrate another scenario, when a transaction occurs, it is crucial to employ the following event hook to update the user’s balance.

main.gomain.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
app.OnRecordAfterCreateRequest().Add(func(e *core.RecordCreateEvent) error {
  if e.Record.Collection().Name == "transactions" {
    user := e.Record.GetString("user")

    records, err := app.Dao().FindRecordsByExpr("users",
      dbx.HashExp{"id": user},
    )
    if err != nil {
      if err := app.Dao().DeleteRecord(e.Record); err != nil {
        return err
      }
      return err
    }

    record := records[0]

    record.Set("balance", record.GetFloat("balance")+e.Record.GetFloat("amount"))
    err = app.Dao().SaveRecord(record)
    if err != nil {
      if err := app.Dao().DeleteRecord(e.Record); err != nil {
        return err
      }
      return err
    }
  }
  return nil
})

Vue

For a convenient interaction with the PocketBase API, it is recommended to use the official JavaScript SDK client. You can explore in here how I implemented the PocketBase JavaScript SDK client.