The v2.0.0 migrations are forward-only. There is no automatic rollback script. This page documents what you can and cannot undo if you need to revert the upgrade.
For every table that had RLS enabled by the v2.0.0 upgrade:
| |
Disabling RLS reverts the visibility filtering. Combined with restoring the previous permission grants, this restores v1.x row visibility.
| |
This is safe only if no application code reads the column. Once you cut traffic on the v2.0.0 backend, the backend will start selecting and inserting the column. Rolling it back at that point breaks the backend.
| |
This drops the new mappings but leaves the new tables in place. See the “Cannot roll back” list below for whether the tables themselves can be removed.
The default password policy is inserted with ON CONFLICT DO NOTHING,
and the value is a JSON blob. There is no automatic “remove” path:
- Removing the row from
cypex.t_configdoes not break the upgrade, but the backend will then apply no password complexity check at all (which is more permissive than the default). - If you inserted a custom policy before the upgrade, rolling back means
restoring the previous
cypex.t_configrow from your backup.
The new tables (t_organization, t_module_organization,
t_role_organization, t_permission_audit_log) cannot be dropped if any
application code references them. After the v2.0.0 backend has started,
the backend will reference them on every request. Drop them only if you
also revert the backend binary to v1.x.
Once the v2.0.0 backend has served requests and new rows have been written
with organization_id populated, rolling back the schema loses the
organization context for those rows. They will still be visible (because
RLS can be disabled and the column can be dropped), but the
organization-scoped logic is gone.
The recommendation: do not write new rows if you plan to roll back. Either:
- Hold traffic on the v1.x backend until you decide, or
- Switch the v2.0.0 backend into maintenance mode before the first user-facing request.
The v2.0.0 backend issues JWTs with the new claims. If users still hold those tokens after a rollback, the v1.x backend will reject them as malformed. The fix is to invalidate all sessions (force logout) before the rollback, or wait for natural token expiry.
Revoking write privileges from cypex_user is straightforward to undo
(GRANT INSERT, UPDATE, DELETE ON ... TO cypex_user;), but doing so on
production without coordination is risky. Plan this as part of the
rollback, not as an ad-hoc fix.
- Decide the rollback trigger before the upgrade window. Which failure modes cause you to roll back versus fix forward?
- Hold traffic as soon as the decision to roll back is made. Either stop the backend or switch it to maintenance mode.
- Restore the database from the pre-upgrade
pg_dumpbackup. This is the cleanest rollback path. The schema changes are not reversible cleanly enough that a partial rollback is usually worthwhile. - Restore the backend to the previous version.
- Invalidate all sessions by restarting the backend with a fresh JWT signing key, or by waiting for natural token expiry.
- Communicate the rollback to users and stakeholders.
The recommendation in Pre-upgrade checklist applies here: rehearse the rollback on a staging replica before doing it on production. The rollback timing is dominated by the database restore, not by the schema changes themselves.
| Change | Rollback cost |
|---|---|
| RLS enabled on tables | Easy: ALTER TABLE ... DISABLE |
organization_id columns | Easy if no new data written |
| New mappings | Easy: DELETE |
| Default password policy | Manual: restore from backup |
| New tables | Hard: depends on app code |
| New JWTs in flight | Hard: force logout |
cypex_user privilege changes | Easy but disruptive |