Skip to content

Drumee Schemas — multi-tenant MariaDB schema and migration tooling

The database layer of Drumee, an open-source, self-hosted collaboration platform: files, folder-native chat, video meetings and fine-grained permissions, running on infrastructure the owner controls. This repository holds every table, stored procedure, function and trigger it runs on, plus the tooling that applies them across a live fleet.

License: AGPL v3 MariaDB Self-hosted

Documentation · Self-hosting guides · Architecture · Discussions


Why this schema looks unusual

Most collaboration platforms put every tenant in one database and separate them with a tenant_id column. Drumee does not. Every workspace and every user gets its own MariaDB database, provisioned from a template at signup and torn down with the account.

That choice is what makes data sovereignty real rather than a policy promise: one tenant's data is a separate database that can be backed up, moved, exported or destroyed on its own, and a query cannot accidentally cross a tenant boundary because the boundary is the database, not a WHERE clause.

The cost is that a schema change is a fleet operation — a stored procedure has to be applied to every database of its class, not once to a shared table. That is what the tooling in bin/ exists for, and why the "one routine per file" rule below is not a style preference.

Who this repository is for

  • Self-hosting Drumee? You do not need this repo. Follow the self-hosting guides — the schema is installed for you.
  • Contributing a back-end change? Anything touching persistence lands here, and it lands as SQL, not as an ORM migration.
  • Evaluating the architecture? Start with Why this schema looks unusual above and the architecture docs.

Prerequisites

  • MariaDB, and a running Drumee instance you can safely break. The tooling reads that instance's own registry to discover which databases exist, so it cannot run against a bare server.
  • Node.jsbin/patch.js and the manifest tooling are Node.
  • The quickest disposable instance is the self-hosting quick start.

Quick start — read before you write

Every command here talks to live databases. Start by comparing two you already have, which only reads:

# Do two databases actually agree?
bin/compare-routines <db_a> <db_b>
bin/compare-tables-structure <db_a> <db_b>

Then apply a single routine to a single database:

bin/patch-from-file yellow_page/procedures/<area>/<name>.sql yp

⚠️ Read Care below before running anything that writes. In short: some files begin with DROP TABLE, common/ applies to the whole fleet, and a procedure whose signature changed must ship as name_v2.

Architecture at a glance

              yp  ── the central directory
                    identity · hubs · media · sharing · billing
                     │
      ┌──────────────┼──────────────┐
      │              │              │
  one database   one database   mailserver
   per user      per workspace   mail routing
      │              │
      └─── common/ ──┘
     routines applied to every class

templates/ holds the schema each new user and workspace database is built from; bin/build-seeds and bin/make-templates maintain them. A pool of pre-built databases is kept warm so signup does not wait on a CREATE DATABASE.

Related repositories

Repository What it is
server-team The back-end that calls these routines
server-core Request lifecycle, sessions, ACL, meta filesystem
setup-schemas Bootstraps a fresh instance's database and seed data
debian Builds and deploys Drumee — container and Debian packages
ui-team The workspace front-end

Browse all repositories


The one rule

One routine per file. Every .sql file contains exactly one stored procedure, function, table definition or trigger. No exceptions. The patch tooling relies on it, and so does the ability to review a change.

How the schema is organised

Drumee is multi-tenant: a workspace and a user each get their own database, built from a template. The directories map to those database classes:

Directory Database class Contains
yellow_page/ yp The central directory — identity, hubs, media, sharing, billing
hub/ hub Per-workspace schema
drumate/ drumate Per-user schema
common/ common Routines applied to every database class
mailserver/ Mail server schema
utils/, udf/ Helper routines and user-defined functions
templates/ Schema templates used to provision new databases

Applying changes

Patch a single routine:

bin/patch-from-file <routine-file-path> <db_name|db_class>

db_class is one of yp, common, hub or drumate.

Patch everything listed in a manifest. With no argument it reads patches/manifest.txt:

bin/patch-from-manifest
bin/patch-from-manifest --manifest=/path/to/manifest.txt

Generate a manifest from the files that changed between two commits:

bin/make-manifest <git_hash1> <git_hash2>

Rebuild the schema templates from a live installation. It picks an active database of each class and dumps it into factory/ (or the directory you name):

bin/make-templates [factory-dir]

This rewrites files in this repository — see Care.

Other tooling

Script What it does
bin/compare-routines Diff routines between two databases
bin/compare-tables-structure Diff table structures
bin/scan-tables-structure Rewrites the table .sql files in this repo from a live database — not a read-only dump
bin/lookup-errors Search log files for known MariaDB errors — bin/lookup-errors <logfile>...
bin/build-seeds Build the seed databases
bin/make-changelog Generate a changelog entry
bin/update-manifest Regenerate patches/manifest.txt from changelog.txt for a date range

Care

These scripts write to live databases. A few things worth knowing before you run one:

  • Some files under templates/ and the table definitions begin with DROP TABLE. Read a table file before applying it — applying one to a populated database will destroy its contents.
  • common/ is a fleet apply. A routine placed there goes to every database of every class, not to one — so it is not a patch-from-file job.
  • bin/scan-tables-structure and bin/make-templates rewrite files in this repository from a live database. They are maintenance tools, not inspection tools; run them only when you mean to regenerate the checked-in SQL.
  • A breaking change to a stored procedure should ship as a new version (name_v2) rather than a redefinition, so running instances keep working until the callers are updated.
  • The filename must match the routine name inside it.

Contributing

See the org CONTRIBUTING guide. Questions: Discussions.

License

AGPL-3.0 — see LICENSE.

Mobile push registration v2

The ordered deployment route is the patches/manifest.txt entry set. Table ownership lives under yellow_page/tables, registration transitions and send-eligibility queries live under yellow_page/procedures/deviceregistration, and the executable contract is tests/notification-v2-schema.sh. Hub recipient resolution uses the dedicated, database-bounded hub_members_for_mobile_push procedure; its page contract is covered by tests/mobile-push-member-page.sh.

Full Notification history keeps acknowledgement and removal separate: contact_activity.dismissed_at is the compatible read marker and hidden_at is explicit removal from Activity history; MFS uses mfs_ack and mfs_dismissed respectively. Chat/teamchat/ticket acknowledgement uses the privacy-safe notification_activity_history table, which stores opaque rollup identity and timing only. The disposable index/removal/history contracts are owned by tests/notification-feed-index.sh and tests/notification-feed-dismissal.sh, plus tests/notification-rollup-history.sh. Per-user Notification Save stores only opaque activity hashes in notification_activity_bookmark; bounded concurrent writes and removal are owned by tests/notification-activity-bookmark.sh.

The durable boundary is compare-and-set ownership and state versioning: registration changes, logout, account switches, and provider invalidation must match the server-issued registration/binding/state tuple. UID-bound tombstones make those transitions replay-safe, so delayed work cannot mutate a newer binding. Only active, unexpired v2 registrations selected by the send procedures are eligible; legacy anonymous registration rows are excluded. Push credential material stays inside the schema/server boundary and must not be copied into documentation, logs, fixtures, or migration evidence.

About

Database schema and stored procedures for Drumee

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages