From 0.48 to 0.49
What to check when upgrading from better-supabase 0.48 to 0.49. The renames left open by the cleanup finish, notifications gain digests and the statuses held and digested, new blocks declare tenant default seeds, maintenance runs without pg_cron, billing keeps native subscriptions and accounting recognizes revenue over time.
0.49.0 finishes the renames that ADR 0130 left open, adds the commissions and
referrals blocks, and gives several blocks new tables, columns and functions.
Run better-supabase upgrade to rename the table and to copy stored action
items into tasks, then generate a migration with db diff for the rest.
| Section | Needs code |
|---|---|
| Permission actions | Rename keys in permissions and in tokens |
| Activity note actions | Run upgrade with the tasks block installed |
| E-invoice deliveries | Run upgrade; rename EINVOICE_* hint checks |
| Seeds and tenant defaults | Run db diff, then call seed_tenant_defaults |
| Maintenance without pg_cron | Install housekeeping, schedule maintenanceTimer |
| Notification digests | Run db diff; widen an adopted delivery status check |
| Native billing | Run db diff |
| Revenue recognition | Run db diff |
| Drive transfers | Pass the service role for offboarding |
Permission actions
The actions of the operations model use the verbs of the rest of the convention. The config types accept only the new names; delegated tokens and stored configs that carry an old name still resolve, so nothing breaks until you write the config again.
| Old action | New action |
|---|---|
view | read |
viewAll | readAll |
edit | write |
admin | manage |
viewSensitive | readSensitive |
Activity note actions
EngagementNotes.actionItems is now actionTaskIds: each action item is a task
of the tasks block, linked through the table activity_note_actions. The
action_items column goes away. The upgrade step creates one task per stored
item and drops the column. It stops with instructions when the tasks block is
not installed; install it first.
E-invoice deliveries
The table invoice_e_deliveries is now e_invoice_deliveries, with its
indexes and policies, and the hint codes EINVOICE_* are E_INVOICE_*. The
upgrade step renames the table in place, so no rows move. The table
invoice_e_endpoints keeps its name: it is the one documented exception in
ADR 0206.
Seeds and tenant defaults
The organizations block installs a seeds module with
seed_tenant_defaults(tenant, variants, locale). It calls the
seed_<block>_defaults function of every installed block that declares rows, in
install order, and create_organization calls it for a new organization unless
database.seed.defaults is false or its onCreate is false.
Blocks that declare defaults:
pipelinesdeclares the default pipeline and stage template of every record type without ascope, with theb2b-salesandrecruitingvariants.accountingdeclares its dimensions, thegenericchart and thenl-rgsDutch chart.permissionsadds the catalog rolesowner,adminandmemberwhen the roles table lacks them.inboxcreates a Help inbox on the in-app channel.attachmentscreates the document typescontract,invoice,receipt,identity,reportandother.calendarcreates a Public holidays calendar for the localesnl,de,fr,en-gbanden-us, with an all-day event per holiday for the years 2026 to 2030.
Apply the new functions with db diff, then call seed_tenant_defaults for the
organizations that should get the rows. Named presets now seed variants: crm
seeds b2b-sales, ats seeds recruiting and erp seeds the generic chart,
written under database.seed.defaults.variants. Design format 9 adds seeds
with sample: { size, seed }, variants and locale, and init --preset and
add --preset write all of it to the config.
Doctor reports BS354 when a declared default never reaches a new organization,
BS355 when a configured variant is not declared, and BS356 when a generated
sample file sits outside database.seed.sample.output.
Maintenance without pg_cron
maintenanceTimer and maintenanceTick in better-supabase/blocks/queue run
better_supabase.maintenance() from the block_ticks queue, and skip the run
when pg_cron already has it. support, usage and webhooks-out now register
their cleanups with the housekeeping module, which becomes a requirement of
those three modules. Doctor reports BS510 when the housekeeping module is
installed and nothing schedules maintenance().
Notification digests
notification_preferences gains a cadence: immediate, daily, weekly or
off. A daily or weekly delivery is held, and the digest_run housekeeping job
folds held deliveries into notification_digests. createNotificationDigests
sends each digest as one email through the mail-sync mailer, and
set_notification_cadence sets the choice.
Run db diff to pick up the column, the table and the functions. The
notifications block also writes two new delivery statuses: held for a
delivery that waits for a digest, and digested for one folded into a digest.
The block's own table accepts them. When the deliveries live in your own table,
its status check must accept pending, sent, failed, skipped, held
and digested; a check that predates digests rejects a held delivery and the
send fails. Doctor reports such a check as
BS361. Widen the check, or add the values to the
enum, and the block keeps working. The
notifications guide has the flow.
The consents block adds requires_consent(subject_type, subject_id, purpose_key) and a consents contribution key for system purposes. sequences
email steps take consentPurpose, and send in notifications takes
consentPurpose; both skip a send while the subject has no consent.
Native billing
billing keeps subscriptions in Postgres: billing_native_subscriptions holds
a plan, a price in minor units, a quantity and the period, independent of
Stripe. create_native_subscription, prorate_change and
cancel_native_subscription are service-role functions, and
createNativeSubscriptions in better-supabase/blocks/billing calls them.
prorate_change returns the credit, charge and net of a mid-period change and,
with the ledger block installed, posts the net as one billing.proration
transaction. Run db diff to pick up the table and the functions.
Revenue recognition
With options.recognition: true, accounting splits an amount over the months
of a service period through schedule_revenue_recognition, books the deferral
against the deferred_revenue account (2200 in the generic chart) and reads
the rows with list_revenue_recognition. The revenue_recognition period kind
posts each month's row when that month closes. The two accounting_recognition_*
tables always exist, so run db diff to pick them up.
Drive transfers
drive_transfer_ownership (drive.transferOwnership) no longer lets a member
with drive.manage take another member's items. A member hands over only their
own items. Moving someone else's items, as driveOffboardingSink does when a
member leaves, needs the service role. Before, a member with drive.manage
could transfer another member's private files to themselves and read them.
New blocks
commissions keeps plans per seller, accrues commissions from sold records or,
with the invoices option, from paid invoices, builds statements per period and
pays them out. referrals keeps codes per member, attributes signups and posts
a reward once to the ledger when a referral qualifies. Both are opt in: install
them with better-supabase add, or through a preset that includes them.
Last updated on
Existing apps
Bring better-supabase into an app that already has its own tables, permissions, events and middleware, one module at a time.
From 0.47 to 0.48
What to check when upgrading from better-supabase 0.47 to 0.48. The deprecated aliases and options that were due go away, every port needs apiVersion 1, and messaging reads prune record conversations before the per-row check.