EMmind MTL business logic
This page describes the MTL edition at the repository refs listed in the project overview. The main CBT journeys were inherited from public EMmind; Google re-verification, MTL policy and messaging, the 30-day 9Q reminder, and the 10 MB upload limit are MTL changes relative to the imported public snapshots.
Actors
| Actor | Surface | Main actions |
|---|---|---|
| Employee | LINE Official Account and LIFF web app | Verify identity, accept terms, complete 9Q, choose a CBT path, keep an emotion journal, plan activities, create a safety plan, request urgent support, and manage the account. |
| Admin or staff | CMS | Sign in and inspect users, journals, skill progress, safety plans, 9Q records, emotions, activities, scenarios, and feedback. |
| LINE platform | Webhook and messaging integration | Verifies LIFF identity, delivers webhook events, sends replies and push messages, and opens LIFF deep links. |
| Scheduled jobs | Core service | Rolls recurring activities forward, sends due activity and 9Q messages, and sends emotion-journal reminders. |
Onboarding and access
- LINE opens the LIFF application, optionally with a
pathandbackToLinedeep-link value. - The web app exchanges the LIFF ID token at
POST /line/auth. - The core service verifies the ID token with LINE. A first login creates
User,LineAccount, andPathSkillrows in one transaction. - The web app checks Google verification. Missing or expired verification opens an external Google OAuth flow and returns to LINE.
- The web app requires terms acceptance, then privacy acceptance.
- Accepting privacy also calls
POST /line/users/privacy-policy. The core service starts a short Redis conversation state and asks through LINE how the employee learned about EMmind. - After all gates pass, the app restores the requested deep link. Without one, it opens the 9Q route.
The web app keeps employee authentication and the requested deep link in a Redis-backed session. The core access token identifies the employee's current LINE account on protected API calls.
LINE conversation behavior
The webhook processes follow and text-message events.
| Input or state | Current behavior |
|---|---|
| Follow event | Sends the identity-confirmation message and offers a DMIND prescreening link for users who are not ready to start EMmind. |
| Greeting keyword | Sends an introductory response. |
| Emotion keyword | Offers concern-specific EMmind activities. |
| Danger keyword | Sends urgent-support copy and a LIFF link to /liff/red-case. |
awaitingKnowSource | Records a predefined referral source or moves to free-text referral-source state. |
completed_quiz or asked_troubled | Records the employee's primary concern, with a free-text branch for "other". |
| Reminder quick replies | Can disable emotion reminders, clear currently flagged activity reminders, open the linked task, or acknowledge that the employee will find another time. The acknowledgement does not reschedule the notification. |
The short conversation states use user:state:<LINE user ID> in Redis. The default lifetime is 15 minutes unless USER_STATE_EXPIRE_SECONDS is configured.
9Q questionnaire
The employee app asks nine questions covering the prior two weeks. Each response scores 0 to 3, for a total of 0 to 27.
| Total | Current result copy | Main action |
|---|---|---|
| 0 to 6 | No or minor symptoms | Acknowledge and continue. |
| 7 to 12 | Relatively low to moderate symptoms | Acknowledge and continue. |
| 13 to 17 | Moderate to relatively high symptoms | Acknowledge and continue. |
| 18 | Severe-symptom copy with the medium result image | Acknowledge and continue. |
| 19 to 27 | Severe symptoms | Offer urgent support at /liff/red-case, with a secondary decline action. |
When a quiz record is created, the core service:
- stores the answer array and total points;
- marks pending quiz reminders complete;
- creates a new pending quiz notification 30 days later;
- increments the user's quiz counter; and
- can push the next LINE prompt that asks for the employee's primary concern.
The current employee route creates a quiz record only when the request includes backToLine. A normal /liff/quiz submission shows the result but does not call the create-quiz API.
CBT learning paths
The application groups work into three concern-based paths. A timestamp on PathSkill marks each completed step. The explicit learning endpoint and sentiment or activity creation append PathSkillActivity history rows. Situation and scenario survey completion updates its timestamp without appending a history row.
| Path | Steps in current UI | Stored completion fields |
|---|---|---|
| Depression | Check current feeling; learn about depression; learn about treatment; keep an emotion journal | emoCheckCompletedAt, learnDepCompletedAt, depTreatCompletedAt, emoJournalCompletedAt |
| "I do not know what I feel" | Learn about emotions; separate thought from emotion; practice situation and emotion recognition | learnEmoCompletedAt, emoThinkCompletedAt, learnSituCompletedAt |
| "I do not want to do anything" | Learn the behavior, thought, and emotion relationship; plan activities | learnBehavCompletedAt, actJournalCompletedAt |
The user may follow a path or open individual skills directly from the path page.
Emotion journal
A journal is unique per user and date. It groups:
- zero to five named emotions with intensity, reasons, optional free text, and story;
- planned activities and their completion ratings;
- stored situation survey forms;
- short journal summaries; and
- generated share-image keys.
Creating a sentiment updates path progress and history and may update the sentiment usage counter. While sentiment reminders are enabled, creation also updates the last emotion date and streak. Editing an existing sentiment changes only the sentiment fields. The core service can render the journal's emotion shapes onto a PNG, upload it to S3, add a border version, and return a shareable object URL.
Situation and thought exercises
The core service stores reusable Question records in emotion and situation groups. It selects random questions while tracking a per-user question pool. Situation answers are stored as SurveyForm rows linked to the current journal. Emotion or scenario answers update the question pool, scenario counter, and path timestamp without storing a SurveyForm row.
Survey-form types drive progress and usage counters. The web app uses them for thought-versus-emotion scenarios and for situation and emotion exercises, then shows a summary or lesson continuation.
Activity planning
Employees can create, edit, delete, and duplicate planned activities. An activity stores its date and time, activity type, free text, reminder flag, pleasure level, achievement level, and a status initialized to planned. The current service does not set the status to completed.
When a dated reminder is enabled, the core service creates a pending NotificationActivity. A midnight job copies recurring notified activities into the current day's journal. A five-minute job sends LINE reminders whose due time falls in the next five minutes. The LINE reminder can open the task or clear the employee's currently flagged activity reminders. Its postpone response does not reschedule the activity. LIFF supports editing the activity time and enabling a dated reminder.
Creating activity-journal work sets actJournalCompletedAt, appends a PathSkillActivity row, and may increment the activity feedback counter.
Safety plan and urgent support
Each employee has at most one safety plan. It stores arrays for warning signs, coping methods, safe places, personal contacts, professional support, and important images or notes.
The urgent-support page offers:
- Thailand's mental-health hotline at 1323;
- the Samaritans number configured in the UI;
- an option to continue with EMmind support through LINE; and
- a link to create or open the safety plan.
Danger keywords in ordinary LINE messages also route users to urgent-support choices through scripted replies and the LIFF page.
Feedback sampling
EMmind samples feedback after repeated use instead of asking every time. Sentiment, survey, activity, lesson, situation, and scenario counters are compared with a threshold of three. Once eligible, a random 50 percent decision determines whether to show feedback and reset that counter.
The feedback form can use an emoji rating or a short assessment. Path completion controls which assessment types are eligible for each concern path. Submitted feedback is stored in Satisfaction and appears in the CMS feedback list.
CMS behavior
The CMS login accepts core email/password accounts. It stores access and refresh JWTs in an HTTP-only cookie session, then calls /users/me. The application rejects a user whose role is exactly user; admin and staff continue.
Current navigation exposes:
| Page | API data |
|---|---|
| Users | /admin/users, with user detail and tabs for journals, safety plan, 9Q, and skills |
| 9Q Quiz | /admin/survey-quizs |
| Emotions | /admin/sentiments |
| Activities | /admin/plan-activities |
| Scenarios | /admin/survey-forms |
| Feedback | /admin/satisfactions |
The checked-out CMS server modules only issue GET requests for these pages. Edit-looking routes exist, but no corresponding create, update, or delete calls are wired in the current CMS core modules.
Scheduled behavior
| Schedule | Job | Time basis |
|---|---|---|
| Every day at midnight | Copy recurring activities into today's journal | Runtime scheduler timezone |
| Every five minutes | Send due activity and 9Q notifications | Stored due timestamps |
| Every day at 08:00 | Send streak and seven-day emotion reminders | Asia/Bangkok |
| Every day at 03:00 | Re-enable emotion reminders after 14 days and reset streak | Asia/Bangkok |