Porta v1.11.0
Skip to content

Migrations ​

Porta uses node-pg-migrate for database schema management. All migrations are SQL files located in the migrations/ directory.

Running Migrations ​

Via CLI ​

bash
# Apply all pending migrations
porta migrate up

# Roll back the last migration
porta migrate down

# Check migration status
porta migrate status

Via Yarn ​

bash
# Apply migrations
yarn migrate

# Roll back
yarn migrate:rollback

# Check status
yarn migrate:status

# Create a new migration
yarn migrate:create my_migration_name

Migration Files ​

Migrations are numbered sequentially and applied in order:

#FileDescription
001001_extensions.sqlPostgreSQL extensions (pgcrypto, citext) and trigger_set_updated_at() function
002002_organizations.sqlOrganizations table with branding, status, super-admin constraint
003003_applications.sqlApplications and application_modules tables
004004_clients.sqlOIDC clients table with full OIDC configuration fields
005005_users.sqlUsers table with OIDC Standard Claims profile fields
006006_roles_permissions.sqlRoles, permissions, role_permissions, and user_roles tables
007007_custom_claims.sqlClaim definitions and user_claim_values tables
008008_config.sqlSystem configuration key-value table
009009_audit_log.sqlAudit log table with indexes on action, entity, actor
010010_oidc_adapter.sqlOIDC payload storage for long-lived tokens (PostgreSQL adapter)
011011_seed.sqlInitial seed data (signing keys table)
012012_two_factor.sqlTwo-factor authentication tables (TOTP, email OTP, recovery codes)
013013_client_secret_sha256.sqlSHA-256 pre-hash column for client secrets
014014_login_methods.sqlLogin methods columns on organizations and clients
015015_signing_key_encryption.sqlAdds AES-256-GCM metadata used to store encrypted signing key private material
016016_failed_login_count.sqlAdds failed_login_count and last_failed_login_at columns to users table for account lockout
017017_audit_retention.sqlAdds audit_retention_days entry to system_config for configurable audit log cleanup
018018_admin_api_enhancements.sqlAdds branding_assets table (org logo/favicon storage) and admin_sessions table (session tracking for admin viewer/revocation)
019019_invitation_details.sqlAdds details JSONB column and invited_by UUID column to invitation_tokens for enhanced invitations with role/claim pre-assignment
020020_two_factor_admin_permission.sqlSeeds admin:user:2fa permission and assigns it to porta-super-admin, porta-user-admin, and porta-admin roles. Adds two_factor_policy column to organizations (default: optional) and getTwoFactorSummaryRaw() SQL function
021021_auth_recovery_jobs.sqlAdds durable, encrypted magic-link and password-reset dispatch jobs
022022_recovery_artifact_ownership.sqlLinks recovery jobs to their single token artifacts
023023_magic_link_authority.sqlBinds new magic-link tokens to their organization and OIDC interaction authority
024024_application_client_correction.sqlCorrects application-admin access and enforces the supported active client-secret limit during upgrade
025025_record_deletion_lifecycle.sqlSimplifies record lifecycle states and cascades module permission deletion
026026_simplify_user_lifecycle.sqlReplaces manual suspension and locking with active/inactive administration plus automatic lockout
027027_branding_asset_size_limits.sqlSets logo and favicon database size limits
028028_totp_replay_protection.sqlAdds the last accepted TOTP time step and constrains supported TOTP parameters

Migration 015 provides the columns used by the current signing key encryption path. Porta stores AES-256-GCM-encrypted signing key private material in PostgreSQL, while the root encryption key remains external to the database. Migration 028 adds persisted TOTP replay protection.

Writing Migrations ​

Conventions ​

  • File format: NNN_description.sql (3-digit zero-padded number)
  • Language: Pure SQL (no JavaScript migrations)
  • Idempotent: Use IF NOT EXISTS where possible
  • Reversible: Include both UP and DOWN sections

Template ​

sql
-- Up Migration
CREATE TABLE IF NOT EXISTS my_table (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name TEXT NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Add auto-update trigger
CREATE TRIGGER set_updated_at
    BEFORE UPDATE ON my_table
    FOR EACH ROW
    EXECUTE FUNCTION trigger_set_updated_at();

-- Down Migration
DROP TRIGGER IF EXISTS set_updated_at ON my_table;
DROP TABLE IF EXISTS my_table;

Creating a New Migration ​

bash
yarn migrate:create add_my_feature

This creates a new file like migrations/029_add_my_feature.sql with UP and DOWN sections.

Environment Configuration ​

Migrations require the DATABASE_URL environment variable:

bash
DATABASE_URL=postgresql://user:password@localhost:5432/porta

Or pass it directly via the CLI:

bash
porta migrate up --database-url postgresql://user:password@localhost:5432/porta

Released under the MIT License.