Database migrations
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.
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:
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:
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:
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:
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.