Attribute Setup
Overview
Attribute Setup (known on the backend as attribute-master) is where the shared schema of custom attributes attached to LINE users is defined for each LINE OA. In other words, it declares the data structure up front: which fields the system will store, what type each one is, and which of them can be used for audience filtering or shown in reports.
The page is aimed at administrators who need to design the customer data structure before any data is collected, because downstream features — Audience, Report, Workflow, and Friend Track — all read their field definitions from here. The menu sits under Settings → User Attribute Setup.
Each attribute master record contains:
| Field | Description |
|---|---|
| Name | The label shown in the list; required, up to 255 characters |
| Description | Additional detail about this attribute set |
| Status | Active or inactive |
| Schema | The full field structure as a tree, supporting nested fields and arrays |
Every field inside a schema carries the following properties:
| Property | Description |
|---|---|
label | The name users see and the true identity the system validates; it must not be blank and must be unique across the whole tree |
dataType | One of six types: string, number, date, boolean, array, object |
filterable | Whether the field can be used as an Audience filter condition |
displayInReport | Whether the field can appear as a column in the All Friends report |
path | The field's full position in the JSON, used to target updates and deletions |
key | An internal identifier generated automatically; never shown or editable in the UI |
Key points to be aware of:
- Fields whose
dataTypeisobjectorarraycannot enablefilterableordisplayInReport, since they are structural containers rather than directly comparable values. - The chosen
dataTypedetermines which operators are available in the Audience filter, so it should be set correctly from the start. - A schema can be built in two ways: entering fields manually or Import from JSON, where a sample JSON payload is pasted in and converted into a schema.
Business Flow
List page (/attribute-setup)
- Opening the page sets the Settings → User Attribute Setup breadcrumb and loads the record table.
- The most recent filter is restored from sessionStorage; if none exists, defaults apply (page 1, 10 rows per page, no search term, no status filter).
- The table shows the row number, name, description, the number of fields in the schema, status, and creation date. Clicking the name opens the record in read-only mode.
- Records can be searched by name and filtered by status (all / active / inactive) from the toolbar, which also displays the total record count on the right.
- Every filter or pagination change is remembered for the session, so returning to the page preserves the previous view.
- Two buttons sit in the top-right corner: Import from JSON to enter import mode, and Create to build a schema manually.
- Deletion requires confirmation. On success the system reports the result and refreshes the table automatically.
Create / edit / view form (/attribute-setup/form)
- The form runs in three modes — create, edit, and view-only — determined by URL parameters (
ididentifies the record being edited,view=trueswitches to read-only). - In edit and view modes, the existing name, description, status, and schema are loaded into the form.
- View-only mode disables every input, renders the schema editor read-only, and hides the save button.
- On save, the system walks the entire tree recursively and validates every label: none may be blank, and none may duplicate another (compared case-insensitively). If validation fails, an error is shown and nothing is sent to the API.
- Once validation passes, the system creates a new record or updates the existing one and returns the user to the list page.
Import from JSON mode
- Step 1 — details and JSON input. The user enters a name (required), a description, and an optional root path, used when the schema should be derived from a nested object rather than the whole payload. The sample JSON is then pasted into the text area.
- Clicking "Parse & Continue" validates the JSON format in the browser first; malformed JSON is reported immediately without calling the API.
- Once the format is valid, the JSON is sent to the backend for conversion into a schema, and the result is carried into the next step. If conversion fails, an error prompts the user to correct the source data.
- Step 2 — review and adjust. The name and description can be revised, and the generated schema can be tuned: labels, data types, the filterable/displayInReport switches, and removal of unwanted fields.
- The Back button returns to step 1 with the pasted JSON intact. Save stores the result as a new attribute master in active status.
Editing a schema
- The editor flattens the tree into an indented table. Fields with children get an expand/collapse arrow, and Expand all / Collapse all controls apply to the whole table.
- Each row exposes four controls — Label, Data type, the Filterable switch, and the Show in report switch — plus a delete button. Both switches are disabled automatically when the data type is
objectorarray. - "Add attribute" appends a new field at the top level, defaulting to type
stringwith both filterable and displayInReport enabled; the user supplies the label. - Deleting a field from a record that has never been saved removes it immediately.
- Deleting a field from a saved record opens an impact warning dialog and asks the backend who is currently using that field. The result covers four areas: the number of users holding a value in the field, plus the trigger rules, audiences, and rich messages that reference it.
- The usage report is advisory only — it never blocks the deletion, and if the check itself fails, the field can still be removed.
- Confirming in this dialog removes the field from the on-screen schema only; the form must be saved again for the change to persist.
Key Screens & Components
List page (/attribute-setup)
- Toolbar — a name search box that queries as you type, a status selector, and the total record count.
- Record table — row number, name (clickable to view details), description, field count, status, creation date, and action buttons, with pagination.
- Create actions — Import from JSON and Create, presented as separate buttons in the top-right corner.
Primary files: src/app/attribute-setup/page.tsx, src/components/attribute-setup/list/attribute-setup.container.tsx
Form page (/attribute-setup/form)
- Basic info card — name (required), description, and status.
- Schema card — hosts the schema editor; edits are written back into the form automatically.
- Schema editor — a tree-style table supporting indentation, expand/collapse, and adding, editing, or removing fields.
- Delete warning dialog — shows the affected user count along with the trigger rules, audiences, and rich messages referencing the field.
Primary files: src/app/attribute-setup/form/page.tsx, src/components/attribute-setup/form/attribute-setup-form.container.tsx, src/components/attribute-setup/form/components/attribute-editor.tsx, src/components/attribute-setup/form/components/attribute-delete-warning-modal.tsx
API service
All calls live in src/services/attribute-master.service.ts under the attribute-master base path.
| Capability | Endpoint |
|---|---|
| List attribute masters | GET /attribute-master |
| Get a single record | GET /attribute-master/{id} |
| Create a record | POST /attribute-master |
| Update a record | PUT /attribute-master/{id} |
| Delete a record | DELETE /attribute-master/{id} |
| Convert JSON into a schema (preview) | POST /attribute-master/parse-json |
| List filterable attributes only | GET /attribute-master/filterable |
| List reportable attributes only | GET /attribute-master/reportable |
| Check attribute usage before deletion | GET /attribute-master/{id}/check-attribute-usage |
Dependencies
- Permissions — the menu and pages are gated by the
attribute-mastermodule permission, mapped to theattribute-setupmenu under the Settings group. Access control is enforced through the side menu and the shared ability system. - Audience Multi-Source Filter — selecting a custom attribute source loads only the filterable attributes, split into two groups: standard profile fields (paths beginning with
__fixed.) and custom attributes from this schema. The available operators follow each attribute's data type. - Report All Friends — loads only the reportable attributes to build dynamic columns, which makes the switch on this page the direct control over report columns.
- Workflow — the node configuration drawer lists all attribute masters and can create or update them inline, without returning to this page.
- Friend Track and the All Friends detail view — load attribute masters to map stored values onto human-readable labels.
- Import Mapping — target fields prefixed with
custom.in the data import wizard are the custom attributes declared here. - System Attribute is a separate feature — the system-level key/value settings used in LINE OA Management and Workflow are unrelated to this schema.
- Shared infrastructure — the CMS authentication and HTTP client (automatic sign-out on token expiry), the breadcrumb and side-menu system, and sessionStorage-based filter persistence, all shared with other list pages in the CMS.
Backend Details (CMS API)
The backend lives in internal/modules/attributemaster/, with two responsibilities pulled out into their own files: the JSON-to-schema converter and an ordered-key helper that keeps the returned fields in the same order the user pasted them, rather than whatever order internal storage happens to produce.
Required permissions
- Every route is wrapped in the module gate for the
attribute-mastermodule. - Policies are split by action:
readAllfor listing;readfor single records, the filterable and reportable lists, the usage check, and the JSON preview conversion;createfor creating and bulk importing;updateanddeletefor their respective operations. - Converting JSON for preview only requires read-level permission, because nothing is persisted at that point.
Validation and business rules enforced by the backend
- The attribute quota is always checked before creation (the plan's
maxAttributesvalue), so a create can be refused even when the schema is entirely valid. - JSON import is split into two clear stages:
POST /api/attribute-master/parse-jsonconverts and returns a preview only — nothing is saved, and can take a root path to target a nested object. Persisting is a separate request. - The backend also exposes
POST /api/attribute-master/import-jsonto create attributes from a whole schema in a single request. That path exists on the API even though the current UI saves through the ordinary create route. GET /api/attribute-master/:id/check-attribute-usagetakes the specific attribute key to check as a query-string parameter; it does not audit the whole record at once.
What gets stored, and the side effects
- Schema definitions live in the
attribute_mastertable, while each person's actual values are stored as custom attributes attached to theline_usertable. - The pre-delete usage check has to look across several tables —
audience,form_builder,import_mapping_job, andtemplate_message— to gather everything referencing the field. - This module writes no cache and publishes no queue messages, so a schema change takes effect immediately for every feature that reads the definitions.
- The blast radius is wide — audience filters, the All Friends report, message merge tags, and the target fields of data import all read from this table, so changing a data type or removing a field affects several features at once.
System-level attributes are a separate backend module
Alongside the per-OA custom attributes, the system defines system-level attributes centrally in their own module (internal/modules/systemattribute/) — the baseline set every OA shares.
- It is a simple CRUD module with just four endpoints under
/api/system-attribute. - Its records are merged with custom attributes in the message merge tag list (when system attributes are requested) and are also used when building forms and reports.
- This table genuinely uses the ORM's automatic soft-delete mechanism — unlike several modules in this system where the condition has to be written by hand — so listings already exclude deleted rows on their own.
- Security note — this module has no module gate and no Super Admin requirement. Passing the shared authentication check with a selected LINE OA is enough to call it, even though the data is system-wide rather than specific to any one OA.
- Edge case — the update operation is deliberately written not to filter out already-deleted rows (preserving the previous system's behaviour). As a result, updating by the id of a deleted record still succeeds, even though that record never appears in listings.
Edge cases worth knowing
- The pre-delete usage report is advisory. The backend does not block the deletion even when other features are found referencing the field, so avoiding breakage is left to the user.
- This module's error handling passes known failures through unchanged (unauthorised, not found, bad request, conflict), but every unrecognised error is collapsed into a single generic error code, which strips the underlying cause from the response — the backend logs are the only place to find it.
- Field ordering within a schema is deliberately preserved rather than incidental, which is what makes report column order and merge tag order predictable.
- Changing the data type of a field that already holds data does not convert the stored values; only the operator set available in the Audience filter changes. Previously stored values may therefore not compare the way you expect.