diff --git a/README.md b/README.md new file mode 100644 index 0000000..b8f5414 --- /dev/null +++ b/README.md @@ -0,0 +1,120 @@ +# saltcorn — dev environment for the dev-deploy plugin + +This project root holds the `dev-deploy` Saltcorn plugin and the launcher +scripts + per-instance state needed to develop and test it against two local +Saltcorn instances. Upstream Saltcorn lives in `saltcorn/` (a sibling git +checkout managed independently from this project). + +## Layout + +``` +saltcorn/ project root (this git repo) +├── dev-deploy/ the plugin (Saltcorn plugin, sc_plugin_api_version 1) +├── startServer.sh launch MAIN instance on :3000 +├── startServerTest.sh launch TEST instance on :3001 +├── devServer.sh launch MAIN under `saltcorn dev:serve` (tsc watch) +├── installSaltcorn.sh reproduce this dev environment from scratch +├── .dev-state/ MAIN instance: env.sh, saltcorn.sqlite, files/, sessions +├── .dev-state-test/ TEST instance: same shape, separate port + secret +└── saltcorn/ upstream Saltcorn checkout (its own .git, gitignored here) +``` + +The upstream subfolder, both `.dev-state*` directories, and `node_modules/` +are all gitignored — only the plugin + scripts + this README are tracked. + +## Prerequisites + +- `git`, `curl` +- `nvm` (auto-installed at `~/.nvm` if missing) → Node 20 +- `git-lfs` for the `.gitattributes` LFS filters (`git lfs install` once per clone) + +`installSaltcorn.sh` handles nvm + Node 20 install for you. + +## Fresh install + +```bash +./installSaltcorn.sh [destination] # default: ./saltcorn +``` + +Clones upstream Saltcorn into `/saltcorn/`, runs `npm install` + `npm +run tsc`, generates `/.dev-state/env.sh` with a fresh session secret, +initializes the SQLite schema, creates the admin user, and writes +`/startServer.sh`. + +The script sets up the **MAIN** instance only. To add the **TEST** instance, +duplicate `.dev-state/` as `.dev-state-test/`, edit its `env.sh` to use a new +`SALTCORN_SESSION_SECRET` and add `export SALTCORN_PORT="3001"`, then: + +```bash +source .dev-state-test/env.sh +saltcorn reset-schema -f +saltcorn create-user -a -e admin@local -p AdminP@ss1 +``` + +The reference `.dev-state-test/env.sh` already in this repo shows the exact +pattern. + +## Running + +```bash +./startServer.sh # MAIN → http://localhost:3000/ +./startServerTest.sh # TEST → http://localhost:3001/ +./devServer.sh # MAIN under `saltcorn dev:serve` (nodemon + tsc watch) +``` + +Login on either instance: `admin@local` / `AdminP@ss1`. + +Each `startServer*.sh` runs `saltcorn install-plugin -d ./dev-deploy` on every +boot, so edits to `dev-deploy/` go live on the next restart. + +## The dev-deploy plugin + +`dev-deploy/` migrates Saltcorn metadata (tables, fields, views, pages, +triggers, roles, library, tags, constraints, files, page groups, workflow +steps, plus selected config keys and plugin configuration) across Dev/Test/Prod +environments via an append-only ops journal with stable cross-environment +UUIDs and HMAC-authenticated peer endpoints. Concurrent edits surface as +conflicts in the admin UI with theirs/mine/per-field-merge resolution. User +row data is left alone unless an admin explicitly marks a table as `managed` +or `starter`. + +Admin UI: `/admin/dev-deploy/` (logged in as an admin). Machine API: +`/dev-deploy/api/{journal,ingest,file/:uuid,health}` (HMAC-signed peer requests). + +## Tests + +```bash +# Both servers must be running first. +./startServer.sh & ./startServerTest.sh & +cd dev-deploy && npm test +``` + +Runs `dev-deploy/test/e2e.js` — ~50+ end-to-end tests covering pairing, +promote, pull, conflict resolution, constraints, files, page groups, +workflow steps, config propagation, managed/starter row data, revert, and +machine-endpoint security. Tests run in order and share state; don't reorder. + +`test/sc-exec.js` is a shim used by the tests to run JS against Saltcorn's +models with full `require()` access (saltcorn's built-in `run-js` uses a vm +sandbox that hides Field/TableConstraint/File/etc.). + +## Notes + +- **Per-instance `sessions.sqlite`.** Saltcorn's SQLite session store writes + `sessions.sqlite` at process cwd (`packages/server/routes/utils.js`). + `startServer.sh` and `startServerTest.sh` `cd` into their respective state + directory before `exec saltcorn serve`, so each instance gets its own + sessions DB. `devServer.sh` cannot do this (its `dev:serve` runs `npm run + tsc` which needs cwd=upstream root), so its sessions land in + `saltcorn/sessions.sqlite` — don't run `devServer.sh` and `startServer.sh` + against the MAIN instance simultaneously. + +- **`SALTCORN_SESSION_SECRET` is the pairing identity.** dev-deploy derives + its at-rest encryption key (KEK) for peer secrets via HKDF from this value. + Rotating it invalidates every peer pairing on the instance. The secret is + generated once per instance and persisted in that instance's `env.sh`. + +- **Upstream Saltcorn updates.** Pull from upstream via + `git -C saltcorn pull` — the project root is a separate repo and doesn't + see those commits. After a pull, you may need `npm install && npm run tsc` + inside `saltcorn/`.