Form Builder
Overview
Form Builder lets LINE OA administrators create online forms — much like Google Forms — publish them as a link for LINE users to fill in, and then review the submissions, the completion statistics, and export the data as CSV, all from within the CMS.
The feature is aimed at marketing and customer-care teams who need to collect information from LINE users: event registrations, satisfaction surveys, membership applications, or identity-verification forms that gate a reward. Submissions can be tied back to a Member Database, and a form can require OTP verification before it is accepted.
The feature spans three screens:
| Screen | Route | Purpose |
|---|---|---|
| Form list | /form-builder | Search, filter, copy the public link, edit, view responses, and delete forms |
| Form editor | /form-builder/form | A five-tab editor with a live preview column |
| Responses | /form-builder/response | Statistics, the response table, and CSV export |
Limits and rules worth knowing before you start:
| Topic | Detail |
|---|---|
| Question count | Up to 10 questions per form. Layout elements (heading 1, heading 2, divider) do not count and are unlimited. |
| Demographic questions | First name, last name, email, phone, citizen ID, and date of birth can each be added only once. |
| Form status | draft / active / inactive. Once a form is published as active or inactive it can no longer be reverted to draft. |
| Per-form OTP | One OTP field per form, and it can only be enabled once Profile Mapping is on and a Member Database has been selected. |
| Cover image | JPG or PNG, no larger than 10MB, at least 1024px wide. |
A form is stored as a single document rather than one table per question. Saving therefore submits a multipart payload holding the question set (questions), the theme and cover image (theme, coverImage), the thank-you page (thankYou), the Member Database and OTP configuration (profileMapping), and the answer-to-attribute mapping (fieldAttributeMappings).
Supported question types
| Group | Question types |
|---|---|
| Basic inputs | Short text, paragraph, email, phone, number, file upload, date, URL |
| Demographic | First name, last name, citizen ID, date of birth (with an optional minimum age) |
| Choice | Single choice, multiple choice, dropdown, multi-select dropdown |
| Special | Terms and conditions (link or full text), custom input (regex or alphabetic/numeric patterns with min and max length) |
| Database lookup | Record-validation field (db_validation), available once Profile Mapping is enabled |
| Layout | Heading 1, heading 2, divider |
Conditional display operators
The operators offered depend on the answer type of the parent question being referenced.
| Parent question answer type | Available operators |
|---|---|
| Text | Answered, equals, does not equal, contains, does not contain |
| Number | Answered, equals, does not equal, greater than, greater than or equal, less than, less than or equal, between, not between |
| Date | Answered, equals, does not equal, between, not between |
| Single choice | Equals, does not equal |
| Multiple choice | Answered, equals, does not equal, contains, does not contain |
Layout elements cannot act as the parent of a condition, and range operators render both a lower and an upper value field.
Business Flow
Managing the form list
- Opening the list checks the user's
VIEWpermission on theform-buildermodule before rendering. - The most recent filter is restored from the session; if none exists, the default is newest-first by creation date, 10 rows per page.
- Forms can be filtered by keyword and status. The filter applies only when the search button is pressed, and searching always resets to the first page.
- The table shows the form title, description, the public link with a copy button, creation date, status, and the number of responses received. Only the creation-date column is sortable.
- Each row offers edit, view-responses, and delete actions. Deletion requires confirmation, and the table refreshes in place on success.
Creating and editing a form
- The editor reads its query parameters to decide the working mode — create, edit, duplicate, or view-only — and the page title adapts accordingly.
- Three sets of initial data load in parallel: the existing form (edit mode only), the shared validation rules for each question type, and the list of Member Databases available for Profile Mapping.
- In create mode the editor state is cleared and the status defaults to
draft. In edit mode the questions, theme, thank-you page, and Profile Mapping settings are hydrated back into the form. - General form settings cover the title (required, up to 200 characters), the description (up to 250 characters), a switch to convert visitors into members, a switch to allow only one submission per user, and the publication status.
- Questions are added from the grouped shortcut buttons or from the combined type dropdown. The system assigns a unique default title and applies the shared rule for that type — a file-upload question, for example, arrives with its list of permitted file extensions already filled in.
- Each question can be retyped, marked required, duplicated, deleted, and dragged into a new position.
- Conditional display is configured per question by choosing a parent question, an operator, and a comparison value. The available operators depend on the parent question's input type, and range operators render two value fields.
- Dragging a dependent question above its parent triggers a confirmation dialog and, once confirmed, removes the conditional link — this prevents a condition that references a question the respondent has not reached yet.
- The right-hand column holds a live preview with three views — the form, the OTP verification screen (shown when OTP is enabled), and the thank-you page. The preview follows whichever editor tab is open and renders with the theme colours actually configured.
- Saving runs client-side validation first: at least one question and at least one required question, a title on every question, complete option lists on choice questions, a parent and value on every conditional question, and valid text and buttons on a custom thank-you page.
- Once validation passes, everything is assembled into a single payload and sent as a create or update request, after which the user returns to the list. If the server rejects the request, the API's own message is surfaced to the user.
- Cancelling after a title has been entered or questions have been added prompts for confirmation before leaving the page.
Connecting a form to a Member Database (Profile Mapping)
- Turn on the Profile Mapping switch and pick the Member Database to link against.
- Map database columns to record-validation questions so that the answers can be used to look up the matching member record. New input fields can be added straight from this panel.
- Define what happens when a record is found: which attribute records the verified state and what value is written to it, and whether one LINE account is limited to one record — with the message shown when a record has already been claimed.
- Define what happens when no record is found: reject with a message, or register the respondent as a new record.
- In the Field Mapping tab, map each question's answer to a user custom attribute so the collected data flows back into the member profile.
Configuring per-form OTP verification
- The verification tab appears only for users who have access to the Member Database module.
- The editor reads the LINE OA's OTP channel status from the OTP Verification Settings page to know whether SMS and email are ready to use.
- The "require verification" switch is only actionable when Profile Mapping is on, a database is selected, and that database has at least one column. If any condition is missing, a warning explains why.
- Turning the switch on for the first time seeds a single configuration row with a ready channel selected automatically (SMS first, falling back to email). If no channel is ready, nothing is seeded and the add-field button stays disabled.
- Each row pairs a Member Database column with a delivery channel. Importantly, the code is sent to the value stored in the matched record — not to whatever the respondent typed into the form.
- Four pieces of copy on the verification screen can be customised: the heading, the description, the verify button, and the resend label. Blank fields fall back to the standard wording, and the description supports the
{destination}placeholder for the partially masked contact detail. - If a channel is later disabled in the OA-level OTP settings, the form keeps its configuration but displays a warning with a link to fix it. OTP is only switched off automatically when Profile Mapping or the linked database disappears.
Reviewing responses and exporting data
- The responses screen is reached from the form list. Opening it without a form reference redirects straight back to the list.
- Three statistic cards head the page — total, complete, and incomplete — and clicking a card filters the table below by that status.
- The form's question structure is read to build the table columns automatically. Three metadata columns are pinned on the left — submission time (sortable), submission status, and a copyable LINE user ID — followed by one column per question, skipping layout elements.
- Cell values render according to the question type: terms show as yes/no, URLs become links that open in a new tab, file uploads become links that open a preview dialog, dates are formatted for readability, and multiple-choice answers are joined with commas. Every cell is single-line with an ellipsis and a tooltip carrying the full value.
- The CSV export button downloads the data matching the current filter, with a file name generated automatically from the form reference and the export timestamp.
Key Screens & Components
Form list (/form-builder)
- Filter bar — a keyword search and a status selector with search and clear actions; the last filter is remembered for the session.
- Form table — title, description, public link with a copy button, creation date, status, response count, and three row actions.
- Delete confirmation — the standard CMS modal set.
Primary files: src/app/form-builder/page.tsx, src/components/form-builder/list/form-builder.container.tsx, src/components/form-builder/list/form-builder-table.tsx
Form editor (/form-builder/form)
The screen is a two-column layout: the editor on the left and a sticky preview on the right. The editor holds the general form settings, the Profile Mapping panel, and a five-tab section.
| Tab | Contents |
|---|---|
| Build | Add, edit, and reorder questions; configure options and conditional display |
| Field Mapping | Map answers to user custom attributes |
| Customize | Cover image, a seven-value colour set, and button styling |
| Verification | Per-form OTP settings and the verification screen copy |
| Thank You | Default or custom mode, icon, message, action button, and auto-close |
All tabs are rendered at once and hidden with CSS, so in-progress edits survive tab switching.
The Customize tab exposes seven colour values covering the page background, the form background, text, buttons, and the theme's primary and secondary colours, with a system default palette pre-applied. The thank-you page action can be set to no button, opening a URL, or switching the user's rich menu.
Other notable components:
- Question card — a drag handle, a required switch, duplicate and delete buttons, and a body that changes with the selected question type.
- Condition panel — parent question, operator, and comparison value, with a paired input for range operators.
- Profile Mapping panel — a three-stage collapsible section: pick the database, map the columns, define the outcome.
- Preview panel — a three-way view switcher bound to the active editor tab.
Primary files: src/app/form-builder/form/page.tsx, src/components/form-builder/form/form-builder-form.tsx, src/components/form-builder/form/hooks/useFormBuilder.ts, src/components/form-builder/form/components/FormBuilderTabs.tsx, src/components/form-builder/form/verification/verification-form.tsx
Responses (/form-builder/response)
- Statistic cards — total, complete, and incomplete; clickable to filter the table.
- Form summary card — title, description, creation date, status, the convert-to-member setting, and the question count.
- Response table — pinned metadata columns followed by one column per question, with widths derived from the question title length.
- File preview dialog — inspect uploaded files without leaving the page.
- CSV export button — downloads the data matching the current filter.
Primary files: src/app/form-builder/response/page.tsx, src/components/form-builder/response/form-builder-response.container.tsx, src/components/form-builder/response/helpers/column-utils.tsx
API services
The editor uses src/services/form-builder.service.ts; the responses screen uses src/services/form-builder-response.service.ts.
| Capability | Endpoint |
|---|---|
| List forms | GET /form-builder |
| Get a single form | GET /form-builder/{id} |
| Create a form | POST /form-builder |
| Update a form | PUT /form-builder/{id} |
| Delete a form | DELETE /form-builder/{id} |
| Fetch shared validation rules | GET /form-builder/common-rules |
| List responses | GET /form-builder/{formHash}/responses |
| Fetch submission statistics | GET /form-builder/{formHash}/stats |
| Export responses as CSV | GET /form-builder/{formHash}/export |
Create and update requests are sent as multipart because the cover image travels alongside the form data.
Dependencies
- Permissions — every screen is gated by the
form-buildermodule permission, and granting it also unlocks the OTP Verification Settings page, since both share the same backend module. - Member Database — a prerequisite for Profile Mapping and the verification tab; without access to the module, neither section renders at all. It also supplies the columns used for record matching and as OTP delivery targets.
- OTP Verification Settings — the underlying layer that determines which channels the LINE OA can send OTPs through. The verification tab reads each channel's readiness from there, and every warning links back to that page.
- Attribute Setup and Template Message — the source of the custom attribute options used in the Profile Mapping and Field Mapping dropdowns.
- Rich Menu Management — the source of rich menu options for the thank-you page action. When a rich menu switch is combined with the convert-to-member switch, whichever runs last determines the final result.
- Content Management — the custom thank-you page uses the same rich-text editor as the content management module.
- Shared infrastructure — the CMS authentication and HTTP client (automatic sign-out on token expiry, which keeps all data scoped to the signed-in LINE OA), the breadcrumb and side-menu system, the standard modal set, and sessionStorage-based filter persistence, all shared with other list pages in the CMS.
Backend Details (CMS API)
The backend lives in internal/modules/formbuilder/, which consolidates three concerns — the form itself, the form's rules, and incoming submissions — into a single service.
Understand this first: cms-api only authors forms and reads submissions. Actually receiving a respondent's submission happens in line-management-client-api-go, a separate service, so this screen can never surface an error that occurred while someone was submitting.
Required permissions
- Every route is wrapped in the module gate for the
form-buildermodule, and this module is the reference implementation for the module gate mechanism across the platform, making it the place where per-module enforcement is genuinely strictest. - Action-level policies are declared only for creating (
create) and updating (update). - Security note — the read endpoints (list, detail, responses, statistics, CSV export) and the delete endpoint declare no action-level policy at all. Passing the module gate is enough to call them. In practice that means any user who can reach the forms module can also delete forms and export every submission, even if their role was intended to be read-only.
Validation and business rules enforced by the backend
- On creation the backend generates the form hash used as the form's public reference — it is not a user-supplied value, and it is what the responses screen uses to address a form instead of the internal id.
GET /api/form-builder/common-rulesreturns the standard validation rules per question type (for example the permitted file extensions for an upload question). These are backend-owned definitions, not values hard-coded in the UI.- Create and update accept
multipart/form-data, because the cover image and attachments travel with the form data. - The whole question structure is stored as one document rather than split into per-question tables, so each save overwrites the entire set.
What gets stored, and the side effects
- The form lives in the
form_buildertable, its conditional logic inform_builder_rule, and incoming answers inform_submission. - Each new submission publishes an event onto the
form_submitted_triggerqueue for Trigger Rule and Workflow to act on. A form is therefore an automation starting point, not merely a data store. - Answers covered by profile mapping are written back into the Member Database and into the LINE user's custom attributes, so a single submission can change the respondent's profile data as well.
- The link between a form and a Member Database lives inside the form's own profile mapping configuration — the same value the Member Database page searches in reverse to display which forms are mapped.
- Files uploaded by respondents and generated CSV exports live on object storage.
- The module exposes a form-lookup function for other modules to call; Audience Filter is the main consumer when building conditions from a form's questions.
Edge cases worth knowing
- Deleting a form runs no reference check first — unlike Quick Reply, which has a dedicated usage endpoint — even though Audience Filter and Trigger Rule may reference it. Rules bound to the form can end up pointing at something that no longer exists.
- Because submissions are received by a different service, changing a form's question structure while responses already exist leaves old answers misaligned with the new questions. The responses screen always builds its columns from the current question structure.
- Per-form OTP settings depend on the OA-level configuration stored in the
otp_configtable, so a change at OA level affects every form with OTP enabled simultaneously. - CSV export streams whatever the supplied filter matches, with no row cap, so exporting a form with a very large number of responses keeps a single request open for the duration.