Afteroffice Studio ID
ENTRY 011 Fold-out plate

A library across 56 school hubs

Aksara

A library system serving 56 school hubs from one application, each with its own data and rules.

LaravelPostgreSQLDockerBlademulti-tenant

The problem

Fifty-six school hubs recorded their library collections however they liked — mostly spreadsheets, some on paper. Nobody could answer a simple question like “how many copies do we hold in total” without first collecting files from 56 people. No hub was permitted to see another hub's data.

The user journey

  1. A hub librarian signs in and sees only their own collection — the separation is enforced in the data layer, not as a display filter.
  2. They search for a title, and if it isn't there, add it once as a bibliography record; each physical copy is then tracked as its own item with its own number.
  3. Members are registered with numbers generated automatically from the organisation code and academic year, ending the clashing manual numbering.
  4. Central staff open a distribution dashboard and see holdings across every hub on one screen.

What was built

A multi-tenant Laravel application on PostgreSQL, running in Docker on a server I operate. Tenant separation is enforced at the data layer rather than the view, so one hub cannot read another's records even by hitting a URL directly.

Architecture

Browser 56 hub · Blade
Caddy TLS · reverse proxy
Laravel Docker · multi-tenant
PostgreSQL Docker volume
Backup dump harian → Drive

The hard part

The hard part wasn't the application — it was moving the legacy data. The sources were messy and inconsistent between hubs, and once bad data lands in production, fixing it costs far more than slowing the migration down.

The outcome

  • 11,212 bibliography records and 44,909 items migrated into the new structure.
  • 5,593 members imported for one organisation, with automatic numbering replacing the manual scheme.
  • 56 hubs running on one application, one database, one deployment.

Commit record

commits364
active working days31
since2026-06-01

What isn't finished

Integration with the team's spreadsheets is still pending on their data being ready. I record that as unfinished, not as a shipped feature.

My role

Product, architecture, all implementation, data migration, and server operations.

Recorded by
Ihsan Nugraha
Checked
6 Aug 2026, 17:17 WIB
How to verify
Click any URL on this page
Recorded by