Review AI

Case Summary
Client
DWK Partners (in-house solution)
Industry
Restaurant review management, AI reply generation
Period
June 2025 – September 2025 (about 4 months)
Challenge
Reviews were scattered across four platforms, making the checking workflow long, and it was hard to write new reply sentences each time
Key features
Unified collection of platform reviews, AI reply generation, response tone settings, statistics dashboard, weekly report
Outcome
Work that meant moving between four apps brought onto one screen, reply writing shifted from "writing" to "checking and sending"
1. About the Service
Review AI is a review management service developed in-house by DWK Partners.
- Target users: Restaurant business owners who manage delivery and place reviews
- Integrated platforms: Baedal Minjok (Baemin), Yogiyo, Coupang Eats, Naver Place
- Delivery format: Mobile-first web service, subscription billing
- Core components: Review collection service + AI reply generation + operational statistics
2. Background
When you run a restaurant, reviews accumulate separately on Baedal Minjok, Yogiyo, Coupang Eats and Naver Place. Each platform has its own owner app, and each requires a separate login. Replying means opening four apps in turn, and once the busy hours pass, reviews pile up. In most cases the reason replies are late or missed is not a lack of will but a problem with the workflow.
The workflow is not the only problem
The content of the replies is also a burden. A good review calls for thanks, and a low rating calls for an apology and a promise to improve, but after writing dozens a day the sentences become identical. A reply that is obviously copied and pasted is worse than no reply at all. Yet there is no time to write a new one each time. In the end, owners respond only to reviews with low ratings, or give up altogether.
From writing to checking
Review AI is an in-house solution built to reduce these two burdens. We developed it over about four months, from June to September 2025. It automatically collects reviews from several platforms and gathers them on one screen, and AI produces a draft reply suited to the content of each review. What the owner does changes from writing sentences to checking and sending.
The premise of collecting without a public API
The first thing decided in the design was the collection method. Most delivery platforms do not provide a public API for owners. So reviews had to be fetched by automating the actions a person would perform in a browser (RPA), and this approach has to be designed on the assumption of failure, because platform screens change, logins expire and responses slow down all the time.
If review management had nothing to do with sales, a service like this would not be needed. But in delivery apps, reviews and ratings affect ranking in listings, and they are also the first information consumers look at before ordering. A review with a reply and one without read differently even at the same rating. The problem was that this was hard to act on even when owners knew it. Things people know they should do but cannot are usually a problem of procedure, not motivation, and procedure can be changed with tools.
Following a restaurant through its day makes the problem clear. The time available for looking at reviews is the brief sit-down after the lunch peak, before dinner preparation begins. Opening four apps, logging in, finding new reviews and thinking up sentences in that short time is not realistic. What the tool has to do is not extend this time, but make it possible to finish within the same time.
In one line What the owner does changes from "writing sentences" to "checking and sending."
3. Key Features
We combined review collection, AI reply generation and operational analysis into one service. The repository is organized as a monorepo that manages the web application, the database package and the collection service together.
Collection service
Platform reviews are fetched by a collection service that runs independently. This service runs as a separate process from the web application and is divided into an API that receives collection requests, a scheduler responsible for periodic execution, and workers that perform the actual collection. Whether the user presses the "Sync now" button on the web or the scheduler runs at the set time, the same worker is executed.
The collection range does not sweep everything each time; only the needed section is fetched. If the user specifies a period, that period is collected; if not, the system finds the date of the last review in the database and collects only what comes after it. If the lookup fails or the account is being connected for the first time, a default period is applied. Fetching everything each time would make collection time keep growing and would also put load on the platforms, so incremental collection was made the default.
Job queue
Collection is done by putting jobs in a queue and processing them in order. If one store has four platforms connected, four jobs are created and each runs independently. If a particular platform does not respond, only that job is marked as failed and the rest continue. Failed jobs remain as retry candidates and are executed again.
There is one more reason for having a queue. Collection is a long-running task and cannot be handled within a web request. The request ends with registering the job, and the actual collection results are reflected on screen later.
Web application
On the web, the owner sees reviews in a single list regardless of platform. Selecting a review generates an AI draft reply, which can be sent as is or edited and sent. In the store settings, the owner manages the response tone, connected accounts and notification conditions.
The screens are designed mobile-first, because owners mostly check reviews inside the store, and what they have in hand at that moment is a phone. Onboarding, store registration, platform connection, review management, statistics, weekly report and settings each exist as their own screen.
Data structure
Data is divided into stores, platform accounts, reviews, replies and job history. One store can have several platform accounts, and reviews are attached to each account. Replies belong to reviews, but the generated draft and the reply actually posted are stored separately. Keeping the draft and the posted version apart makes it possible to check how much the AI-written sentences were edited before going out, and this serves as a basis for reviewing generation quality.
Job history is kept per collection run. It records when collection was attempted for which account, how many items were fetched, and, if it failed, at which stage it stopped. In a system that operates without a public API, this record is the starting point for incident response.
Platform connection management
Connecting a platform account is not something that is done once and finished. If the password is changed or additional authentication is triggered, the connection breaks, and if it is left in that state no reviews come in. Connection status is managed per account, and collection that failed because of an authentication problem is displayed separately from ordinary failures. The user can see right on screen which account needs to be reconnected.
Because several platform accounts are attached to one store, the connection status and last collection time are shown separately for each account. If users cannot tell whether everything has stopped or only a particular platform has stopped, they come to doubt the service as a whole.
Weekly report
The review status for the week is summarized in a report, because even users who do not check every day need to be able to grasp the overall trend on a weekly basis. It brings together items that can serve as management indicators, such as rating changes, review counts and reply rate.
How the work proceeded
Within the four-month period, the priority was clear. If collection does not work, the remaining features are meaningless, so we first completed collection for one platform end to end. We built the list screen with the collected data, added reply generation on top of it, and expanded to the other platforms last.
The reason we did not connect the platforms all at once is that each platform has a different screen structure and authentication method. Only after going through one of them to the end does it become clear which parts to extract as common and which to leave platform-specific. The collection interface organized while completing the first platform became the standard for the later expansion.
Main features
Unified management of reviews from several platforms
Reviews from Baedal Minjok, Yogiyo, Coupang Eats and Naver Place are viewed in one list. There is no need to move between apps for each platform, and filtering to unanswered reviews only or sorting by rating is done in one step. Each review shows its source platform, so there is no confusion about where it was posted.
AI automatic reply generation
The service generates a draft reply that reflects the review content and rating. A response tone can be set for each store, so the same review yields sentences suited to the character of the store, because the replies of a store that uses a formal tone and one that uses a friendly tone should differ. The way of responding to low-rated and high-rated reviews is also differentiated. If the generated sentences are not satisfactory, the user can regenerate them or edit them directly.
Incremental collection and automatic sync
Only reviews after the date of the last collected review are fetched. Collection time does not grow as data accumulates, and storing the same review twice is also prevented. Because the scheduler runs periodically, new reviews come in without the user having to press sync.
Failed job isolation and retry
Even if one platform does not respond, collection for the other platforms continues, because the unit of work is divided by platform. The status of a failed job is recorded and it becomes a retry candidate. Situations that retrying does not solve, such as a problem with a connected account, are displayed separately so that the user is guided to reconnect the account.
Statistics dashboard
Rating trends, review counts by platform and reply rate can be checked by period. The point at which reviews increase or ratings fall can be pinned down with data, and if ratings are low only on a particular platform, that becomes a basis for reviewing how that platform is operated.
Weekly report
The review status is summarized and provided on a weekly basis. Even users who do not check the dashboard every day do not miss the weekly trend. It is structured for comparison with the previous week, so that it shows change rather than a single number.
Important review notifications
A notification is sent when a review with a low rating or one that meets specific conditions comes in. Not every review can be checked in real time, so this is a mechanism for picking out and notifying only the reviews that need to be dealt with first. Notification conditions are adjusted in the store settings.
Subscription billing
The service is offered as a subscription, and payments are processed through an integration with Toss Payments. The trial period is provided through a separate path so that the features can be checked before paying.
Response tone settings
The response tone is stored per store so that the sentences suit the character of the store. Once the user specifies whether to use formal or friendly expressions and how long replies should be, this is applied consistently to subsequent generation. If the character changes from reply to reply, it looks as though several people took turns writing them, so it is more natural to fix the generation criteria to the store.
Onboarding and store connection
A newly registered user goes through the process of registering a store and connecting platform accounts. This process is divided into step-by-step screens so that not all of the information has to be entered at once. When the connection is finished, the first collection runs automatically, so the user can see reviews for their own store coming in right after signing up.
Clearing unanswered reviews
The default state of the review list was set closer to "what needs to be handled" than to "all." Unanswered reviews are shown first, and once a reply is sent the review is cleared from the list, because people follow through to the end only when they can see the work to be done shrinking. Filters for narrowing the range by period, platform and rating were added on top of that.
Core design Collection that operates without a public API has to be designed on the assumption of failure. Jobs were split into a queue so that the unit of failure can be pinpointed.
4. Outcome
Checking reviews and writing replies, previously scattered across four platforms, were brought together on one screen. Instead of opening an app four times, the owner opens one, and instead of writing sentences, checks and sends. The workflow and the burden of writing, which were the biggest causes of replies piling up, were reduced together.
Because collection was separated out on a queue basis, the rest of the collection continues even if a problem occurs on one platform. With incremental collection as the default, collection time does not grow as data accumulates. In a collection system that operates without a public API, these two things determine most of its stability.
By providing statistics and the weekly report together, review management goes beyond individual responses and leads on to operational indicators, because the point at which ratings fall and the review content at that time can be seen together.
Allowing the draft reply to be regenerated was also a deliberate choice. The first sentence the AI writes cannot always be right, and telling users to rewrite it themselves when they do not like it ultimately returns them to the same burden as at the start. With the cost of regenerating kept low, users press a few times and pick one of the results. This process is faster than writing it themselves.
The structure in which the collection service is separated as an independent process is used as is when platforms are added later. A new platform becomes a matter of adding one crawler module, and the queue, scheduler and storage logic are left untouched. The more integration targets there are, the greater the benefit of this structure.
Storing the draft and the posted version separately also helped operations. Because it is possible to check how much the generated sentences are edited before going out, response quality is reviewed from records rather than intuition.
We built the service, including the web application, collection service and payments, from June to September 2025.
5. Technical Overview
Web
Built with Next.js 15, React 18 and Tailwind CSS. It uses a mobile-first layout, with server-side rendering and API routes used together. Static pages such as the service introduction, pricing, terms and refund policy are included in the same application.
Collection service
An independent service based on Node.js and Express. It consists of an API that receives collection requests, a scheduler responsible for periodic execution and workers that perform the actual collection, with the collection logic for each platform separated into crawler modules. When a platform is added, only the crawlers increase and the rest of the structure stays as it is.
Queue / Storage
The job queue is built with BullMQ and Redis. Job registration and execution are separated, and the status of failed jobs is tracked. The database is Prisma ORM with PostgreSQL, and the schema is separated into its own package so that the web application and the collection service share the same definition.
Monorepo structure
Turborepo is used to manage the web application, the database package and the collection service in a single repository. When the schema changes, it is reflected in both services at the same time, so a situation in which only one side uses an older schema does not arise.
Deployment
The deployment is built with Docker and Docker Compose, and build and deployment are automated with GitHub Actions. The collection service runs in a separate container from the web application so that collection load does not affect web responses.
Operating environment
The success and failure of collection jobs and the number of items processed are recorded and the status is checked. Collection runs when no one is watching, so without records a problem would go unnoticed until a user makes an inquiry. Keeping a job history was a measure needed before attaching a separate monitoring tool.
For deployment, the web application and the collection service are each brought up in their own container. When the collection logic is changed, the web application is not redeployed, and the reverse is also true. In a service where the collection side is modified frequently, for example in response to platform screen changes, this separation reduces the deployment burden.
Criteria for technology choices
The point that breaks most often in this service is collection. So the criterion for technology choices was also "When it breaks, can we tell where it broke?" Keeping collection as a service separate from the web application means collection failures do not affect web responses, and putting jobs in a queue makes it possible to pinpoint the unit that failed. Separating the schema into a shared package prevents the two services from assuming different structures.
The web side, by contrast, was kept simple. The review list and reply writing are not screens that need complex state management, and a tool used by owners is better when it loads quickly.
Problems addressed during implementation
Platform screen changes. Collection without a public API depends on the screen structure of the platform. When the screen changes, collection breaks, and we need to know that before the user does. This is why job failures are kept as a status and recorded separately from retries.
Duplicate collection. Storing the same review several times throws the statistics off. The range is set from the last collection point, and duplicates are also checked at the storage stage.
Separating collection from the response. Collection takes from tens of seconds to several minutes. Handling this within a web request would freeze the screen. We split it so that the request goes only as far as registering the job and the result is reflected afterward.
Consistency of response quality. If the generated replies come out with a different character each time, the voice of the store wavers. The response tone is stored per store so that the same criteria are applied to every generation request.
Controlling collection load. If collection for many stores concentrates at the same time, the platform side may judge it to be abnormal access. The structure of putting jobs in a queue and processing them sequentially serves not only to separate functions but also to control the request rate.
Volume of notifications. If every review triggers a notification, notifications get ignored. The reason stores set the conditions themselves is that which reviews are urgent depends on the type of business and how it is operated.
6. Project Information
| Item | Details |
|---|---|
| Project name | Review AI (web/app, automatic replies) development |
| Scope of work | Planning, web and collection service development, payment integration |
| Technologies | Next.js, React, Node.js, Express, BullMQ, Redis, Prisma, PostgreSQL, Docker, Toss Payments |
Planning a similar project?
Share your requirements and timeline, and we will outline a suitable scope and setup.
Comments 0
Be the first to leave a comment.