You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
'{"_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,
"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>",
"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 UPDATESET
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.
'{"_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
+
DELETEFROM operations WHERE flow_id IN (
128
+
SELECT id FROM flows WHERE team_id =26AND id <>'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
129
+
);
130
+
DELETEFROM published_flows WHERE flow_id IN (
131
+
SELECT id FROM flows WHERE team_id =26AND id <>'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
132
+
);
133
+
DELETEFROM flows WHERE team_id =26AND 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.
0 commit comments