publish promotes development's content, then builds
The admin edits development and the build renders production, so nothing written in the panel could reach the live site. Build was only half of publishing, and the missing half was invisible: it succeeded, against the content somebody last promoted, and a successful build of yesterday's site reads as a broken renderer. Publish copies the site's content tables across and then builds. Two things it will not copy: `users`, because production's logins are not development's and nobody should be locked out of the live site to publish a photograph; and `contact_submissions`, the legacy inbox, because development's is empty and production's is not — copying it would destroy real messages in order to publish nothing. The table list is written out rather than derived. A table added later should be considered rather than swept along, and an empty development table quietly overwriting production-only data is discovered far too late to fix. Order is load-bearing in two places. Production is dumped before anything is destroyed, and the publish refuses to start if that dump fails. Development is read BEFORE production is cleared, so a failure to read leaves production untouched rather than empty for a reason that had nothing to do with it. `TRUNCATE ... RESTART IDENTITY`, so the sequences the copy sets are not merely ahead of the rows it inserts — otherwise the collision arrives on the client's next save, hours later, somewhere else. `backupAfterPublish` has been sitting in backups.ts without a caller since the day "On publish" became a backup schedule. This is the caller. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ import { watchMailbox } from './messages';
|
||||
import { watchOriginals } from './originals-watch';
|
||||
import { readServers, savePorts, siteSecrets, startServer, stopServer } from './servers';
|
||||
import { buildSite, readStatic, startStatic, stopStatic } from './static-site';
|
||||
import { publish } from './publish';
|
||||
import { join, resolve, sep } from 'node:path';
|
||||
import { fofosRequest, FofosError, probe, type FofosResponse } from './fofos-client';
|
||||
|
||||
@@ -514,6 +515,22 @@ router.post('/_config/static/build', async (ctx) => {
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
Publish: promote development's content to production, then build.
|
||||
|
||||
A route of its own rather than a flag on build, and BEFORE `/:action` below — that handler would
|
||||
otherwise catch `publish` and reject it as "must be start or stop", which is the kind of 400 nobody
|
||||
can read backwards to a route-ordering mistake.
|
||||
*/
|
||||
router.post('/_config/static/publish', async (ctx) => {
|
||||
try {
|
||||
const result = await publish(await siteSecrets());
|
||||
return ctx.json({ ...result, status: await readStatic() }, result.ok ? 200 : 400);
|
||||
} catch (error) {
|
||||
return ctx.json({ error: (error as Error).message }, 400);
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/_config/static/:action', async (ctx) => {
|
||||
const action = ctx.req.param('action');
|
||||
if (action !== 'start' && action !== 'stop') {
|
||||
|
||||
Reference in New Issue
Block a user