Blueprint · Support
Surveys
Multi-question surveys with a public respond link and private results. Separate from the CSAT feedback app.
Published by Croft · version 1 · surveysquestionnaireresearchpublic formresultssupport
What this needs
Requires no connections. Runs on demand, when called directly.
Record streams
- answers (write)
- questions (write)
- survey_responses (write)
- surveys (write)
About this blueprint
Surveys is a small survey tool in two pages. The private one builds and reads: create a survey, give it an intro and an open or closed state, add questions of three kinds — free text, single choice from a list of options, or a 1 to 5 rating — reorder them, and then read the results question by question. Ratings come back as an average with the full 1 to 5 spread, choices as proportional bars with counts and percentages, and text answers as a readable list of quotes attributed to whoever left them. A responses tab shows who answered when and how many of the questions they got through. The public one is the respond page: it takes a survey id in the query string, renders that survey's questions in order, marks which ones are required, tracks a progress bar as they are filled in, and lets people answer anonymously if they would rather.
Under the hood there is a single callable workflow over four append-only record streams: surveys, questions, survey responses, and answers. Because a workflow run never hands an id back, the respond page mints the response id itself before writing, which is what lets every answer row point at the response it arrived with. Every write is a full snapshot keyed by a stable id, so editing a question is a newer append and removing one is a tombstone; answers already given stay in the history rather than vanishing with the question. Reordering rewrites two questions' positions as two snapshots, for the same reason. The public respond page can read the survey and its questions and nothing else, because the questions are meant to be read by respondents and the answers are not.
It is built for the surveys that are too long for a one-question rating and too small to justify a survey platform: a post-onboarding questionnaire, an event debrief, an internal pulse check, a pricing sanity test. Set a survey to open, send the link, and watch the bars fill in. For single-question customer satisfaction scoring, the separate Feedback template is the simpler fit; this one is deliberately the multi-question sibling.
How it works
Source — 1 file, show
index.ts
;
/**
* Surveys — the write engine behind the multi-question survey app.
*
* Every entity lives in an append-only record stream as an event log: each
* append is a full snapshot of the row, and the newest row per `id` wins.
* Removals append a tombstone (`_op: "gone"`) rather than erasing history.
* The artifact pages read current state with a `row_number()` window query.
*
* `_op` is "live"/"gone" and never the word "delete", because `records.query`
* rejects COPY EXPORT INSTALL LOAD ATTACH CREATE INSERT UPDATE DELETE PRAGMA
* as whole words anywhere in the SQL text — string literals included.
*
* The appends are written out one stream at a time, rather than through a
* computed stream name, so the analyzer can name every stream this workflow
* touches and an install plan can list them.
*
* This is the multi-question survey app. Single-question customer satisfaction
* scoring is the separate Feedback template.
*/
;
;
Want this running in your own workspace?
Installing recompiles this exact version in your workspace, lands it paused, and walks you through granting whatever it needs above. No account yet? Installing creates one.