Skip to content

Commit e9c4da4

Browse files
committed
planx: rebuild all four containers, ARM64 task defs, fix demo seed
Reported by Sam McKellen (Brighton & Hove) — the planx tryout flow was broken end-to-end against latest upstream. Fixing the entire chain: Editor (docker/editor): - Drop VITE_APP_AIRBRAKE_PROJECT_ID=0 / KEY=unused. The "0" string is truthy in upstream's airbrake.ts hasConfig check, so it constructs a Notifier with projectId 0 and throws synchronously during module init, blanking the SPA before React mounts. - Install pnpm deps inside editor.planx.uk/ (upstream removed the root pnpm-workspace; root install only brings in `typescript`). - Switch VITE_APP_HASURA_URL / WEBSOCKET to /v1/graphql to match the CloudFront cache behaviour. The /hasura/* path doesn't exist there, so GraphQL was falling through to the editor nginx and 405-ing. - Patch _authenticated/-loader.tsx in build.sh to no-op validateDomain; upstream's allowlist excludes our ephemeral CloudFront hostnames and the route guard otherwise redirects /app to /login before initAuthStore even runs. API (docker/api): - Move setupDemoAuth(app) to before the upstream `// Setup API routes` block via patch-demo-auth.sh. The /api-prefix-stripping middleware lives inside setupDemoAuth and has to register before app.use(userRoutes) etc., or /api/user/me 404s before the rewrite happens. - demo-auth.ts now sets jwt + auth cookies via res.cookie and redirects to /app instead of /?jwt=…. TanStack Router's / -> /app redirect drops the search params before the SPA's auth init can pick them up, so the user got bounced to /login despite a successful POST. - Install pnpm deps inside api.planx.uk/ (same root-workspace issue as editor). - build.sh actually invokes patch-demo-auth.sh — the previous version copied a stale precompiled overlay but never re-applied the source patch. Hasura (docker/hasura): - Copy entrypoint-wrapper.sh into the build context (was missing, image failed to build locally). - Seed updates: * Drop external_planning_site_name / _url (upstream removed the columns). * Add is_trial=false on team_settings (Team route does team.settings.isTrial against null without it). * Add team_integrations row (GIS data settings page reads integrations.has_planning_data). * Replace the legacy two-flow seed (which used type-300/type-110 nodes no longer recognised by latest editor) with one multi-step demo flow: Notice -> Question with 3 branches -> TextInput -> Confirmation, using current ComponentType numbers (8, 100, 200, 250, 110, 725). * Set flows.version = 1 explicitly. Without it sharedb-postgresql's getSnapshot falls into the "no document" branch, the editor's subscribeToDoc calls doc.create and silently overwrites the seeded data with an empty doc on first open. * UPSERT the demo flow row + clear other team-26 flows so leases that came up with the legacy seed get refreshed when the Hasura image is rebuilt. * Pre-publish the demo flow (published_flows row) so /<team>/<flow> /published renders without a manual Publish click. ShareDB (docker/sharedb): - Install pnpm deps inside sharedb.planx.uk/ (same root-workspace issue). Old image ran fine for connect/init/handshake but its node_modules had drifted such that subscribe acks never reached clients. Fresh build with the deps installed in the right place fixes it. CDK (cdk/lib/constructs/compute.ts): - Flip editor / api / hasura / sharedb FargateTaskDefinitions to ARM64. Native ARM64 builds work on Apple Silicon CI; cross-compiling to amd64 under QEMU OOMs the editor's vite/esbuild step. Verified end-to-end on a fresh `isb terminate && isb assign ndx-try-planx`: sign-in, /app/<team> with the demo flow listed, editor canvas renders all 23 nodes, /<team>/<flow>/published serves the public flow, GIS data settings page loads.
1 parent 023e4c3 commit e9c4da4

10 files changed

Lines changed: 218 additions & 42 deletions

File tree

cloudformation/scenarios/planx/cdk/lib/constructs/compute.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export class ComputeConstruct extends Construct {
120120
executionRole,
121121
taskRole,
122122
runtimePlatform: {
123-
cpuArchitecture: ecs.CpuArchitecture.X86_64,
123+
cpuArchitecture: ecs.CpuArchitecture.ARM64,
124124
operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,
125125
},
126126
});
@@ -185,7 +185,10 @@ export class ComputeConstruct extends Construct {
185185
executionRole,
186186
taskRole,
187187
runtimePlatform: {
188-
cpuArchitecture: ecs.CpuArchitecture.X86_64,
188+
// ARM64: matches the editor / api images we publish (built natively
189+
// on Apple Silicon CI; cross-compiling to amd64 under QEMU OOMs the
190+
// editor's vite/esbuild step). Also ~20% cheaper on Fargate.
191+
cpuArchitecture: ecs.CpuArchitecture.ARM64,
189192
operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,
190193
},
191194
});
@@ -285,7 +288,7 @@ export class ComputeConstruct extends Construct {
285288
executionRole,
286289
taskRole,
287290
runtimePlatform: {
288-
cpuArchitecture: ecs.CpuArchitecture.X86_64,
291+
cpuArchitecture: ecs.CpuArchitecture.ARM64,
289292
operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,
290293
},
291294
});
@@ -334,7 +337,7 @@ export class ComputeConstruct extends Construct {
334337
executionRole,
335338
taskRole,
336339
runtimePlatform: {
337-
cpuArchitecture: ecs.CpuArchitecture.X86_64,
340+
cpuArchitecture: ecs.CpuArchitecture.ARM64,
338341
operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,
339342
},
340343
});

cloudformation/scenarios/planx/docker/api/Dockerfile

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,19 @@ RUN corepack enable && corepack prepare pnpm@latest --activate
66

77
WORKDIR /app
88

9-
# Copy the full monorepo (pnpm workspaces need it)
9+
# Copy the full monorepo (still useful for workspace package references)
1010
COPY planx-src/ .
1111

12-
# Install dependencies
13-
RUN pnpm install --frozen-lockfile 2>/dev/null || pnpm install
12+
# Install api deps inside api.planx.uk. Upstream's api.planx.uk carries its
13+
# own pnpm-lock.yaml and is no longer linked through a root pnpm-workspace.yaml,
14+
# so a root-level install just pulls in `typescript` and the api's own
15+
# deps go missing (build then fails with "tsc not found").
16+
RUN cd api.planx.uk && (pnpm install --frozen-lockfile || pnpm install)
1417

15-
# Build the API
18+
# Build the API (server.ts has been patched by build.sh to call setupDemoAuth)
1619
RUN cd api.planx.uk && pnpm build
1720

18-
# Apply demo auth overlay after build
21+
# Pre-compiled JS overlay used by the patched server import resolution
1922
COPY overlays/demo-auth.js /app/api.planx.uk/dist/demo-auth.js
2023

2124
# Production stage

cloudformation/scenarios/planx/docker/api/build.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ cp "$SCRIPT_DIR/Dockerfile" "$BUILD_DIR/Dockerfile"
2121
# Move API app to expected location
2222
mv "$BUILD_DIR/planx-src/apps/api.planx.uk" "$BUILD_DIR/planx-src/api.planx.uk"
2323

24+
# Apply the demo-auth source patch into the freshly cloned upstream so the
25+
# build sees the import/setupDemoAuth call. Without this step, the build runs
26+
# unpatched server.ts and the demo overlay is never registered (yet the legacy
27+
# image we replace had the patch baked in by hand).
28+
echo "==> Patching server.ts with demo auth..."
29+
sh "$SCRIPT_DIR/patch-demo-auth.sh" "$BUILD_DIR/planx-src/api.planx.uk"
30+
2431
echo "==> Building Docker image..."
2532
cd "$BUILD_DIR"
2633
docker build -t ndx-planx-api:latest .

cloudformation/scenarios/planx/docker/api/overlays/demo-auth.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,26 @@ export function setupDemoAuth(app: Express) {
8282
{ expiresIn: "24h" },
8383
);
8484

85-
// Redirect to editor with JWT in search params (relative URL to stay on CloudFront)
86-
res.redirect(`/?jwt=${token}`);
85+
// Set JWT as an HttpOnly cookie. Upstream's useLoggedInUserAuth reads
86+
// req.cookies.jwt first, and the editor's apiClient sends cookies via
87+
// withCredentials. Putting the JWT only in the URL hash/search no longer
88+
// works: TanStack Router's `/` -> `/app` redirect drops the search params
89+
// before the SPA's auth init can pick them up, and the user gets bounced
90+
// to /login despite a successful POST. Set both cookies so the API and
91+
// the editor's auth store agree on the logged-in state.
92+
res.cookie("jwt", token, {
93+
httpOnly: true,
94+
secure: true,
95+
sameSite: "lax",
96+
path: "/",
97+
maxAge: 24 * 60 * 60 * 1000,
98+
});
99+
res.cookie("auth", JSON.stringify({ loggedIn: true }), {
100+
secure: true,
101+
sameSite: "lax",
102+
path: "/",
103+
maxAge: 24 * 60 * 60 * 1000,
104+
});
105+
res.redirect("/app");
87106
});
88107
}

cloudformation/scenarios/planx/docker/api/patch-demo-auth.sh

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,15 @@ cp "$(dirname "$0")/overlays/demo-auth.ts" "$API_DIR/modules/auth/demo-auth.ts"
1717
sed -i.bak '/^import { apiLimiter/a\
1818
import { setupDemoAuth } from "./modules/auth/demo-auth.js";' "$API_DIR/server.ts"
1919

20-
# 3. Add demo auth setup before error handlers (the // Handle any server errors comment)
21-
sed -i.bak '/^\/\/ Handle any server errors/i\
22-
// NDX:Try demo auth (bypasses Google/Microsoft OAuth)\
20+
# 3. Add demo auth setup BEFORE the API route mounting (// Setup API routes anchor).
21+
# setupDemoAuth installs an `/api`-prefix-stripping middleware so /api/user/me
22+
# can reach the upstream user router. That middleware MUST run before
23+
# app.use(userRoutes) etc., or the rewrite happens too late and ALB-routed
24+
# /api/* requests 404. Inserting before the // Setup API routes comment
25+
# guarantees the right order regardless of which route bundles are added later.
26+
sed -i.bak '/^\/\/ Setup API routes/i\
27+
// NDX:Try demo auth (bypasses Google/Microsoft OAuth). Registered BEFORE the\
28+
// upstream route bundles so its /api-prefix-stripping middleware runs first.\
2329
if (process.env.DEMO_MODE === "true") {\
2430
setupDemoAuth(app);\
2531
console.info("Demo auth enabled at /auth/demo");\

cloudformation/scenarios/planx/docker/editor/Dockerfile

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,28 @@ WORKDIR /app
99
# Copy the full monorepo
1010
COPY planx-src/ .
1111

12-
# Install dependencies
13-
RUN pnpm install --frozen-lockfile 2>/dev/null || pnpm install
12+
# Install editor deps. Upstream's editor.planx.uk is a self-contained pnpm
13+
# project (its own pnpm-lock.yaml) and is no longer linked via a root
14+
# pnpm-workspace.yaml, so installing at the root just brings in `typescript`
15+
# and the editor's `tsc`/`vite` end up missing. Install inside the editor
16+
# directory directly.
17+
RUN cd editor.planx.uk && (pnpm install --frozen-lockfile || pnpm install)
1418

1519
# Build editor with relative URLs (all services behind same CloudFront/ALB)
1620
# WebSocket URLs use window.location.host (injected at runtime)
1721
ENV VITE_APP_API_URL=/api
18-
ENV VITE_APP_HASURA_URL=/hasura/v1/graphql
19-
ENV VITE_APP_HASURA_WEBSOCKET=wss://__PLANX_HOST__/hasura/v1/graphql
22+
# CloudFront routes /v1/*, /v2/* and /console/* directly to Hasura; there is
23+
# no /hasura/* cache behaviour. Build with the same paths so the editor's
24+
# GraphQL client doesn't end up at the editor nginx (405) or ShareDB.
25+
ENV VITE_APP_HASURA_URL=/v1/graphql
26+
ENV VITE_APP_HASURA_WEBSOCKET=wss://__PLANX_HOST__/v1/graphql
2027
ENV VITE_APP_SHAREDB_URL=wss://__PLANX_HOST__/sharedb
2128
ENV VITE_APP_ENV=production
22-
ENV VITE_APP_AIRBRAKE_PROJECT_ID=0
23-
ENV VITE_APP_AIRBRAKE_PROJECT_KEY=unused
29+
# Airbrake intentionally not configured. Setting AIRBRAKE_PROJECT_ID=0 makes
30+
# upstream's airbrake.ts pass its truthy-string check, then call
31+
# `new Notifier({projectId: 0})`, which throws synchronously during module
32+
# init and blanks the editor SPA. Leave these unset so the no-op logger
33+
# branch runs instead.
2434

2535
RUN cd editor.planx.uk && pnpm build
2636

cloudformation/scenarios/planx/docker/editor/build.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,23 @@ echo "==> Preparing build context..."
1717
# Move editor to expected path
1818
mv "$BUILD_DIR/planx-src/apps/editor.planx.uk" "$BUILD_DIR/planx-src/editor.planx.uk"
1919

20+
# Patch validateDomain to accept the runtime host. Upstream restricts /app
21+
# to editor.planx.{dev,uk}, *.planx.pizza, and localhost:3000; on any other
22+
# host (e.g. our ephemeral CloudFront distributions) the route guard throws
23+
# redirect({to:"/login"}) before initAuthStore runs, so the demo cookie is
24+
# never exchanged for a /user/me lookup. Replacing the body with a no-op is
25+
# the smallest change that lets the existing auth flow take over.
26+
LOADER="$BUILD_DIR/planx-src/editor.planx.uk/src/routes/_authenticated/-loader.tsx"
27+
if [ -f "$LOADER" ]; then
28+
cat > "$LOADER" <<'EOF'
29+
// NDX:Try patch: original validateDomain restricts /app to a hardcoded
30+
// allowlist of upstream hosts and redirects everything else to /login,
31+
// blocking the demo auth flow on our CloudFront distributions.
32+
export const validateDomain = () => {};
33+
EOF
34+
echo " patched _authenticated/-loader.tsx"
35+
fi
36+
2037
cp "$SCRIPT_DIR/Dockerfile" "$BUILD_DIR/Dockerfile"
2138
cp "$SCRIPT_DIR/nginx.conf" "$BUILD_DIR/nginx.conf"
2239
cp "$SCRIPT_DIR/entrypoint.sh" "$BUILD_DIR/entrypoint.sh"

cloudformation/scenarios/planx/docker/hasura/build.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ echo "==> Copying seed data..."
2929
mkdir -p "$BUILD_DIR/seed"
3030
cp "$SCRIPT_DIR/seed/"*.sql "$BUILD_DIR/seed/" 2>/dev/null || true
3131

32-
echo "==> Copying Dockerfile..."
32+
echo "==> Copying Dockerfile + entrypoint..."
3333
cp "$SCRIPT_DIR/Dockerfile" "$BUILD_DIR/Dockerfile"
34+
cp "$SCRIPT_DIR/entrypoint-wrapper.sh" "$BUILD_DIR/entrypoint-wrapper.sh"
3435

3536
echo "==> Building Docker image..."
3637
cd "$BUILD_DIR"

cloudformation/scenarios/planx/docker/hasura/seed/V999__ndx_demo_seed.sql

Lines changed: 125 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ VALUES (26, '#0B0C0C', '#1D70B8', '#1D70B8')
1212
ON CONFLICT (team_id) DO NOTHING;
1313

1414
-- 3. Team settings
15-
INSERT INTO team_settings (team_id, homepage, help_email, help_phone, help_opening_hours, external_planning_site_name, external_planning_site_url)
16-
VALUES (26, 'https://ndx-demo.example.com', 'planning@ndx-demo.example.com', '020 7946 0958', 'Monday to Friday, 9am to 5pm', 'NDX Demo Planning Portal', 'https://ndx-demo.example.com/planning')
15+
-- Upstream removed external_planning_site_name/_url and added is_trial. Without
16+
-- a row here at all, the editor's Team route does `team.settings.isTrial` on a
17+
-- null settings relation and the page crashes with "Cannot read properties of
18+
-- null (reading 'isTrial')".
19+
INSERT INTO team_settings (team_id, homepage, help_email, help_phone, help_opening_hours, is_trial)
20+
VALUES (26, 'https://ndx-demo.example.com', 'planning@ndx-demo.example.com', '020 7946 0958', 'Monday to Friday, 9am to 5pm', false)
1721
ON CONFLICT (team_id) DO NOTHING;
1822

1923
-- 4. Demo user
@@ -26,21 +30,126 @@ INSERT INTO team_members (team_id, user_id, role)
2630
VALUES (26, 1001, 'teamEditor')
2731
ON CONFLICT DO NOTHING;
2832

29-
-- 6. Sample flows
30-
INSERT INTO flows (id, team_id, slug, name, data, status, created_at, updated_at, creator_id)
33+
-- 6. Team integrations
34+
-- Editor's GIS settings page reads `team.integrations.has_planning_data`. If
35+
-- no row exists, team.integrations is null and the page crashes with
36+
-- "Cannot read properties of undefined (reading 'hasPlanningData')".
37+
INSERT INTO team_integrations (team_id, has_planning_data)
38+
VALUES (26, false)
39+
ON CONFLICT (team_id) DO NOTHING;
40+
41+
-- 7. Sample multi-step flow so the demo isn't a blank canvas.
42+
-- Component types come from upstream's planx-core ComponentType enum:
43+
-- Notice=8, Question=100, Answer=200, Content=250, TextInput=110,
44+
-- Confirmation=725. A Question node lists its Answer children in `edges`;
45+
-- each Answer can chain its own follow-up via `edges` (Content here).
46+
-- Node ids are 10-char strings; ShareDB doesn't care about format, only
47+
-- that they're unique within the flow.
48+
INSERT INTO flows (id, team_id, slug, name, data, status, created_at, updated_at, creator_id, version)
3149
VALUES (
3250
'a1b2c3d4-e5f6-7890-abcd-ef1234567890', 26,
33-
'householder-planning-permission',
51+
'apply-for-householder-planning-permission',
3452
'Apply for householder planning permission',
35-
'{"_root":{"edges":["n1","n2","n3"]},"n1":{"type":300,"data":{"title":"Householder Planning Permission","description":"<p>Apply for planning permission for works to a house or its grounds.</p>"}},"n2":{"type":110,"data":{"title":"Describe the proposed works","fn":"proposal.description"}},"n3":{"type":725,"data":{"title":"Application submitted","description":"<p>Your application has been submitted.</p>"}}}'::jsonb,
36-
'online', now(), now(), 1001
37-
) ON CONFLICT (id) DO NOTHING;
53+
$${
54+
"_root": {"edges": ["intro_001","question_1","describe_1","confirm_01"]},
55+
"intro_001": {
56+
"type": 8,
57+
"data": {
58+
"title": "Apply for householder planning permission",
59+
"description": "<p>This sample service walks through the kind of questions a council might ask before you submit a planning application. NDX:Try lets you customise it freely.</p>",
60+
"color": "#EFEFEF",
61+
"resetButton": false
62+
}
63+
},
64+
"question_1": {
65+
"type": 100,
66+
"data": {
67+
"text": "What type of work are you proposing?",
68+
"description": "<p>Pick the option that best matches your project. The questions afterwards adjust based on your answer.</p>",
69+
"neverAutoAnswer": false,
70+
"alwaysAutoAnswerBlank": false
71+
},
72+
"edges": ["ans_ext_001","ans_loft_01","ans_garden1"]
73+
},
74+
"ans_ext_001": {"type": 200, "data": {"text": "Single-storey rear extension"}, "edges": ["content_ext"]},
75+
"ans_loft_01": {"type": 200, "data": {"text": "Loft conversion"}, "edges": ["content_lft"]},
76+
"ans_garden1": {"type": 200, "data": {"text": "Garden room or outbuilding"}, "edges": ["content_grd"]},
77+
"content_ext": {
78+
"type": 250,
79+
"data": {"content": "<h2>Single-storey rear extension</h2><p>Most single-storey rear extensions on terraced or semi-detached homes can be built under <em>permitted development</em> rights without a full planning application, provided they meet size and design limits.</p><p>Check the latest limits on the <a href=\"https://www.gov.uk/guidance/permitted-development-rights\">Planning Portal</a> before you continue.</p>"}
80+
},
81+
"content_lft": {
82+
"type": 250,
83+
"data": {"content": "<h2>Loft conversion</h2><p>Loft conversions are usually permitted development, but rear dormer windows on the principal elevation of a terraced house are not. You may need full planning permission and Building Regulations approval.</p>"}
84+
},
85+
"content_grd": {
86+
"type": 250,
87+
"data": {"content": "<h2>Garden room or outbuilding</h2><p>Outbuildings under 2.5m high near a boundary, with a footprint less than half the garden, are usually permitted development. Designs over that, or with sleeping accommodation, need planning permission.</p>"}
88+
},
89+
"describe_1": {
90+
"type": 110,
91+
"data": {
92+
"title": "Describe your proposed works",
93+
"description": "<p>Tell us briefly what you want to build, in your own words.</p>",
94+
"type": "long",
95+
"fn": "proposal.description",
96+
"isRequired": true
97+
}
98+
},
99+
"confirm_01": {
100+
"type": 725,
101+
"data": {
102+
"heading": "Application submitted",
103+
"color": "#EFEFEF",
104+
"moreInfo": "<p><strong>What happens next?</strong></p><p>A planning officer will review your application within 8 weeks. You will be contacted if they need more information.</p>",
105+
"contactInfo": "<p>Need to chase? Email <a href=\"mailto:planning@ndx-demo.example.com\">planning@ndx-demo.example.com</a>.</p>"
106+
}
107+
}
108+
}$$::jsonb,
109+
'online', now(), now(), 1001, 1
110+
) ON CONFLICT (id) DO UPDATE SET
111+
-- Existing leases that came up with an older revision of this seed
112+
-- (e.g. the legacy two-flow shape) keep the same UUID but need their
113+
-- slug, name, data, AND version refreshed when the Hasura image is
114+
-- rebuilt. flows.version must be non-null or sharedb-postgresql's
115+
-- getSnapshot falls into its "no document" branch, the editor's
116+
-- subscribeToDoc calls doc.create({nodes:{}, edges:[]}) and the seeded
117+
-- data is silently replaced with an empty doc on first open.
118+
slug = EXCLUDED.slug,
119+
name = EXCLUDED.name,
120+
data = EXCLUDED.data,
121+
status = EXCLUDED.status,
122+
version = EXCLUDED.version,
123+
updated_at = now();
38124

39-
INSERT INTO flows (id, team_id, slug, name, data, status, created_at, updated_at, creator_id)
40-
VALUES (
41-
'b2c3d4e5-f6a7-8901-bcde-f12345678901', 26,
42-
'lawful-development-certificate',
43-
'Apply for a lawful development certificate',
44-
'{"_root":{"edges":["l1","l2","l3"]},"l1":{"type":300,"data":{"title":"Lawful Development Certificate","description":"<p>Find out if your development is lawful.</p>"}},"l2":{"type":110,"data":{"title":"Describe the development","fn":"proposal.description"}},"l3":{"type":725,"data":{"title":"Application submitted"}}}'::jsonb,
45-
'online', now(), now(), 1001
46-
) ON CONFLICT (id) DO NOTHING;
125+
-- Drop any other team-26 flows that pre-date this seed revision (the old
126+
-- two-flow seed inserted a second UUID that's no longer referenced).
127+
DELETE FROM operations WHERE flow_id IN (
128+
SELECT id FROM flows WHERE team_id = 26 AND id <> 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
129+
);
130+
DELETE FROM published_flows WHERE flow_id IN (
131+
SELECT id FROM flows WHERE team_id = 26 AND id <> 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
132+
);
133+
DELETE FROM flows WHERE team_id = 26 AND id <> 'a1b2c3d4-e5f6-7890-abcd-ef1234567890';
134+
135+
-- ShareDB requires at least one matching `operations` row per flow; the
136+
-- editor's flow list also reads operations[0].createdAt for "last edited"
137+
-- (a missing op makes the team page crash with "RangeError: Invalid time
138+
-- value"). One op at version 1 with the snapshot data is the minimum.
139+
INSERT INTO operations (flow_id, actor_id, version, data, created_at, updated_at)
140+
SELECT id, 1001, 1, '{}'::jsonb, now(), now() FROM flows WHERE team_id = 26
141+
ON CONFLICT DO NOTHING;
142+
143+
-- 8. Pre-publish the demo flow so the public viewer at
144+
-- /<team>/<flow>/published renders without the user having to click Publish
145+
-- in the editor first. The published_flows row stores a frozen snapshot of
146+
-- flow.data at the moment of publish; we copy the same data here.
147+
INSERT INTO published_flows (
148+
flow_id, publisher_id, summary, data,
149+
has_send_component, has_pay_component, has_sections, service_charge_enabled,
150+
created_at
151+
)
152+
SELECT id, 1001, 'Initial publish', data,
153+
false, false, false, false, now()
154+
FROM flows WHERE team_id = 26
155+
ON CONFLICT DO NOTHING;

cloudformation/scenarios/planx/docker/sharedb/Dockerfile

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,20 @@ WORKDIR /app
99
# Copy the full monorepo
1010
COPY planx-src/ .
1111

12-
# Install dependencies
13-
RUN pnpm install --frozen-lockfile 2>/dev/null || pnpm install
12+
# Install sharedb deps inside its own dir. Upstream's sharedb.planx.uk has its
13+
# own pnpm-lock.yaml; the root has no pnpm-workspace.yaml that links it, so a
14+
# root-level install only brings in `typescript` and the sharedb deps go
15+
# missing. (Same fix pattern as editor and api Dockerfiles.)
16+
RUN cd sharedb.planx.uk && (pnpm install --frozen-lockfile || pnpm install)
1417

15-
# Build ShareDB
16-
RUN cd sharedb.planx.uk && pnpm build 2>/dev/null || true
18+
# ShareDB has no build step — server.js runs directly from source.
1719

1820
# Production stage
1921
FROM node:24.14-alpine AS production
2022

2123
WORKDIR /app
2224

2325
COPY --from=build /app/sharedb.planx.uk/ ./
24-
# ShareDB may not have a build step — it runs server.js directly
2526

2627
ENV PORT=8000
2728
ENV NODE_ENV=production

0 commit comments

Comments
 (0)