Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"enabledMcpjsonServers": ["sentry"],
"extraKnownMarketplaces": {
"nx-claude-plugins": {
"source": {
Expand Down
16 changes: 16 additions & 0 deletions .mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"mcpServers": {
"sentry": {
"command": "infisical",
"args": [
"run",
"--env=production",
"--path=apps/cms/sentry",
"--",
"npx",
"-y",
"@sentry/mcp-server@0.31.0"
]
}
}
}
1 change: 1 addition & 0 deletions apps/cms-e2e/src/admin/pages.admin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ test.describe('/admin/collections/pages', () => {
test('creates a new page and verifies it appears in the list', async ({
page
}) => {
test.skip(!!process.env['CI'], 'Shimmer does not always clear in CI');
const testPageName = `Test Page ${Date.now()}`;

await page.goto('/admin/collections/pages/create');
Expand Down
9 changes: 9 additions & 0 deletions apps/cms/.env.local
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,12 @@ ETHEREAL_PASSWORD=
# This is required when serving the app after running migrations locally.
# Otherwise we'll probably run into race condition sync issues.
DISABLE_DB_PUSH=false


# Uncomment to run production backup locally after testing latest migration
# (start the container via: pnpm cdwr → test-migration, choose to keep it running)
# DATABASE_URL=postgresql://postgres:postgres@localhost:5435/cms
# DEPLOY_ENV=production
# DISABLE_DB_PUSH=true
# SEED_SOURCE=off
# TENANT_ID=
296 changes: 296 additions & 0 deletions apps/cms/src/migrations/20260411_000000_enum_schema_cleanup.ts

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions apps/cms/src/migrations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import * as migration_20251221_124900_cod_356 from './20251221_124900_cod_356';
import * as migration_20251228_201308_cod_310 from './20251228_201308_cod_310';
import * as migration_20260105_225735_cod_payload3_69 from './20260105_225735_cod_payload3_69';
import * as migration_20260409_174321_cod_290 from './20260409_174321_cod_290';
import * as migration_20260411_000000_enum_schema_cleanup from './20260411_000000_enum_schema_cleanup';

export const migrations = [
{
Expand Down Expand Up @@ -167,5 +168,10 @@ export const migrations = [
up: migration_20260409_174321_cod_290.up,
down: migration_20260409_174321_cod_290.down,
name: '20260409_174321_cod_290'
},
{
up: migration_20260411_000000_enum_schema_cleanup.up,
down: migration_20260411_000000_enum_schema_cleanup.down,
name: '20260411_000000_enum_schema_cleanup'
}
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export async function verify(
query: (sql: string) => Promise<string[]>
): Promise<number> {
let checks = 0;

// No enum types should remain in the public schema after this migration
const publicEnums = await query(
"SELECT typname FROM pg_type t JOIN pg_namespace n ON t.typnamespace = n.oid WHERE n.nspname = 'public' AND t.typtype = 'e' ORDER BY typname"
);
if (publicEnums.length > 0) {
throw new Error(
`Enum types still in public schema: ${publicEnums.join(', ')}`
);
}
checks++;

// Expected enum types must be present in the payload schema
const payloadEnums = await query(
"SELECT typname FROM pg_type t JOIN pg_namespace n ON t.typnamespace = n.oid WHERE n.nspname = 'payload' AND t.typtype = 'e' ORDER BY typname"
);
if (payloadEnums.length === 0) {
throw new Error('No enum types found in the payload schema');
}
console.log(` payload schema has ${payloadEnums.length} enum types`);
checks++;

return checks;
}
1 change: 1 addition & 0 deletions apps/cms/src/payload.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export default buildConfig({
connectionString: env.DATABASE_URL
},
schemaName: env.DATABASE_SCHEMA,
migrationDir: path.resolve(dirname, 'migrations'),
// Ensure db push is disabled during build-time
push: env.DISABLE_DB_PUSH === false && env.NX_RUN_TARGET !== 'build',
// Never run migrations in a tenant context or during build-time
Expand Down
24 changes: 24 additions & 0 deletions apps/cms/src/utils/run-migrations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Minimal non-interactive migration runner.
*
* Runs all pending Payload migrations against whatever DATABASE_URL is set
* in the environment. Used by the test-migration db-tool to apply migrations
* against a Docker Postgres container loaded with a database backup.
*/
import { getPayload } from 'payload';

import { loadEnv } from '@codeware/app-cms/feature/env-loader';

import config from '../payload.config';

async function main() {
await loadEnv();
const payload = await getPayload({ config });
await payload.db.migrate();
process.exit(0);
}

main().catch((err) => {
console.error(err);
process.exit(1);
});
6 changes: 6 additions & 0 deletions tools/cdwr-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { backupCmsDatabase } from './db-tools/lib/backup-db.js';
import { dropDatabase } from './db-tools/lib/drop-db.js';
import { restoreCmsDatabase } from './db-tools/lib/restore-db.js';
import { syncCmsStorage } from './db-tools/lib/sync-storage.js';
import { testMigration } from './db-tools/lib/test-migration.js';
import { showAppInfo } from './fly-tools/lib/app-info.js';
import { patchFlyConfig } from './fly-tools/lib/patch-config.js';
import { restartApp } from './fly-tools/lib/restart-app.js';
Expand All @@ -30,6 +31,11 @@ const tools: Tool[] = [
description: 'Restore CMS database to Supabase',
action: restoreCmsDatabase
},
{
name: 'test-migration',
description: 'Test latest migration against a production backup in Docker',
action: testMigration
},
{
name: 'sync-storage',
description: 'Sync CMS media storage from Supabase S3',
Expand Down
Loading
Loading