Kaizen
Browse modulesFormsforms/serverClasses

Class: FormSubmissionService

Defined in: server/forms/form-submission-service.ts:48

Extends

Constructors

Constructor

new FormSubmissionService(deps: FormFeatureDeps): FormSubmissionService;

Defined in: server/forms/base-form-service.ts:5

Parameters

ParameterType
depsFormFeatureDeps

Returns

FormSubmissionService

Inherited from

BaseFormService.constructor

Properties

deps

protected readonly deps: FormFeatureDeps;

Defined in: server/forms/base-form-service.ts:5

Inherited from

BaseFormService.deps

Accessors

actorId

Get Signature

get protected actorId(): string | null;

Defined in: server/forms/base-form-service.ts:7

Returns

string | null

Inherited from

BaseFormService.actorId

Methods

advanceStep()

advanceStep(submissionId: string, input: {
  extensions?: FormDataRecord;
  fromStepKey: string;
  stepData: FormDataRecord;
  user?: {
     email?: string;
     id: string;
     organizationId?: string;
     roles?: string[];
  };
}): Promise<{
  nextStepIsTerminal: boolean;
  nextStepKey: string;
  submission: FormSubmissionWithVersion;
}>;

Defined in: server/forms/form-submission-service.ts:479

Wizard navigation: validate the current step's fields, merge them into data, evaluate the step's outgoing transitions against the pinned rule versions, and advance the draft in place.

Same-row update: the draft FormSubmissionVersions row's data, visitedStepKeys, currentStepKey, and lastActivityAt are mutated; no new version row is created. This keeps in-flight drafts cheap and avoids polluting the version history with intermediate states.

Fires the afterStepAdvance hook on success.

Parameters

ParameterType
submissionIdstring
input{ extensions?: FormDataRecord; fromStepKey: string; stepData: FormDataRecord; user?: { email?: string; id: string; organizationId?: string; roles?: string[]; }; }
input.extensions?FormDataRecord
input.fromStepKeystring
input.stepDataFormDataRecord
input.user?{ email?: string; id: string; organizationId?: string; roles?: string[]; }
input.user.email?string
input.user.idstring
input.user.organizationId?string
input.user.roles?string[]

Returns

Promise<{ nextStepIsTerminal: boolean; nextStepKey: string; submission: FormSubmissionWithVersion; }>


assertVersionUnpublished()

protected assertVersionUnpublished(versionId: string): Promise<void>;

Defined in: server/forms/base-form-service.ts:28

Guard that rejects mutations against a published FormSchemaVersion. Once a version is published the DAG (steps, transitions, entry-step key) is frozen — editors must spawn a fresh draft version with FormSchemaService.createDraftVersion to make further changes.

Centralised here so step / transition / future services share one invariant and one error message.

Parameters

ParameterType
versionIdstring

Returns

Promise<void>

Inherited from

BaseFormService.assertVersionUnpublished


create()

create(userId: string, input: {
  data: Record<string, unknown>;
  formSchemaVersionId: string;
}): Promise<FormSubmissionWithVersion>;

Defined in: server/forms/form-submission-service.ts:165

Parameters

ParameterType
userIdstring
input{ data: Record<string, unknown>; formSchemaVersionId: string; }
input.dataRecord<string, unknown>
input.formSchemaVersionIdstring

Returns

Promise<FormSubmissionWithVersion>


createDraft()

createDraft(userId: string, formSchemaId: string): Promise<FormSubmissionWithVersion>;

Defined in: server/forms/form-submission-service.ts:392

Create — or resume — a draft submission for a multi-step (or single-page) form.

Pinned-version contract: the draft's formSchemaVersionId is set once, at creation time, from the schema's current published version. Subsequent schema edits create new versions but do not affect this draft.

Resume semantics: at most one active draft per (user, schema). If the user already has an in-flight draft, it's returned as-is. If they have only a completed submission, a new draft version is appended to the same submission row, prefilled from the latest completed version (cross-version shape-migrated when the pins differ).

Fires the afterDraftCreated hook on success.

Parameters

ParameterType
userIdstring
formSchemaIdstring

Returns

Promise<FormSubmissionWithVersion>


finalizeSinglePage()

finalizeSinglePage(submissionId: string, input: {
  data: FormDataRecord;
  visitedStepKeys: string[];
}): Promise<FormSubmissionWithVersion>;

Defined in: server/forms/form-submission-service.ts:808

Single-page-mode finalization: commit the whole form in one call, skipping per-step advanceStep. Server-side validation is authoritative; the client's check is a nicety.

Used when the schema's renderMode is single-page — the form is still authored as steps + transitions so we can reuse the publish validator and DAG checks, but at runtime the user fills every field at once and the renderer never advances through them.

Parameters

ParameterType
submissionIdstring
input{ data: FormDataRecord; visitedStepKeys: string[]; }
input.dataFormDataRecord
input.visitedStepKeysstring[]

Returns

Promise<FormSubmissionWithVersion>


getActiveDraftForUser()

getActiveDraftForUser(userId: string, formSchemaId: string): Promise<FormSubmissionWithVersion | null>;

Defined in: server/forms/form-submission-service.ts:92

Returns the user's in-flight draft for formSchemaId, or null if none. Pairs with createDraft for callers that want to distinguish "user has a draft to resume" from "fresh start" before mutating — createDraft would also transparently resume an existing draft, but the explicit lookup lets UIs surface the resume state up front instead of silently picking one.

Composed from FormSubmissionRepository.findLatestForUser and FormSubmissionVersionRepository.findActiveDraft; null is returned both when the user has never submitted and when their latest submission has no active draft (already completed, no edit-in-progress).

Parameters

ParameterType
userIdstring
formSchemaIdstring

Returns

Promise<FormSubmissionWithVersion | null>


getByFormSchemaId()

getByFormSchemaId(formSchemaId: string): Promise<FormSubmission[]>;

Defined in: server/forms/form-submission-service.ts:72

Parameters

ParameterType
formSchemaIdstring

Returns

Promise<FormSubmission[]>


getById()

getById(id: string): Promise<FormSubmission>;

Defined in: server/forms/form-submission-service.ts:49

Parameters

ParameterType
idstring

Returns

Promise<FormSubmission>


getByIdWithCurrentVersion()

getByIdWithCurrentVersion(id: string): Promise<FormSubmissionWithVersion>;

Defined in: server/forms/form-submission-service.ts:54

Parameters

ParameterType
idstring

Returns

Promise<FormSubmissionWithVersion>


getByUserId()

getByUserId(userId: string): Promise<FormSubmission[]>;

Defined in: server/forms/form-submission-service.ts:67

Parameters

ParameterType
userIdstring

Returns

Promise<FormSubmission[]>


getDraftForRender()

getDraftForRender(submissionId: string): Promise<{
  conditionsTable: ConditionsTable;
  entryStepKey: string | null;
  renderMode: "wizard" | "single-page";
  steps: {
     description: string | null;
     fields: {
        additionalInfo?: {
           body?: string;
           title?: string;
        };
        adoptionStatement?: string;
        allowedFonts?: string[];
        asset?: {
           alt?: string;
           fileId?: string;
           filename?: string;
           mimeType?: string;
           url?: string;
        };
        dataSource?: string;
        defaultValue?:   | string
           | {
           from: string;
           to: string | null;
         };
        description?: string;
        fields?: {
           additionalInfo?: {
              body?: ...;
              title?: ...;
           };
           adoptionStatement?: string;
           allowedFonts?: ...[];
           asset?: {
              alt?: ...;
              fileId?: ...;
              filename?: ...;
              mimeType?: ...;
              url?: ...;
           };
           dataSource?: string;
           defaultValue?:   | string
              | {
              from: ...;
              to: ...;
            };
           description?: string;
           format?: string;
           label: string;
           maxDate?: string;
           maxFiles?: number;
           maxLength?: number;
           minDate?: string;
           name: string;
           options?: ...[];
           placeholder?: string;
           prefillFrom?: string;
           required: boolean;
           showRange?: boolean;
           showTime?: boolean;
           signatureMode?: "typed" | "drawn";
           timezone?: string;
           type:   | "number"
              | "date"
              | "file"
              | "email"
              | "url"
              | "select"
              | "text"
              | "checkbox"
              | "textarea"
              | "phone"
              | "radio-group"
              | "multiselect"
              | "field-array"
              | "image"
              | "file-download"
              | "section-header"
              | "section-unset"
              | "signature"
              | "signature-adopted";
        }[];
        format?: string;
        label: string;
        maxDate?: string;
        maxFiles?: number;
        maxLength?: number;
        maxRows?: number;
        minDate?: string;
        minRows?: number;
        name: string;
        options?: (
           | string
           | {
           description?: ... | ...;
           value: string;
        })[];
        placeholder?: string;
        prefillFrom?: string;
        required: boolean;
        showRange?: boolean;
        showTime?: boolean;
        signatureMode?: "typed" | "drawn";
        timezone?: string;
        type:   | "number"
           | "date"
           | "file"
           | "email"
           | "url"
           | "select"
           | "text"
           | "checkbox"
           | "textarea"
           | "phone"
           | "radio-group"
           | "multiselect"
           | "field-array"
           | "image"
           | "file-download"
           | "section-header"
           | "section-unset"
           | "signature"
           | "signature-adopted";
     }[];
     formSchemaVersionId: string;
     id: string;
     key: string;
     label: string | null;
  }[];
  submission: FormSubmissionWithVersion;
  transitions: FormStepTransitionWithKey[];
}>;

Defined in: server/forms/form-submission-service.ts:885

Single-call convenience for the renderer: returns the active draft with the steps, transitions (pre-joined with fromKey/toKey plus resolved conditionLogic from the pinned rule version), the conditions lookup table referenced by those transitions, and the schema's render mode.

Throws FormNotFoundError("ActiveDraft", id) if there's no in-flight draft on the submission.

Parameters

ParameterType
submissionIdstring

Returns

Promise<{ conditionsTable: ConditionsTable; entryStepKey: string | null; renderMode: "wizard" | "single-page"; steps: { description: string | null; fields: { additionalInfo?: { body?: string; title?: string; }; adoptionStatement?: string; allowedFonts?: string[]; asset?: { alt?: string; fileId?: string; filename?: string; mimeType?: string; url?: string; }; dataSource?: string; defaultValue?: | string | { from: string; to: string | null; }; description?: string; fields?: { additionalInfo?: { body?: ...; title?: ...; }; adoptionStatement?: string; allowedFonts?: ...[]; asset?: { alt?: ...; fileId?: ...; filename?: ...; mimeType?: ...; url?: ...; }; dataSource?: string; defaultValue?: | string | { from: ...; to: ...; }; description?: string; format?: string; label: string; maxDate?: string; maxFiles?: number; maxLength?: number; minDate?: string; name: string; options?: ...[]; placeholder?: string; prefillFrom?: string; required: boolean; showRange?: boolean; showTime?: boolean; signatureMode?: "typed" | "drawn"; timezone?: string; type: | "number" | "date" | "file" | "email" | "url" | "select" | "text" | "checkbox" | "textarea" | "phone" | "radio-group" | "multiselect" | "field-array" | "image" | "file-download" | "section-header" | "section-unset" | "signature" | "signature-adopted"; }[]; format?: string; label: string; maxDate?: string; maxFiles?: number; maxLength?: number; maxRows?: number; minDate?: string; minRows?: number; name: string; options?: ( | string | { description?: ... | ...; value: string; })[]; placeholder?: string; prefillFrom?: string; required: boolean; showRange?: boolean; showTime?: boolean; signatureMode?: "typed" | "drawn"; timezone?: string; type: | "number" | "date" | "file" | "email" | "url" | "select" | "text" | "checkbox" | "textarea" | "phone" | "radio-group" | "multiselect" | "field-array" | "image" | "file-download" | "section-header" | "section-unset" | "signature" | "signature-adopted"; }[]; formSchemaVersionId: string; id: string; key: string; label: string | null; }[]; submission: FormSubmissionWithVersion; transitions: FormStepTransitionWithKey[]; }>


getSubmissionPrefill()

getSubmissionPrefill(userId: string, formSchemaId: string): Promise<
  | CrossVersionPrefillResult
| null>;

Defined in: server/forms/form-submission-service.ts:116

Prefill values for a user's next submission of a form schema. Locates the user's most recent submission, and either passes the data through (same schema version) or runs cross-version prefill against the current schema (different version).

Returns null if the user has no previous submission for this schema.

Parameters

ParameterType
userIdstring
formSchemaIdstring

Returns

Promise< | CrossVersionPrefillResult | null>


goToPreviousStep()

goToPreviousStep(submissionId: string): Promise<FormSubmissionWithVersion>;

Defined in: server/forms/form-submission-service.ts:632

Wizard back-navigation: pop the current step off visitedStepKeys and re-pin currentStepKey to the new tail. Field data on the popped step is left on data so a forward re-walk along the same path re-hydrates the inputs; if the user re-routes across a branching transition, submitDraft / finalizeSinglePage's visited-path filter strips the orphaned answers from the validated payload.

Refuses to navigate back from the entry step (only key in the visited stack). Throws FormNotFoundError("ActiveDraft", id) if there's no in-flight draft, and FormValidationError if already at the first step.

Parameters

ParameterType
submissionIdstring

Returns

Promise<FormSubmissionWithVersion>


setUserEditing()

setUserEditing(id: string, allowed: boolean): Promise<FormSubmission>;

Defined in: server/forms/form-submission-service.ts:367

Override whether this specific submission allows user editing. Takes precedence over the schema's allowUserEditing default. Callers that expose editing UIs should gate on FormSubmission.allowUserEditingOverride.

Parameters

ParameterType
idstring
allowedboolean

Returns

Promise<FormSubmission>


softDelete()

softDelete(id: string): Promise<FormSubmission>;

Defined in: server/forms/form-submission-service.ts:357

Parameters

ParameterType
idstring

Returns

Promise<FormSubmission>


submitDraft()

submitDraft(submissionId: string, input?: {
  stepData?: FormDataRecord;
}): Promise<FormSubmissionWithVersion>;

Defined in: server/forms/form-submission-service.ts:701

Submit a multi-step draft.

Terminal-step data: advanceStep refuses to walk past a terminal step (no outgoing transitions), so the terminal step's field values never reach the draft via the wizard's normal merge path. Pass them here as stepData and they're validated against the terminal step's schema, merged into the draft data, and persisted before whole-form revalidation runs. Omit stepData only when the terminal step has no fields (e.g. a pure confirmation page).

Whole-form revalidation runs against the visited path (only the fields the user actually saw). Orphaned answers — answers belonging to fields on non-visited steps, e.g. when the user backtracked across a branching decision — are preserved on data for audit but stripped from the validated payload.

Refuses to submit from a non-terminal step (one with outgoing transitions). Fires afterSubmissionCreated on success.

Parameters

ParameterType
submissionIdstring
input?{ stepData?: FormDataRecord; }
input.stepData?FormDataRecord

Returns

Promise<FormSubmissionWithVersion>


transaction()

protected transaction<T>(fn: (deps: FormFeatureDeps) => Promise<T>): Promise<T>;

Defined in: server/forms/base-form-service.ts:11

Type Parameters

Type Parameter
T

Parameters

ParameterType
fn(deps: FormFeatureDeps) => Promise<T>

Returns

Promise<T>

Inherited from

BaseFormService.transaction


update()

update(id: string, input: {
  changeReason?: string;
  data: Record<string, unknown>;
  formSchemaVersionId: string;
}): Promise<FormSubmissionWithVersion>;

Defined in: server/forms/form-submission-service.ts:259

Parameters

ParameterType
idstring
input{ changeReason?: string; data: Record<string, unknown>; formSchemaVersionId: string; }
input.changeReason?string
input.dataRecord<string, unknown>
input.formSchemaVersionIdstring

Returns

Promise<FormSubmissionWithVersion>

On this page