Architecture

Database migrations

Edit page
Apply package-owned PostgreSQL migration providers safely and adopt the recognized legacy history.

Every database-backed official or local layer supplies an immutable PortalLayerManifest. The manifest identifies the provider, its package version, dependencies, schema export, and migration directory. Core, Service Requests, and Timesheets each ship a clean current-state baseline.

Ordering and journals

nuxt-customer-portal db migrate resolves all manifests, rejects duplicate IDs, cycles, missing dependencies, and incompatible duplicate versions, and then applies providers in dependency order. Execution is serialized with a PostgreSQL advisory lock.

Each provider has its own journal table in the shared nuxt_customer_portal_migrations schema. A journal row records the migration filename, SHA-256 checksum, package version, and application time. An applied file whose contents later change is checksum drift and aborts the run before that SQL is replayed.

Terminal
npx nuxt-customer-portal doctor
npx nuxt-customer-portal db status
npx nuxt-customer-portal db migrate

Each migration file runs transactionally. A failure rolls back that file and releases the advisory lock; earlier committed provider migrations remain recorded and a repeat run resumes from the first pending file.

Local providers

Register a local layer with the same provider contract:

portal.config.ts
import { definePortalConfig, localPortalLayer } from '@nuxt-customer-portal/kit'

export default definePortalConfig({
  layers: [
    '@nuxt-customer-portal/preset',
    localPortalLayer({
      id: 'acme-billing',
      source: './layers/acme-billing',
      schema: './layers/acme-billing/server/db/schema',
      migrations: './layers/acme-billing/migrations',
      dependsOn: ['core']
    })
  ]
})

Generate only for a local provider; official package streams are immutable:

Terminal
npx nuxt-customer-portal db generate --provider acme-billing

Hosts should extend official data through host-owned tables in their own PostgreSQL schema. Direct changes to official tables require a fork or explicit takeover of that migration stream and fall outside package compatibility guarantees.

Adopt a legacy installation

The unchanged combined history is retained under legacy/drizzle. Adoption does not replay its SQL. First request a dry-run mapping:

Terminal
npx nuxt-customer-portal db adopt-legacy

The command verifies the recognized 22-entry legacy journal and representative core, Service Requests, and Timesheets tables. Any mismatch aborts without writing package journals. After reviewing the mapping, stamp the current package baselines:

Terminal
npx nuxt-customer-portal db adopt-legacy --apply

Disable or remove a provider

Disabling a package removes its runtime contribution but never drops its tables or data. Permanent removal requires an explicit, host-owned migration and retention decision. This keeps package removal reversible and prevents configuration changes from becoming destructive database operations.