Tran Manh Tuan

Dr.Well-B

Dr.Well-B is a membership platform for doctors, dentists and medical students in Japan, launched publicly in 2023. Rather than solving one task, it brings many services into one portal: verified professional accounts, profile-based advertising, surveys, recruitment and job search, professional content and a reward-point programme — all run by an operations team from a back-office console.

I was the Tech Lead from 2022 to 2024 and also worked directly on the backend: technical direction, system and data-flow design, the Node.js / NestJS API, Firestore, search, background processing and the Google Cloud services around them, code review, and coordination between the Japanese side and the development team in Vietnam.

Why it is a management-system project: every module reads the same member profile and writes to the same action log. A change to how ads are targeted changes points, reports and exports downstream — so the work was as much about workflows, data flow and back-office control as about individual features.

Modules and who uses them

Two groups use the system. Members — doctors, dentists, doctors in training, independent practitioners and medical students — use the member portal. Operators and admins use a separate administration console to review accounts and approvals, manage ads, suppliers, surveys and job postings, and run downloads.

Dr.Well-B module overviewDoctors, dentists, medical students and other members use the member portal; operators and admins use the administration console. The member portal leads to accounts and profiles, personalised advertising, dynamic surveys, recruitment and job search, and professional content. The administration console manages accounts and profiles, advertising, surveys, recruitment and downloads/exports. Advertising and jobs generate points and rewards. Advertising, surveys, jobs and accounts feed analytics and reporting. Points and surveys produce download/export files, and downloads/exports send notifications and email.

Doctors / Dentists / Medical students / Members

Operators / Admins

Dr.Well-B member portal

Dr.Well-B administration

Accounts & profiles

Personalised advertising

Dynamic surveys

Recruitment / job search

Professional content

Points / rewards

Download / export

Notifications / email

Analytics / reporting

Diagram fitted to its frame

The portal and the console share one set of modules. Profiles and action logs are what connect them, rather than each feature standing alone.

My responsibilities

  • Set the technical direction and chose the solution for each large feature, assessing technical risk before it was built.
  • Designed the system architecture and how modules exchange data.
  • Designed and built backend APIs in Node.js / NestJS.
  • Designed the Firestore data model, Elasticsearch search, background processing and the cloud services behind them.
  • Reviewed technical designs and pull requests, reviewed security, and unblocked the team on hard problems.
  • Set the unit and automation testing strategy (Cypress) for a system with many rules.
  • Supported staging and production deployments, and tracked technical progress and risk across the large features.

Membership with professional verification

Registration here is a verification workflow, not an email-and-password form. The platform collects professional data — specialty and sub-specialty, workplace, department, position, graduation year, university, student number, licence number, clinical training — and verification documents such as licence images, student cards, training certificates and CVs.

When the details can be verified, the account is activated straight away. When they cannot, the application moves into an admin approval flow: the member is asked for more documents, an admin reviews them, the decision is recorded in an approval history, and the record is locked once it is approved. Each outcome sends its own email.

Registration and verification flow for medical professionalsA user starts registration, enters personal details, professional details, licence or school details, uploads verification documents and submits. If the details can be verified, the system creates and activates the member account and sends a registration-complete email. If not, the application moves to additional review: the user is asked for more documents and an admin reviews and approves. Once approved, the account is activated and the approval history is updated; if not yet approved, the flow returns to requesting more documents.

Yes

No

Yes

Not yet

User starts registration

Enter personal details

Enter professional details

Enter licence / school details

Upload verification documents

Submit registration

Can the details be verified?

Create / activate member account

Send registration-complete email

Move to additional review

Request additional documents

Admin review / approval

Approved?

Activate account

Update approval history

Diagram fitted to its frame

Automatic verification where possible, human approval where not — with a history of every decision.

Profile-targeted advertising

Ads are not random banners. Each one carries delivery rules: placement and banner size, destination URL, banner or text, tags, target specialties and medical societies, a delivery window, a click limit, a priority and a status. Selection filters every active ad against the member's profile and history, and what a member does with an ad feeds back into the next selection — hiding or refreshing an ad can drop it from that member's candidates or lower its priority for them, while signs of interest keep similar ads coming.

On the console side, operators create, copy and schedule ads, set limits and priority, manage the suppliers behind them, and can download the list of members an ad's tags match.

Profile-based advertisement selection flowAn admin creates and publishes ads, the system fetches the active ads and filters them through four checks: the ad matches the user's specialty, society or tags; it is inside its delivery period; its click limit has not been reached; and the user has not hidden or refreshed it. An ad that fails any check is dropped or its priority is lowered. Ads that pass every check are scored for priority and relevance, ranked, prepared as banner, text and URL, displayed, and an action log is written; the action log feeds back into the next selection.

No

Yes

No

Yes

Yes

No

Yes

No

Admin creates / publishes ads

Fetch active ads

Matches specialty / society / tag?

Within the delivery period?

Click limit reached?

User hid / refreshed this ad?

Score priority / relevance

Rank candidates

Prepare banner / text / URL

Display ad

Write action log

Drop or lower priority

Diagram fitted to its frame

Four filters decide whether an ad is a candidate at all; only then does ranking start. The action log closes the loop.

A configurable survey engine

Admins build surveys without code: title, description, notes, minimum and maximum responses, publish state and a linked ad, then questions with a type, required or optional, answer lists and free input. Questions can depend on each other — "if question 1 is A, show question 2" — which gives conditional branches, sub-questions and embedded questions. Members get a form that changes with their answers, and in some flows a changed answer overwrites the earlier one instead of creating a duplicate submission.

Dynamic survey flow from configuration to reportingAn admin creates a survey, configures its metadata, adds questions, chooses each question type, sets required or free-input options, configures the relations between questions and publishes. A member opens the survey and answers; if an answer triggers a follow-up question, that question is shown or enabled before continuing, otherwise the member continues straight away. The member submits, the system stores the survey result, and the data moves on to reporting, downloads and analytics.

Yes

No

Admin creates a survey

Configure metadata

Add questions

Choose question type

Set required / free input

Configure question relations

Publish survey

Member opens the survey

Answer a question

Does the answer trigger a follow-up?

Show / enable follow-up question

Continue the survey

Submit

Store survey result

Reporting / download / analytics

Diagram fitted to its frame

The form is data, not code: question relations decide at answer time which questions a member sees.

Points and rewards from action logs

Points are not calculated inside the request that earns them. Eligible actions — ad clicks, job actions and configured bookings — are written to action logs, and batches do the rest. The daily batch reads unprocessed logs, checks eligibility, looks up the points for each action, applies the rules (several clicks on the same ad or job in one day count once; points are capped per month), writes a point distribution plan and marks the logs as processed. The monthly batch aggregates points and profiles into distribution results and files. Members redeem their points through a partner points app.

Point and reward calculation through action logs and batchesAd clicks, job actions and other eligible bookings or actions are all written to action logs. A daily batch reads the action logs and checks rules, duplicates and limits; the result both creates a point distribution plan and marks the logs as processed. A monthly batch aggregates the point distribution plans into a monthly distribution result, from which files and reports are generated.

Ad click

Job action

Eligible booking / action

Action logs

Daily batch

Check rules / duplicates / limits

Point distribution plan

Mark logs as processed

Monthly batch

Monthly distribution result

Generate file / report

Diagram fitted to its frame

Event log first, daily calculation next, monthly aggregation last. The user action finishes immediately; the business rules run afterwards.

Asynchronous exports and notifications

Survey results, full doctor-profile exports, CSV files and ZIP archives can take far longer than a request should. They run as background work on Cloud Tasks and Cloud Functions; the file lands in Cloud Storage, and Firebase Cloud Messaging tells the admin when it is ready — the console asks for notification permission for exactly this. A download history keeps track of past exports.

Business email covers the rest of the lifecycle: registration complete, licence verified, licence not verified, additional documents requested, and system or operational notices.

Asynchronous download flowAn admin requests an export through the backend API. The backend hands the work to a background task or batch; the task reads Firestore and business data, builds a CSV or ZIP file and stores it in Cloud Storage. When the file is ready, Firebase Cloud Messaging sends a completion notice, so the admin does not have to keep a screen open waiting on a long request.

Admin requests an export

Backend API

Background task / batch

Firestore / business data

CSV / ZIP

Cloud Storage

Firebase Cloud Messaging

Completion notice

Diagram fitted to its frame

The admin asks once and is told when the file exists, instead of holding a screen open on a long request.

Job search on Elasticsearch

The member portal includes recruitment and job search, filtered by free text, employment type and prefecture. Search, filtering and sorting run on Elasticsearch indexes rather than on Firestore, and searches and clicks are logged for points, tracking and analytics.

High-level architecture

Angular applications sign in through Firebase Authentication and call a Node.js / NestJS backend. Firestore holds business data, Cloud Storage holds files, Elasticsearch serves search, and Cloud Run, Cloud Functions and Cloud Tasks carry the background work. BigQuery serves aggregation and reporting, Cloud Logging collects logs, and Firebase Cloud Messaging delivers notifications.

Dr.Well-B high-level technical architectureUsers and admins use Angular web applications. The frontend signs in through Firebase Authentication and calls the Node.js / NestJS backend. The backend works with Firestore, Cloud Storage, Elasticsearch and Cloud Run. Cloud Run queues work in Cloud Tasks, sends notifications through Firebase Cloud Messaging, writes data to BigQuery and logs to Cloud Logging. Cloud Tasks and Cloud Functions write to Firestore; Firestore feeds BigQuery; Cloud Functions also log to Cloud Logging. These are the main components in the project documentation, not a one-to-one copy of the internal production diagram.

Users

Admins

Angular web applications

Firebase Authentication

Node.js / NestJS backend

Firestore

Cloud Storage

Elasticsearch

Cloud Run

Cloud Functions

Cloud Tasks

Firebase Cloud Messaging

BigQuery

Cloud Logging

Diagram fitted to its frame

The main components in the project documentation. This is not a one-to-one copy of the internal production diagram.

How data moves between modules

Overall data flow between modulesThe user profile is an input to ads, surveys and jobs. User actions are written to action logs; ads and jobs write to the action logs too, while surveys feed analytics and BigQuery directly. Action logs feed the point engine and analytics. Jobs use search. The point engine and analytics both produce exports and reports. The content module stands on its own and takes no part in these data flows.

Profile

User actions

Ads

Survey

Job

Content

Action logs

Point engine

Search

Analytics / BigQuery

Export / report

Diagram fitted to its frame

Profiles flow into ads, surveys and jobs; actions flow into logs; logs and survey data flow into points, analytics and exports.

What the project covers

Concern in a large management systemHow it shows up in Dr.Well-B
Business workflow with approvalLicence verification, admin approval, approval history, locked records
Rules configured by operators, not codeSurvey engine with question relations; ad delivery rules
PersonalisationAd selection by specialty, society, tags, schedule, limits and behaviour
Event and batch processingAction logs, a daily point batch, then monthly aggregation and files
Long-running workBackground exports on Cloud Tasks / Cloud Functions, FCM notification
Search at scaleElasticsearch indexes and sorting, separate from Firestore
ReportingBigQuery aggregation, CSV/ZIP export, download history
Keeping many rules from regressingCypress automation across services, surveys and mobile browsers

The diagrams are reconstructed at component level from the project's design documents. They omit internal URLs, identifiers, proprietary code and client data; the screenshots use test accounts and demo data, with internal names blurred.

Image 1 of 5