CatalyzeUp
sondely

Moving Sondely to the TourCockpit platform

Decided by Chip on 5 November 2026: Sondely moves entirely onto the TourCockpit platform. It becomes one Next.js application (API and screens) on Prisma and Postgres, with TourCockpit's framework, test pyramid (unit, integration, component, end to end, usability), translation system and agent layer (MCP, chat, voice, and later WhatsApp). What Sondely writes itself is its business logic: surveys, scoring, assessments, sessions, reminders, impact and exports.

Chip's goal on 7 November 2026: a new repository, the full product moved over, a full agentic system with voice and charts, and a name for the assistant. What was built on 7 and 8 November 2026:

  • A new repository, CatalyzeUp/sondely-platform, whose root is the Next.js application. It replaces the server/ folder inside CatalyzeUp/sondely that these pages first planned; the Python app and the Vite app stay in CatalyzeUp/sondely until the cutover. Where a page still names a path under server/, read it as the same path at the root of sondely-platform.
  • The framework base is ideaplaces-tour-platform at 74e9a2a53 (7 November 2026), not the f952d0eea these pages were read at; framework-base.json in the repository records it (Framework Copy).
  • The full product: the API route groups, the scoring engine, sessions and responses, the nine templates, translations, impact reports with CSV and PDF exports, assignments and reminders, notification settings, API keys, and the screens, built in Next.js directly rather than behind a Vite fallback.
  • The assistant, named Sona (it echoes Sondely, sondage and sonar): the in-app chat drawer, an MCP server with OAuth, survey charts in the conversation, and a voice call in the browser for owners and admins (Agent Layer).
  • Infrastructure and deploy: Postgres servers, container apps at platform-dev.sondely.com and platform.sondely.com (temporary hosts until the cutover), and a deploy after green CI (Infrastructure).
  • The data migration script, rehearsed on dev, then on production data: impactpulse_prod copied into the new production Postgres with verification passing, while the Python app stays live (Cutover Runbook).
  • Production deployed: platform.sondely.com serves commit a003202 from main with the database reachable; platform-dev.sondely.com serves dev.

sondely.com is still served by the Python app on Cosmos, so the copy in the new production database goes stale; the migration is idempotent and runs again at the cutover. The production reminder job stays off until then, so nobody is reminded twice. The cutover is the open step: Switchover checklist.

Chip on risk: "there will be bugs, not a problem". The plan does not promise none. It catches them in layers, before and after the cutover, and turns each one into a failing test first: Testing and Catching Bugs.

This section is the full documentation for the move. Each page is specific enough to build from.

The pages

Page Answers
Framework Copy Manifest Every TourCockpit file: copied as is, copied and stripped, later, or left behind, with the domain imports to cut, the target path and the copy procedure
Data Model: Mongo to Postgres Every Mongo collection field by field, the draft Prisma schema, JSON columns, tenant columns, and the data quirks found in Cosmos
Sign-in, Sessions and API Keys Every sign-in method today and its target, respondent grants, org-bound keys, and the security holes with how the new design closes each
API Route Map All 95 routes with their roles, schemas, writes, dry run and idempotency needs, the Sondely error codes, and the new routes
Business Logic to Port The survey rules as numbered, testable statements: question types, scoring, the nine templates, lifecycle, sessions, reminders, impact, exports, content translation
Testing and Catching Bugs The contract suite, running the Python suite against both backends, the test pyramid adopted, CI gates, and the bug-catching layers
Screens into Next.js All 30 screens, the order they move in, the Vite fallback, the token move to a cookie, custom domains
Agent Layer Sona: MCP, in-app chat with charts, builder voice in the browser, then respondents by WhatsApp and by voice: what is copied from Faro, what is rewritten for surveys, and the scenario tests
Cutover Runbook The migration script as built and what it does not do yet, rehearsals, the verification checks, cutover day step by step, rollback, decommissioning
Infrastructure and Deploy Terraform for Postgres, roles, secrets, the container apps and Sona's voice; the Docker image; CI and the deploy after green CI; monitoring
Translation TourCockpit's catalog system, moving Sondely's catalogs into it, and survey content translation kept separate

Why the agent layer is the point of the move: Sondely as an Agent.

Phases

The phases were planned in the order below the diagram. The build of 7 and 8 November 2026 took them in a different order: the screens and the agent layer were built before the data cutover, in the same repository, and the contract suite of phase 1 was not built. The diagram shows the order as built; green is built, white is open.

# Phase Done means State on 8 November 2026 Detail
0 Security fixes in Python Known holes closed in the running app. Chip accepted the risk for now on 5 November 2026; the holes stay listed so they are not lost Unchanged: the Python app still serves sondely.com Auth
1 Contract suite TypeScript tests against /api/v1 that record today's behaviour, green against Python Not built. The new app was written from the Python code and these pages, with its own tests; the Python scoring cases became TypeScript tests Testing
2 Scaffold and infrastructure A Next.js repository with the copied framework, CI, Postgres through Terraform, the Prisma schema, tenant isolation test green. No traffic yet Built: CatalyzeUp/sondely-platform, deployed to platform-dev.sondely.com Framework, Infrastructure
3 Parity Every route group ported; contract suite green against TypeScript; read-by-read diff empty on a production snapshot; scores identical Route groups ported. No contract suite and no read-by-read diff; scores are recomputed and compared by the migration verifier Routes, Business logic
4 Cutover Write freeze, migrate, verify, move sondely.com to the new app; Python app and Cosmos kept for the rollback window Open, Chip's call. The migration is rehearsed on dev and on production data, both verified, with nothing quarantined; the production app is deployed at platform.sondely.com Runbook
4b Screens into Next Survey taking and landing first, usability verified on phone and desktop; done when the Vite app serves nothing and is deleted Built before the cutover, all in Next.js; the Vite app keeps serving sondely.com until the cutover Screens, Translation
5 Legible API Validator, dry run, classed error codes, key scopes, question update and reorder, soft delete Built with the copied framework: strict schemas, dry run, coded errors classed for the assistant, idempotency, organization-bound keys Agent layer
6 MCP From one sentence in Claude, a valid translated draft, published only after its own yes, proven in CI Built: the MCP server with OAuth, the same tools and proposals as the drawer Agent layer
7 In-app chat The same scenarios pass in the drawer, rules parity test green Built: Sona in the drawer, with survey charts. The nightly live-model suites are not built Agent layer
7v Builder voice Owners and admins call Sona from the browser, with charts shown during the call Built (decided by Chip's goal of 7 November 2026) Agent layer
8a, 8b Respondents by WhatsApp text, then voice Questions sent word for word by code, consent and channel recorded, resume across days Open, the later phase Agent layer

Sized by complexity: phases 1 to 4 are the bulk, and the data move in phase 4 is the only step that cannot easily be undone, which is why nothing else changes with it. Phases 5 to 7 are mostly copying and stripping what TourCockpit already proved. Phase 8 is a product decision first.

What is open

As of 8 November 2026:

  1. The cutover of sondely.com from the Python app to the new one. Chip's call (Runbook).
  2. The production data migration at the cutover: the rehearsal copy of 8 November 2026 verifies, but goes stale while the Python app keeps writing, so the cutover empties the database and migrates again. The write freeze it needs is not built (Runbook).
  3. Respondents by WhatsApp and by voice (phases 8a and 8b), behind the consent and data processing decision (Agent layer).
  4. Dependency advisories: after the upgrade of Next.js to 15.5.29 closed the critical advisory, ten high severity advisories remain (and ten moderate), all in transitive dependencies, some reached through Prisma.

What the research found

Found while writing these pages, from the code and from Azure (read only):

  • Security beyond the holes known on 3 November. Twelve more are listed on the Auth page. The most exposed today:
    • The seeded key ip_live_wehappers_dev_key_00001, written in plain text in backend/app/main.py, answers on production, and keys are not limited to one organization.
    • The dev app runs with ENVIRONMENT=development and is reachable from outside, so /api/v1/dev/emails shows every sign-in code sent on dev.
    • Anyone can join any organization as a respondent and then read its member and invitee emails.
  • WeHappers does not share Sondely's database. It calls Sondely production as an API client with that hard-coded key, and its data is a tenant inside impactpulse_prod. The cutover keeps those routes in the contract suite and rotates the key first (Runbook).
  • Scores need deliberate parity: Python rounds ties to even, and a scoring setting stored as null scores differently from a missing one (Business logic).
  • Bugs to fix rather than copy: one attempt can create two response records, three retake checks disagree, reminders can be sent twice because the loop runs on every replica, draft translations reach respondents, the survey builder recreates every question on save.
  • Specs that drifted from the code: Maslow has 6 groups and 24 questions in code, the stored score is a raw sum, there are nine templates. The pages specify what the code does.
  • No error monitoring: Sondely logs to law-catalyzeup, which the C3 self-healing monitor does not read. Wiring it is a condition of the cutover (Testing).
  • TourCockpit's error code table has 65 codes, not the 69 an earlier version of these pages stated.

Decisions taken

  • Postgres (decision 1): new CatalyzeUp servers, psql-catalyzeup-sondely and psql-catalyzeup-sondely-dev, as recommended. Built on 7 November 2026 (Infrastructure).
  • CI runners (decision 4): GitHub-hosted runners; the Nous pool is not registered for CatalyzeUp. Taken with the build on 7 November 2026 (Infrastructure).
  • A new repository instead of a server/ folder in CatalyzeUp/sondely: CatalyzeUp/sondely-platform, from Chip's goal of 7 November 2026.
  • The assistant's name (agent layer decision 1): Sona, from Chip's goal of 7 November 2026 (Agent layer).
  • Voice for builders first: owners and admins call Sona from the browser, from Chip's goal of 7 November 2026 ("a full agentic system with voice and charts"). The plan listed voice only for respondents; respondent voice stays the later phase (Agent layer).

Decisions for Chip

The numbers are kept as first written, because other pages refer to them. Decisions 1 and 4, and the name in 11, are taken (above).

Infrastructure and data:

  1. Postgres: taken, new CatalyzeUp servers.
  2. Existing ip_live_ API keys: keep accepting them once and rehash, or rotate all at cutover (Auth).
  3. Rollback window and writes after cutover: recommended is exporting new rows for re-entry rather than a reverse migration (Runbook).
  4. CI runners: taken, GitHub-hosted runners.
  5. Answers: JSON for parity, or an answer table now (Data model).

Product behaviour (parity or fix):

  1. Error format: coded errors at cutover, or keep {detail} until phase 5. Fourteen frontend files read .detail today (Routes).
  2. Translations shown to respondents: drafts as today, or approved only (Business logic).
  3. Scoring edge cases: non-whole ratings, unscored questions in group results, null versus missing scoring settings (Business logic).
  4. "No memberships means admin": keep the rule, or replace it with an explicit onboarding state (Auth).
  5. Interface languages: English, French and Spanish as today, or more; and whether a person signs off a locale (Translation).

Agent layer, later:

  1. MCP keys read only, editing a published survey, a session resumed on another channel, call recording consent, reminders by WhatsApp (Agent layer). The assistant's name is taken: Sona.

Cutover:

  1. When sondely.com moves from the Python app to the new one, which starts the production data migration (Runbook).