Inspiration
Most review tools ask, "How fast can I reply?" For a small business, the better question is "Should I reply at all?"
A cheerful template under a review that says "the food made me sick, I'm calling a lawyer" can turn a bad day into a legal problem. A reply to a spam ad gives it free visibility. And many local businesses, especially in Pakistan, get reviews in Roman Urdu, Urdu, English, or a mix of all three. Owners often can't tell whether a reply is safe without help.
That's where the tagline came from: Know when not to reply.
What it does
ReviewDesk is a reply desk for Google Business reviews. It sorts every review into one of four lanes:
| Lane | Meaning |
|---|---|
| Reply | A public reply is safe. A draft is ready for your approval. |
| Check facts | The review makes a claim you should verify before answering. |
| Hold | Do not reply publicly yet. The owner needs to review it first. |
| Report | Looks like spam or a policy violation. Guidance for Google's report option. |
For each review it:
- writes a 30–80 word draft in the reviewer's language, with an English copy so the owner knows exactly what it says;
- shows why it chose a lane, such as "risk flag: health";
- lets you edit, keep draft versions, insert saved phrases, and copy the reply;
- records every decision in a ledger with its reason.
Nothing is posted automatically. The owner approves each reply and copies it by hand. Live posting to Google is a separate, optional setting.
An opt-in Autopilot can record clean, high-star replies after a veto window, but only inside a strict safety policy: it starts off, dry run is on by default, mixed-sentiment reviews wait for a human, and a daily cap limits volume.
Around that core there is a workspace for real use: team roles (owner, manager, responder, viewer), keyword automation rules like "Hold health and legal claims", reusable reply templates, CSV import and export, search and filters, and keyboard shortcuts.
How I built it
- App: Next.js 16 and TypeScript, deployed on Vercel.
- Data: Prisma with PostgreSQL.
- UI: Tailwind CSS and daisyUI, with a motion layer (aurora background, scroll reveal, count-up numbers) that respects reduced-motion settings.
- Engine: the prompts and policy rules live in a pure logic layer, separate from the database and secrets, so the rules can be read and reviewed on their own.
- Security: Google credentials are encrypted with AES-256-GCM before storage and never sent back to the browser. Passwords are hashed with bcrypt, sessions use signed httpOnly cookies, and reset links are single-use. Review text goes to the model provider for triage and nowhere else.
- Process: I built it with an opencode coding agent. An
AGENTS.mdfile set the build order, with a stop after each step so I could review the result before moving on.
The model only suggests. A deterministic policy decides whether an Autopilot reply may be recorded:
$$ \text{auto}(r)=\big[\text{stars}(r)\ge s_{\min}\big]\;\wedge\;\big[\text{lang}(r)\in\mathcal{L}{\text{trusted}}\big]\;\wedge\;\neg\,\text{risk}(r)\;\wedge\;\neg\,\text{mixed}(r)\;\wedge\;\big[n{\text{today}}<c\big] $$
A reply that passes is recorded only after a veto window of $T = 30$ minutes, and the owner can undo it. If any condition fails, the review goes to the approval queue instead.
Challenges
- Roman Urdu has no spelling standard. "Khana thanda tha" and "khana thanda thaa" both mean the same thing. Detecting the language and keeping the reply natural took the most care. I added a trusted languages setting so Autopilot only touches languages a native reader has checked.
- Reviews are untrusted input. The demo inbox includes a spam ad and a prompt-injection attempt ("Ignore your previous instructions…"), so the rules are tested against hostile text.
- Deciding what the AI may never do alone. Writing replies was the easy part. The hard design question was which decisions stay with a human. The answer is encoded as policy rules, not just a prompt.
- Reviewing agent-written code. A review pass caught a missing constant that would have crashed the credential test, an API route that had been deleted while the UI still called it, and type errors in the Autopilot settings.
- Accessibility versus animation. My animated headings were silent to screen readers until I added a readable copy of the text.
What I learned
- Agents work best with clear rules, small steps, and a stop after each one.
- Safety rules belong in readable code, not only in a prompt.
- Type checks and lint don't catch everything, such as a UI that screen readers can't read or a route that was quietly removed.
- For a tool that writes in public, a clear "don't reply" is worth as much as a good draft.
What's next
- Post approved replies directly to Google through the connected account.
- Tests for the policy rules and the language checks.
- Dark mode, once the remaining hard-coded colors move onto theme tokens.
Built With
- ai
- bcrypt
- daisyui
- eslint
- github-actions
- google-business-profile-api
- google-reviews
- jwt
- llm
- lucide-react
- neon
- nextjs
- node.js
- nodemailer
- postgresql
- prettier
- prisma
- radix-ui
- react
- rest-api
- shadcn-ui
- tailwindcss
- typescript
- vercel
Log in or sign up for Devpost to join the conversation.