Skip to main content

Template Message Management

Overview

Template Message is a library of LINE Flex Messages built from ready-made templates. Each saved template is stored in two forms side by side:

  • The author's input — kept so the template can be reopened and edited in the same form.
  • Send-ready Flex JSON — kept so other modules can pull it and send it directly without rebuilding anything.

The feature is designed for content teams who want to produce Flex Messages without writing JSON, while still leaving the door open for those who prefer to write it by hand.

Every text field supports merge tags in the form {{key}}, substituting each recipient's data at send time.

The six template kinds

KindStructureBubbles
RegisterIcon, title, description and one button1
ShoppingImage, title, subtitle and two buttons1
NotificationImage, icon, title, description and one button1
CarouselSeveral horizontally scrolling cards, each a full-card image with one actionStarts at 2, up to 6
Custom JSONHand-written Flex JSONAs defined by the JSON
Card BuilderA visual card composer built from blocks, compiled into a bubble1

Card Builder is the default kind when creating a new template.

Business Flow

1. List screen

  1. Permissions are checked, then the last filter is restored from sessionStorage.
  2. The table shows the template name (linking to the detail view), the template kind, the last-updated date (or the creation date if it has never been edited), and the action buttons.
  3. Only edit and delete are offered as buttons; the detail view is reached by clicking the template name.
  4. The filter offers a search box and a template-kind selector.
  5. Deletion requires confirmation, and on success a confirmation dialog returns the user to the list.

Worth knowing — the kind selector in the filter does not yet include Card Builder, so templates of that kind cannot be filtered for.

2. Shared form behaviour

  1. The form supports four modes: create, edit, copy and view.
  2. In create mode the kind is set to Card Builder and a starter set of blocks is prepared — a hero image, a heading text block and a button.
  3. When opening existing data, the read path branches by template kind. Structured templates convert their stored image URLs back into files so they can be edited.
  4. Changing the template kind always prompts first, because existing data is replaced with the new kind's defaults.
  5. The sample content the system seeds is deliberately in English and is not translated with the interface; only the kind names themselves are localised.
  1. The form presents editable cards. The first three kinds have one card; Carousel shows a card header with move-up, move-down and delete controls, plus an add-card button until six cards exist.
  2. The fields shown depend on the kind:
    • The title appears in every kind except Carousel.
    • Descriptions are capped at 200 characters.
    • Images accept JPG, JPEG and PNG up to 10 MB.
    • Icons accept the same formats up to 1 MB, and are required in kinds that have one.
  3. If an image or icon is still one of the system's sample assets, a notice appears prompting the author to replace it with real artwork.
  4. Card buttons support four action types:
    • Send a message — a label (up to 50 characters) and the text to send.
    • Open a link — a label (up to 100 characters) and a URL.
    • Place a call — the label field itself holds the phone number; there is no separate label field.
    • Postback — the data to return and the text to display.
  5. In Carousel templates the label fields are hidden entirely, because the action is attached to the whole image rather than to a button.
  6. The number of buttons per card comes from the template's defaults; there are no controls to add or remove buttons.

4. Custom JSON templates

  1. The screen is a large text area for Flex JSON, with a helper that inserts merge tags at the cursor position.
  2. The JSON is validated as parseable when the field loses focus, with an error message when it is not.
  3. The preview updates only when the JSON is valid; incomplete JSON leaves the previous preview in place rather than raising an error.

5. Card Builder templates

Card Builder composes a card from individual blocks, suiting authors who want layout freedom without writing JSON.

  1. Alongside the blocks, an alt text is required — the text shown in chat lists and notifications — capped at 400 characters.
  2. Five block types are available:
    • Hero image — upload an image, pick an aspect ratio (or use the image's natural ratio), choose between filling the frame with cropping or showing the whole image, and set a tap action.
    • Video — paste an MP4 URL directly (video is not uploaded through the CMS), upload a cover image, and pick an aspect ratio. If the block is not first, a warning explains it will render as a still image, because LINE only plays video in the top slot of a card.
    • Text — the text plus size, weight, alignment, text colour and an optional background colour.
    • Button — a label, button style (filled, outlined or text-only), colour, height, an optional background colour, and an action.
    • Separator — a divider with a colour option.
  3. Block actions offer three choices: none, open a link (which must be an HTTP or HTTPS URL), or send a message.
  4. Blocks can be reordered by drag and drop or with up/down arrows, and removed individually.
  5. Images in blocks are uploaded to the server as soon as they are chosen, and only the resulting URL is stored — so saving sends pure JSON with no file attachments.
  6. Compiling blocks into a bubble happens in the browser, following these rules:
    • If the first block is an image or video, it is hoisted into the card's edge-to-edge hero slot.
    • If the first block is neither, nothing is hoisted and every block sits in the card body in the author's order — supporting layouts where a heading precedes the image.
    • Text, button and separator blocks without a background colour are grouped inside a padded container for readability, while blocks with a background colour render full-bleed.
    • A video that is not in the top position degrades to its cover image.
    • The compiler is deliberately tolerant: incomplete blocks are skipped rather than failing the whole operation, so the preview keeps working while the card is being built.
  7. The save criteria are separate from the compiler and stricter: at least one block, every block complete, and at least one block that renders real content rather than only separators.

6. Preview, validation and saving

  1. The preview updates automatically with a short delay whenever form values change, rendered with a real Flex Message renderer.
  2. The save button's conditions vary by kind:
    • Custom JSON — a template name and valid JSON.
    • Card Builder — a template name and a valid block set.
    • Structured templates — a template name, at least one card, at least one button per card, all required fields for that kind, and every button satisfying the rules of its action type.
  3. Creating saves immediately; editing opens a confirmation dialog first.
  4. What is submitted depends on the kind: structured templates send image files and per-card data, Custom JSON sends the JSON as typed, and Card Builder sends both the block structure and the compiled Flex JSON together.
  5. Field-specific server errors are shown on the relevant field; otherwise an error dialog appears, handling several possible message shapes from the API.

Key Screens & Components

List screen

The list container (src/components/template-message/list/template-message.container.tsx) owns the table, filters, sorting and deletion.

Form screen

The form splits into a container handling data loading and transformation, preview JSON assembly, validation rules and saving, and a large form component covering the rendering of every template kind, button handling and file uploads.

Card Builder

Card Builder lives in src/components/template-message/form/flex-card-builder/ with a clean four-way split:

  • The interface for adding, editing, reordering and removing blocks.
  • The block-to-bubble compiler, written as pure functions with no UI dependencies so it can be tested in isolation, and shared between the preview and the save payload.
  • The save-criteria validator, kept deliberately separate from the compiler because the compiler must be tolerant while saving must be strict.
  • A factory producing new blocks with sensible defaults.

Merge tag helpers

Two helpers work together: a picker that lists available merge tags, loading them the first time it is opened, and an input that suggests tags automatically when the author types a brace. The loaded list is cached for reuse.

API endpoints

OperationEndpoint
List templatesGET /template-message
Read one templateGET /template-message/{id}
Dropdown list for other modulesGET /template-message/find-all-object
Merge tag listGET /template-message/merge-tags
Create a templatePOST /template-message
Upload a Card Builder imagePOST /template-message/upload-image
Update a templatePUT /template-message/{id}
Delete a templateDELETE /template-message/{id}

Hard-coded limits

Carousels start at two cards and grow to six, images up to 10 MB, icons up to 1 MB, template names up to 100 characters, descriptions up to 200 characters, message-button labels up to 50 characters, link-button labels up to 100 characters, and Card Builder alt text up to 400 characters.

Dependencies

  • Rich Message Management — the template content type pulls both the list and the content from this module.
  • Trigger rules, friend tracking, workflows and Form Builder — all select templates from here to define the messages they send.
  • Actual delivery — happens in the campaign and auto-response modules, via Rich Messages.
  • Auto Response — button text fields offer autocomplete drawn from auto-response keywords.
  • Rich Menu — shares the action-type constants.
  • Database contract — the author's source data and the send-ready Flex JSON are stored in separate fields. Card Builder templates are compiled in the browser and both payloads are submitted together.
  • Access control — the server-side template-message module unlocks the list and form pages consistently.

Backend Details (CMS API)

The template quota

Entirely invisible from the frontend: the number of templates an organization can create is capped by a plan quota. The backend checks it before every create and rejects over-quota requests with a "package limit reached" message. The platform default is 20 templates, and platform administrators adjust it per organization from the organization module settings page.

The frontend does not check the quota in advance, so users fill in the entire form before discovering they cannot save — worth knowing when helping users troubleshoot.

Where merge tags come from

GET /api/template-message/merge-tags does not return a hard-coded list. It is assembled from two sources:

  1. System tags such as the user's name and their LINE display name.
  2. Tags derived from the organization's custom attributes for that LINE OA. The list shown in the merge-tag picker therefore differs per channel and changes as attributes are configured.

The showSystem parameter controls whether the system tags are included.

Merge tag substitution does not happen in this module. Templates store the text with its merge tags intact; substitution happens when the message is assembled for delivery, inside the shared LINE message service used by campaigns, auto responses and workflows.

Other rules the backend applies

  • Duplicate names are rejected within the scope of a single OA.
  • Both create and update accept multipart data so image files can travel with the other fields.
  • POST /api/template-message/upload-image is a separate route for Card Builder images, deliberately declared as a static path so it is not mistaken for a template id during route matching.

Permissions

  • Every route is wrapped in ModuleGate for the template-message module, which is genuinely enforced — an organization with the module disabled loses the whole feature.
  • Per-action permission metadata exists but is not enforced.
  • GET /api/template-message/find-all-object, used by other modules for dropdowns, carries no permission metadata, matching the previous system.

Side effects and things worth knowing

  • Redis cache — the backend caches both the template list and individual template details.
  • Card Builder images live in object storage. What the template stores is the image's location, consistent with the frontend uploading immediately on selection and submitting only the URL on save.
  • The backend does not validate Flex JSON in this module, unlike Rich Message, which sends it to LINE for validation. Structurally invalid JSON can therefore save successfully here and only fail when the message is actually sent.