Skip to main content

Dashboard

Overview

The dashboard is the first screen users reach after selecting a LINE OA. It summarises the friend base for that channel — split into members, guests and blocked users — alongside trend charts and the campaigns scheduled for the next seven days.

It is open to any role with dashboard view permission. All the headline figures come from a single endpoint, GET /dashboard/total-friends, while the campaign list at the bottom borrows its data from the Campaign Management module.

Important caveat — in the current release only the numeric cards at the top show real server data. The trend line chart and the daily activity bar chart are approximated in the browser from the period's opening and closing totals; they are not true daily figures. Details follow below.

Business Flow

1. Opening the page and setting the period

  1. Dashboard view permission is checked first; without it, a "no permission" screen is shown.
  2. The breadcrumb and active sidebar entry are set to match.
  3. The reporting period is always fixed at the last seven days, counting back from today. There is no date picker on this page yet.

2. Fetching data and deriving the displayed values

  1. The app calls GET /dashboard/total-friends with that date range.
  2. The server returns a set of metrics, each carrying four values: the total at the start of the period, the total at the end, the difference, and the difference as a percentage.
  3. Each card picks the value that matches what it is trying to convey — cards showing a running total read the end-of-period figure, while cards showing movement read the period difference.
  4. Because the whole page is served by one request, every card enters and leaves its loading state together.

3. What appears on the page

The top row holds three cards:

  1. Total friends — the current cumulative friend count, shown as a large figure with a short explanatory hint.
  2. Active friends — a doughnut chart splitting members from guests, with blocked users subtracted from each group.
  3. Blocked users — a doughnut chart of blocked users split between members and guests. When both are zero, a grey ring is drawn with a "no data" label.

The seven-day activity box contains two numeric cards, one for guests and one for members. Each shows how many were added and how many blocked during the period. Figures appear green when positive and red when negative, with a plus sign on positive values.

The upcoming activities card lists campaigns scheduled for the next seven days.

The friends growth chart is a seven-day line chart with three series: total friends, members and guests.

The daily activity chart is a seven-day bar chart showing new friends and blocked users per day.

4. Upcoming activities

  1. The card computes its own range — from the start of today through the end of the day seven days out.
  2. It fetches campaigns with the scheduled status in that window, ordered by start date with the nearest first, capped at ten items.
  3. Each entry shows a date badge, the campaign name, the send time with a "today" / "tomorrow" / dated label, and a status tag using the same colours as the campaign module.
  4. Clicking an entry opens that campaign's detail page; the "view all" button leads to the Campaign Planner.
  5. When nothing is scheduled, an empty state appears with a shortcut to create a campaign.

5. Data accuracy caveats

These points matter a great deal for anyone taking figures from this page:

  • The trend line is not real daily data. The app draws a straight line between the opening and closing totals because the server does not yet expose daily breakdowns. The code carries an explicit note to replace this once it does.
  • The daily bars are randomised. The period difference is divided evenly across seven days and then redistributed randomly while preserving the total, so each bar changes on every re-render. Only the weekly total matches the real data.
  • The two groups of numbers are not directly comparable. The top cards show cumulative totals; the activity cards and bar chart show the difference over the seven-day window.
  • There is no error handling. If the request fails, every card shows zero with no warning.

Key Screens & Components

Page structure

The dashboard is composed of several thin layers. The data-fetching logic sits in the chart container (src/components/dashboard/dashboard-chart/dashboard-chart.container.tsx), which calls the API, selects the values to display, and hands them to the component that lays out the whole page.

Cards and charts

  • Doughnut cards are used for active friends and blocked users, each with a two-line legend below the chart.
  • Score cards summarise movement per group, distinguished by background colour between guests and members.
  • The line and bar charts live in src/components/dashboard/charts/, alongside a registration file for the charting library's components that must be imported before any chart is used.
  • Chart colours and status tag colours are centralised in a shared constants file so the page stays visually consistent.

Upcoming activities group

This group splits into a container that fetches campaigns and handles navigation, a list component with a header, footer and scrollable body, a single-row component, and an empty-state component.

Responsive layout

The top cards form three columns on medium screens and up, and stack on mobile. The activities card and the growth chart split one-third to two-thirds on large screens, and the bar chart spans the full width. Every chart is wrapped in a fixed-height box so layout does not jump as data loads.

API endpoints

OperationEndpoint
Friend totals and group breakdownsGET /dashboard/total-friends
Campaigns scheduled in the next seven daysGET /campaign

Dependencies

  • Login — the dashboard is the destination after selecting a LINE OA, and everything it shows is automatically scoped to that channel.
  • Access control — the page is unlocked by the server-side dashboard module and needs only the view permission.
  • Campaign Management — the upcoming activities card reads directly from the campaign module for its data, statuses and link targets.
  • Campaign Planner — the "view all" button on the activities card leads to the calendar view.
  • Where the numbers come from — member, guest and blocked counts derive from the server's LINE user records, which are updated by webhooks on follow and unfollow events and by the follower sync job. If the figures look wrong, investigate those systems rather than the dashboard.

Backend Details (CMS API)

The dashboard module in cms-api is one of the smallest in the system — it exposes a single endpoint, GET /api/dashboard/total-friends. Nothing is aggregated centrally here. Other figures on the screen, such as the upcoming campaign list, come straight from those features' own endpoints.

The conditions the backend applies when counting friends

Counting runs against the LINE user table with four baseline conditions applied to every metric:

  1. Scoped to the LINE OA id from the token. The OA id is never taken from a caller-supplied parameter, so cross-channel access is impossible.
  2. Only rows created on or before the given date are counted, which is the mechanism that makes the start-of-period and end-of-period figures possible.
  3. Only rows already linked to a real LINE user are counted. Rows without that link are excluded, so the figure can be lower than the raw row count in the table.
  4. Soft-deleted rows are excluded.

Metric-specific conditions are then layered on top — separating followers, unfollowers and blocked users.

Why the daily charts are approximations

The data-accuracy caveats above have a straightforward backend explanation: this endpoint returns point-in-time totals only, never a daily series. The frontend therefore has just two real data points, the start and end of the period, and has to synthesize the line and bar charts from them. Making the charts show real data requires changing the backend to return a daily series first; it cannot be fixed on the frontend alone.

Required permissions

  • The request must pass the ordinary JWT guard, which requires that the token already carries a LINE OA id — the technical reason the dashboard is only ever reachable after a channel is selected.
  • There is no ModuleGate and no super-admin guard on this route. Any user with an OA-scoped token can call it.
  • Module-level permission metadata exists for dashboard but is not enforced, so hiding the menu on the frontend is a user-facing control, not an API-level block.