Skip to main content

Loyalty & Rewards App

Overview

The loyalty app is a point- or stamp-card and reward redemption system delivered through LINE. It is built from these pieces:

ComponentMeaning
ProgramThe parent program — point or stamp mode, card size, and on/off status
MilestonesAccumulation goals; reaching one earns the associated reward
TiersMembership levels, available in point mode only, ordered by rank
BranchesLocations where points can be earned and rewards redeemed
StaffEmployees authorized to grant points, managed through invitations
Activity / CustomersTransaction history and member customer records

The module uses the same error code set as client-api, so both sides speak an identical error vocabulary.

Business Flow

Configuring the Program

  1. GET /api/apps/loyalty/program reads the current program. If none exists, the request fails with LOYALTY_PROGRAM_MISSING.
  2. PUT /api/apps/loyalty/program saves the program (mode, card size, and so on). An invalid card size returns LOYALTY_CARD_SIZE_INVALID.
  3. PUT /api/apps/loyalty/program/status turns the program on or off.

Building the Reward Ladder

  1. Milestones are managed through GET /api/apps/loyalty/milestones, POST /api/apps/loyalty/milestones, PUT /api/apps/loyalty/milestones/:id, and DELETE /api/apps/loyalty/milestones/:id.
  2. Tiers are managed through GET /api/apps/loyalty/tiers, POST /api/apps/loyalty/tiers, PUT /api/apps/loyalty/tiers/:id, and DELETE /api/apps/loyalty/tiers/:id.
    • Tiers work in point mode only; any other mode returns LOYALTY_TIER_POINT_MODE_ONLY.
    • Inconsistent numbers return LOYALTY_TIER_INVALID.
    • A rank that collides with an existing tier returns LOYALTY_TIER_RANK_TAKEN.
  3. POST /api/apps/loyalty/tiers/recalculate recomputes membership levels immediately, in addition to the nightly job. It exists because a shop that has just finished configuring its ladder should not have to wait until 3 AM to see whether the setup is correct.

Branches and Staff

  1. Branches are managed through GET /api/apps/loyalty/branches, POST /api/apps/loyalty/branches, and DELETE /api/apps/loyalty/branches/:id.
  2. Staff are managed through GET /api/apps/loyalty/staff, POST /api/apps/loyalty/staff/invite to send an invitation, PUT /api/apps/loyalty/staff/:id to edit, and DELETE /api/apps/loyalty/staff/:id to revoke an invitation.

Viewing Customer Data

  1. GET /api/apps/loyalty/activity shows the history of point grants and redemptions.
  2. GET /api/apps/loyalty/customers searches member customers.
  3. GET /api/apps/loyalty/customer looks up a single customer.

End User and Frontline Staff Side

Granting points and redeeming rewards happen through client-api in the LIFF app, not through the endpoints documented here.

Key Files & Functions

The code lives in internal/modules/loyalty/.

FileRole
controller.goRoute registration; every route carries apps.AppEnabledGuard(d)
service_program.goProgramService — the parent program plus error code definitions
service_catalog.goCatalogService — reward ladder, branches, staff allowlist

Every route sits on the authed group, followed by appEnabled and the policy check (PolicyModuleLineOa).

MethodRouteHandlerPolicy
GET/api/apps/loyalty/programct.getProgramread
PUT/api/apps/loyalty/programct.saveProgramupdate
PUT/api/apps/loyalty/program/statusct.setProgramStatusupdate
GET/api/apps/loyalty/milestonesct.listMilestonesreadAll
POST/api/apps/loyalty/milestonesct.createMilestonecreate
PUT/api/apps/loyalty/milestones/:idct.updateMilestoneupdate
DELETE/api/apps/loyalty/milestones/:idct.deleteMilestonedelete
GET/api/apps/loyalty/tiersct.listTiersreadAll
POST/api/apps/loyalty/tiersct.createTiercreate
PUT/api/apps/loyalty/tiers/:idct.updateTierupdate
DELETE/api/apps/loyalty/tiers/:idct.deleteTierdelete
POST/api/apps/loyalty/tiers/recalculatect.recalculateTiersupdate
GET/api/apps/loyalty/branchesct.listBranchesreadAll
POST/api/apps/loyalty/branchesct.createBranchcreate
DELETE/api/apps/loyalty/branches/:idct.deleteBranchdelete
GET/api/apps/loyalty/activityct.listActivityreadAll
GET/api/apps/loyalty/customersct.searchCustomersreadAll
GET/api/apps/loyalty/customerct.lookupCustomerreadAll
GET/api/apps/loyalty/staffct.listStaffreadAll
POST/api/apps/loyalty/staff/invitect.createInvitecreate
PUT/api/apps/loyalty/staff/:idct.updateStaffupdate
DELETE/api/apps/loyalty/staff/:idct.revokeInvitedelete

All error codes are defined in service_program.go: LOYALTY_PROGRAM_MISSING, LOYALTY_TIER_POINT_MODE_ONLY, LOYALTY_TIER_INVALID, LOYALTY_TIER_RANK_TAKEN, and LOYALTY_CARD_SIZE_INVALID.

Connections to Other Services

  • Access control — Every route passes apps.AppEnabledGuard(d); the app must be enabled for the organization first (see the Add-on Apps Platform). Policy metadata uses PolicyModuleLineOa.
  • Tables — The loyalty group defined in internal/entities/loyalty.go, covering program, milestone, tier, branch, staff, activity/transaction, and customer membership, plus line_oa_app, line_oa, and line_user.
  • Nightly job — Tier recalculation runs at 03:00 in the worker.
  • Cross-serviceline-management-client-api-go shares the same error code set.
  • Related modulesAdd-on Apps Platform, the Appointment Booking App, the Bulletin Board App, and LINE User Management.