feat: multi-schema support, auto-container, CI workflows, and docs#44
feat: multi-schema support, auto-container, CI workflows, and docs#44supunappri99 wants to merge 53 commits into
Conversation
…secrets from public configuration
…development sessions
…database cloning via container execution
…mote PostgreSQL version detection
…actor configuration into committed and ignored secrets files
…ig to gitignored secrets file
…artup logic across database commands
…m postkit.config.json to postkit.secrets.json in E2E tests
…e while ignoring ephemeral .postkit files
…lizing utility functions and standardizing deployment steps.
…file deletion using fs/promises
…iguration storage, and internal service functions
…urable base branches
…ches for git comparisons
chore: postkit agent skill
…crets refactor: split config/secrets, auto-container mode, dedup utilities
…ingle to array-based schema configuration and per-schema file handling
…and app subdirectories
…re planning migration
…cture documentation
…irectories and update project configuration
…tructures and update configuration
…atabase import and bump version to 1.2.2
…architectures and update import documentation
…mprove SQL planning efficiency
…de to local database connection string
…tion, and integrated visual assets.
…age feature layouts
…age and updated theme CSS selectors
…pelines in GitHub Actions
… structure changes
…cuting GitHub PR creation
… test utilities and mocks
…-support feat: multi-schema support, docs overhaul, and CI pipelines
There was a problem hiding this comment.
Potential Issues
1. Intermediate apply error handling in cli/src/modules/db/commands/plan.ts:154
The intermediate apply for cross-schema resolution catches errors but only warns:
} catch (err) {
spinner.warn(`Intermediate apply for "${schemaName}" failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
}If a schema creates a table that another schema references, and the intermediate apply fails silently, the subsequent pgschema plan for the dependent schema will likely fail anyway with a more obscure error. Consider making this fatal for certain error types, or at least logging more details about what errors are safe to ignore.
2. Schema fingerprint validation could block rapid iteration
The apply command validates that schema files haven't changed since plan was generated:
if (current !== stored) {
throw new PostkitError(
`Schema files for "${schemaName}" have changed since the plan was generated.`,
'Run "postkit db plan" again to regenerate the plan.',
);
}This is good for safety but could be frustrating during active development when making rapid changes. Consider adding a --skip-fingerprint-check flag for development workflows, or make the error message more actionable (show what changed).
3. Container cleanup could be incomplete if process is killed
In startSessionContainer, if the process is killed before stopSessionContainer is called, the container remains running:
export async function stopSessionContainer(containerID: string): Promise<void> {
await runCommand(`docker stop ${containerID}`);
await runCommand(`docker rm ${containerID}`);
}This is called from abort and deploy, but if the CLI process crashes (SIGKILL), containers leak. Consider a cleanup function that runs on process exit signals.
4. Free port scan has no upper bound retry
In findFreePort, if all ports 15432-15532 are taken:
for (let port = start; port <= end; port++) {
if (await isPortFree(port)) return port;
}
throw new Error(`No free port found between ${start} and ${end}.`);The error is thrown without any suggestion to the user. Could the error message include a hint to check for leftover PostKit containers? e.g., docker ps | grep postkit-session
Questions
1. Why is intermediate apply for cross-schema resolution non-fatal?
In plan.ts, when applying a schema's plan to enable cross-schema references for subsequent schemas:
spinner.start(`Applying "${schemaName}" plan to local DB for cross-schema resolution...`);
try {
await applyPlanToLocalDb(session.localDbUrl, planFilePath);
spinner.succeed(...);
} catch (err) {
spinner.warn(`Intermediate apply for "${schemaName}" failed (non-fatal): ...`);
}Is this non-fatal behavior intentional? What types of errors are expected to be safe to ignore here?
2. Should empty schema directories be allowed?
In plan.ts, schemas with no directory are skipped with a warning:
if (!existsSync(schemaDir)) {
logger.warn(`Schema "${schemaName}" has no directory at ${schemaDir} — skipping. Run "postkit db schema add ${schemaName}" to scaffold it.`);
planFiles[schemaName] = null;
schemaFingerprints[schemaName] = null;
continue;
}Is this the intended UX? Should users be required to run postkit db schema add before a schema can be added to config, or is this flexible skip-by-warn acceptable?
3. Any plans for automated config migration?
The breaking changes (5 of them) require manual migration. Is there any plan to add a postkit db migrate-config command to automate this, or is the manual approach preferred going forward?
4. Is SHOW server_version_num reliable across all cloud providers?
For container version detection:
const pgVersion = await getRemotePgMajorVersion(remoteUrl);This uses SHOW server_version_num. Are there any known issues with this on managed Postgres services (RDS, Cloud SQL, Neon, Supabase, etc.) that might report different version formats?
…se containers on SIGINT/SIGTERM
…-support feat: implement container interrupt handling to clean up local database
Deploying postkit with
|
| Latest commit: |
2324bd7
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://1ce9fd7f.postkit.pages.dev |
⏺ Issue 1 — No Fix NeededCross-schema migration is not a supported feature of the As a result, a failure during this step has no impact on supported workflows. ⏺ Issue 2 — No Fix NeededThe fingerprint check is a valid and necessary safety mechanism. The existing error message already provides clear guidance:
Re-running the Introducing a
This friction is intentional and helps prevent unsafe operations. Answers for Questions1. Why is intermediate apply for cross-schema resolution non-fatal?The non-fatal behavior is intentional. The intermediate apply strips structural SQL only ( Error types that are safe to ignore:
If the apply fails for a genuinely structural reason (e.g. a missing type), the dependent schema's pgschema run will fail anyway with a direct, clear error. The non-fatal warn avoids false-fatal errors from the "already exists" class while still surfacing that something went wrong.
2. Should empty schema directories be allowed?The skip-by-warn behavior is intentional and the correct UX for the current design.
Running 3. Any plans for automated config migration?Automated config migration already exists.
The migrated result is written back to A separate 4. Is
|
| Example value | Meaning |
|---|---|
160003 |
PostgreSQL 16.3 |
150008 |
PostgreSQL 15.8 |
140012 |
PostgreSQL 14.12 |
The implementation at database.ts:148 extracts the major version with Math.floor(num / 10000), which is correct for this format. No known provider deviates from it.
feat: multi-schema support, auto-container, CI workflows, and docs
Branch:
development→mainSummary
schemas: string[]config, per-schemadb/schema/<name>/directories, per-schema pgschema plan runs with intermediate apply for cross-schema resolution, and combined migration outputpostkit.config.json(committed) +postkit.secrets.json(gitignored),postkit db schema addcommand, and separatedb/infra/directory for DB-level infrastructureChanges
cli/src/modules/db/types/—schemas: string[]replacesschema: string; sessionplanFiles/schemaFingerprintsbecomeRecord<string, string | null>mapscli/src/modules/db/utils/db-config.ts—getPlanFilePath(schemaName),getGeneratedSchemaPath(schemaName),getInfraPath()per-schema path helperscli/src/modules/db/commands/plan.ts— loops overconfig.schemas, runs pgschema per schema, intermediate apply between schemas for cross-schema reference resolutioncli/src/modules/db/commands/apply.ts— iteratesplanFilesrecord, combines wrapped SQL from all schemas into one migration filecli/src/modules/db/commands/schema.ts— newpostkit db schema add <name>command viaschema-scaffold.tsservicecli/src/modules/db/services/container.ts— new: auto-startspostgres:{version}-alpineDocker container whenlocalDbUrlis empty; used bystart,deploy,importcli/src/modules/db/services/schema-generator.ts— per-schema reads fromdb/schema/<name>/, writesschema_<name>.sql, fingerprints per schemacli/src/modules/db/services/infra-generator.ts— reads fromconfig.infraPath(db/infra/) instead ofdb/schema/infra/cli/src/commands/init.ts— scaffoldsschemas: ["public"],infraPath: "db/infra", gitignore entries updated toplan_*.sql/schema_*.sqlcli/src/common/config.ts—PostkitPublicConfig/PostkitSecretssplit;deepMergefor secrets overlay; auto-migration from legacyremoteDbUrl.github/workflows/pr-checks.yml— new:cli-build→cli-unit-tests→cli-e2e-tests(Docker) on PRs tomain/development.github/workflows/release.yml—unit-testsande2e-testsjobs;releasejob gated on bothagent/skills/— all four PostKit skills updated for multi-schema layout and correct config structure.claude/skills/create-pr/SKILL.md— fixed to generate description only (no push/create); reads template firstdocs/— new blog posts, hero images via@docusaurus/plugin-ideal-image, updated all module docs, newcross-schema-migrations.md,schema.mdcommand page, agent skills overviewcli/test/— TypeScript strict-mode fixes; newcontainer.test.ts,schema-scaffold.test.ts; E2Ecase-6-multi-schema-full-flow.test.tsandauto-container.test.tsType of Change
Test Plan
npm run test)npm run test:e2e) (if applicable)npm run build)public+appschemas on local Postgres; auto-container start/abort;postkit db schema add; docs site builds and hero images render correctly in light/dark modeBreaking Changes
Breaking changes — existing projects must migrate before upgrading:
1. Config key renamed —
postkit.config.json2. Directory structure change — infra SQL moves out of the schema folder
3. Schema SQL must be in a named subdirectory
4. Session state shape changed — existing
.postkit/db/session.jsonfiles with the oldplanFile/schemaFingerprintscalar fields will be treated as having no pending plan. Runpostkit db abortbefore upgrading to clear any active session.5. Ephemeral file names changed —
.postkit/db/plan.sql→plan_<schema>.sql,schema.sql→schema_<schema>.sql. Update.gitignoreentries (or re-runpostkit init).