Skip to main content

Form Builder

Overview

Form Builder creates forms for LINE users to fill in — registration forms, surveys, or prize-draw entries. Each form carries a form hash as its public identifier, and every answer is stored in the form_submission table.

The module's standout capability is profile mapping, which binds individual answers to fields in the Customer Database or to a LINE user's custom attributes, so submitted data flows straight back into the profile.

It also provides a rule system, stored in form_builder_rule, for conditional logic within a form — for example, skipping to a different question based on an answer — along with a set of common rules shared across forms.

Form responses are an important data source for Audience Filter and act as a trigger source for Trigger Rule.

Business Flow

Authoring a form

  1. GET /api/form-builder/common-rules loads the standard rule set for the form editor to use.
  2. POST /api/form-builder (multipart/form-data) creates a form, specifying questions, answer types, rules, and profile mapping. The system generates the form hash automatically.
  3. GET /api/form-builder lists all forms with pagination; GET /api/form-builder/:id returns a single form.
  4. PUT /api/form-builder/:id (form-data) updates a form and DELETE /api/form-builder/:id removes it.

Collecting and reading responses

  1. LINE users open the form through client-web or LIFF and submit their answers. Submission itself is handled by client-api, not by this module, and if OTP is enabled on the form the respondent must verify their phone number first.
  2. GET /api/form-builder/:id/responses reads submissions with pagination and filtering per FormSubmissionDto.
  3. GET /api/form-builder/:id/stats summarises statistics per question for the form's dashboard.
  4. GET /api/form-builder/:id/export exports all responses as a CSV file.
  5. Answers covered by profile mapping are written back into the Customer Database or the LINE user's custom attributes.
  6. Each new submission publishes an event to the form_submitted_trigger queue so Trigger Rule can act on it.

Key Files & Functions

Core code lives in internal/modules/formbuilder/, comprising controller.go, service.go, and dto.go. The service consolidates the logic of three TypeScript repositories (form-builder.repository.ts, form-builder-rule.repository.ts, and form-submission.repository.ts) into a single file.

MethodRouteHandlerPolicy (metadata)
GET/api/form-builderct.getAllForms
GET/api/form-builder/common-rulesct.getCommonRule
GET/api/form-builder/:idct.getFormById
GET/api/form-builder/:id/responsesct.getFormResponses
GET/api/form-builder/:id/statsct.getFormResponseStats
GET/api/form-builder/:id/exportct.exportResponses
POST/api/form-builderct.createFormcreate form-builder
PUT/api/form-builder/:idct.updateFormupdate form-builder
DELETE/api/form-builder/:idct.deleteForm

Every route is wrapped by modulegate.ModuleGate(d, "form-builder"). The function other modules call is GetFormById(ctx, id), which Audience Filter invokes through an interface.

Connections to Other Services

  • Access controlModuleGate("form-builder") is actively enforced here. PolicyModuleFormBuilder appears as metadata only on the create and update handlers.
  • Tablesform_builder, form_builder_rule, form_submission, customer_database, customer_database_row, line_user, otp_config
  • RabbitMQ — publishes to the form_submitted_trigger queue.
  • Storage Service — holds form attachments and exported CSV files.
  • Cross-module — consumed by Audience Filter, and linked to Customer Database through the databaseId key inside profile_mapping.
  • Related modules — OTP Config, Trigger Rule, Audience Filter, and Customer Database.