Table of Contents
20 — Questionnaire template management
Technical reference. For task-based help, see the corresponding user guide.
Documentation status: complete for the current implementation
Reviewed: 2026-07-21
Primary users: subscribed coaches
Surfaces: coach admin portal and platform API
Purpose
Questionnaire templates let a coach maintain a reusable catalogue of intake and follow-up forms. A template defines the family-facing title, explanatory copy, sections, question order and response controls. One active template is the default, but a coach can choose any active template when inviting a family or adding a later questionnaire in Session Prep.
Templates are authoring sources, not live family forms. Assigning one creates a self-contained snapshot. Editing, changing the default or removing the source template does not rewrite an existing family's questions or answers.
User outcomes
| Coach need | Outcome |
|---|---|
| Maintain different forms | Create and name multiple active templates for different ages, services or stages of support. |
| Start from proven content | Duplicate a template and edit the copy without changing the source. |
| Standardize new assignments | Mark exactly one active template as the default. |
| Build structured forms | Arrange questions into sections and use six supported answer types. |
| Personalize assignment | Select a template for an invitation or add a new snapshot from Session Prep. |
| Retire old content safely | Remove a template from future use while retaining all assigned snapshots and responses. |
Entry points
| Surface | Route/location | Function |
|---|---|---|
| Coach portal | /questionnaires | Manage the active template collection. |
| Coach portal compatibility route | /questionnaire-template | Opens the same questionnaire manager for older links. |
| New-family invitation | Questionnaire selector | Use the default, choose another active template or choose Send later / no questionnaire yet. |
| Session Prep | Add questionnaire | Create another independent family questionnaire from an active template. |
The portal protects the questionnaire manager with the coach subscription gate. The platform also verifies the coach role, active organization membership, organization state and coach subscription instead of trusting route visibility.
Template collection and default
The active list is sorted with the default first, then by name and creation time. Each card shows its internal name, family-facing title, question count, update date, default badge and unsaved badge. The API also returns the assigned-family-questionnaire count; the current manager uses that count in the removal confirmation rather than displaying it on every card.
- A coach/organization scope always has an active default. Reading an empty catalogue creates the built-in starter template.
- The first explicitly created template is default only if no active template already exists.
- Set as default moves the default marker; it does not assign or alter any family questionnaire.
- New invitations preselect the current default, while compatible clients that omit a questionnaire choice also fall back to the server's active default.
- Reusable invite codes resolve the current default when each family redeems the code. A one-use invitation instead stores its selected/default template snapshot when the invitation is created.
Editor model
Template details
Every template has:
- an internal questionnaire name used to distinguish templates in coach tools;
- a family-facing title;
- optional descriptive copy; and
- 1–80 ordered questions.
The editor keeps changes in browser memory until Save. Switching to another template within the mounted manager preserves each template's local dirty draft and displays an Unsaved badge. Reloading or leaving the page does not have a dedicated unsaved-change guard, so uncommitted edits can still be lost.
Sections and question order
Each question requires a section and question label. Questions with the same normalized section name are presented together. A section description is edited on the first question in that section and normalized onto every question in the group when saved.
- Add question appends a long-text starter question.
- Up/down controls reorder questions and the persisted
sortOrderis rebuilt from the visible order. - A question can be removed only while at least one question remains.
- Every question can be required or optional and can include family-facing help text.
Supported question types
| Type | Family input | Template-specific controls |
|---|---|---|
| Long text | Multi-line text | Label, required state and help text. |
| Short text | Single-line text | Label, required state and help text. |
| Single choice | One option | Ordered option list and optional free text per option. |
| Multi choice | More than one option | Ordered option list and optional free text per option. |
| Yes / no | Boolean choice | Label, required state and help text. |
| Number | Numeric input | Label, required state and help text. |
Single- and multi-choice questions require at least one non-empty option and support up to 30 options. Each option has a stable identifier, a display label and an Ask for details switch. Typing Other as an option label automatically turns that switch on, but the coach can turn it off again. When enabled, a family selecting the option can add its own text.
New question/option identifiers are generated by the editor. Option identifiers derived from labels are made unique before write; the server trims option IDs and rejects duplicate question or option IDs. Both kinds are limited to 80 characters by the shared contract. Family answers are validated later against the identifiers and types frozen into their assigned snapshot.
Core workflows
Create
- New creates a template with the internal name New questionnaire, title Pre-session sleep questionnaire, one Session prep long-text question and starter description.
- The server returns the durable template and the editor selects it immediately.
- The new template does not become default when another active default already exists.
Edit and save
- Name, title, description, section content, question text, type, required state, help text and options remain local until Save.
- The client validates the whole template, displays a summary and scrolls to the first invalid field.
- A successful patch replaces the local copy with the normalized server response and clears its dirty badge.
- A failed save leaves the local edits available for correction or retry.
Template writes do not carry a revision or expectedUpdatedAt. Two tabs editing the same template therefore use last-write-wins behavior; saving an older tab can replace a newer saved version.
Duplicate
Duplicate creates a new active template using the selected template's current in-memory content and adds “copy” to its name. This means unsaved edits in the selected template are included in the copy even though the source itself has not been saved. The duplicate has a new identity and is not default.
Set default
Set as default updates the active collection so exactly the selected template is default. It affects subsequent default selection only; issued one-use invitation snapshots and assigned family questionnaires remain unchanged.
Remove
“Remove” is a soft archive of the template:
- the final active template cannot be removed;
- removing the default selects another active template as the replacement before archiving it;
- the archived template disappears from the manager and from new selection lists;
- the response reports how many family questionnaires were retained; and
- no family snapshot is reassigned, rewritten or deleted (
reassignedFamilyQuestionnaireCountremains0).
The portal confirms removal, explicitly warns when families use the template and notes that removal cannot be undone from that screen. Current list/update routes address active templates only, so there is no user-facing restore path for an archived template.
Assignment and snapshot semantics
Invitation-time choice
| Choice | Result |
|---|---|
| Selected active template | The one-use invitation stores that exact template ID, name, title and question snapshot. Acceptance creates the family questionnaire from the stored version. |
| Current default | The same snapshot behavior applies; later default/template changes cannot alter the issued invitation. |
| Send later / no questionnaire yet | Acceptance creates no questionnaire and suppresses legacy implicit creation for that accepted invitation. |
| Choice omitted by an older client | The server snapshots the current active default for backward compatibility. |
Add from Session Prep
The current Session Prep flow sends { templateId } to the plural create endpoint. Each use appends a new independent snapshot, even if the family already has questionnaires. Existing questions, answers, status and submission timestamps are never overwritten.
Compatibility behavior
Older released clients still have singular endpoints:
- singular read may lazily create a default questionnaire when none exists, unless an accepted invitation explicitly chose send-later;
- singular template selection and singular write operate on the latest snapshot; and
- replacing that latest snapshot keeps only answers whose question identifiers remain valid, recalculates progress and clears submission state.
Current coach tooling uses the plural collection/create path. New work must not use a compatibility mutation when the intended outcome is “add another questionnaire.”
Validation and limits
| Rule | Current enforcement |
|---|---|
| Template name | Required, trimmed. |
| Family-facing title | Required, trimmed. |
| Question count | 1–80. |
| Section and question label | Required on every question. |
| Choice options | At least one non-empty option in the portal; no more than 30 in the contract. |
| Question/option ID | Non-empty and at most 80 characters. |
| Save failure | Server error is shown and the local draft stays dirty. |
| Remove final template | Rejected with instruction to create another questionnaire first. |
Platform API contract
| Method and path | Role |
|---|---|
GET /coach/questionnaire-templates | List active templates, usage counts and the default. Creates a starter when the scope has none. |
POST /coach/questionnaire-templates | Create an active template. |
PATCH /coach/questionnaire-templates/:templateId | Update active-template content; archived: true is a compatibility soft-remove path. |
DELETE /coach/questionnaire-templates/:templateId | Soft-remove a template and return replacement/retention information. |
POST /coach/questionnaire-templates/:templateId/default | Make one active template the default. |
GET /coach/questionnaire-template | Legacy singular read of the default. |
PUT /coach/questionnaire-template | Legacy singular default-template write. |
POST /coach/families/:familyId/questionnaires | Append a new family snapshot from templateId. |
GET /coach/families/:familyId/questionnaires | Read every family questionnaire snapshot without creating one. |
GET/PUT /coach/families/:familyId/questionnaire | Legacy latest-snapshot compatibility behavior. |
POST /coach/families/:familyId/questionnaire/template | Legacy replacement of the latest snapshot from a template. |
Authorization and data boundaries
- Templates are scoped by both coach user and organization; a coach cannot address another coach's template ID.
- Template management requires a coach role, active organization membership, an active/trialing organization and qualifying coach subscription.
- Creating a family snapshot additionally requires the matching active assignment and record access for that family.
- Only active, non-archived templates can be selected for a new family snapshot.
- Stored invitation and family snapshots remain readable independently of later source-template edits or removal.
- Family users never receive the coach's full template catalogue; they receive only questionnaires assigned to them.
Acceptance checklist
- A coach can create, edit, duplicate and select among multiple named templates.
- Exactly one active template is default for each coach/organization scope.
- All six question types round-trip with sections, help text, required state and stable ordering.
- Choice questions cannot save without a valid option; Other can request free text.
- Dirty state is visible and server failures do not discard the editor draft.
- Removing the final template is denied and removing a used template retains every family response exactly.
- One-use invitations preserve the exact selection made at invitation time.
- Send later creates no questionnaire on acceptance.
- Session Prep appends a new snapshot and never overwrites earlier answers.
- Compatibility singular mutations are not mistaken for the current plural add flow.
Source evidence
Coach portal
admin-web/src/routes/QuestionnaireTemplatePanel.tsxadmin-web/src/routes/FamilyInvitationsPanel.tsxadmin-web/src/routes/SessionPrepArtifactsPanel.tsxadmin-web/src/routes/AdminDashboard.tsxadmin-web/src/api/client.ts
Platform and contracts
platform/apps/api/src/routes/coach-routes.tsplatform/apps/api/src/services/family-profile-artifact-service.tsplatform/apps/api/src/services/prisma-invite-flow-service.tsplatform/packages/shared/src/family-profile-artifacts.tsplatform/docs/multi-tenancy/05-development-plan.md
