Skip to content

feat(web): Add email agent support (DB, API, UI, tests)#335

Merged
cungminh2710 merged 4 commits intomainfrom
codex/implement-inbound-email-generation-feature
Apr 25, 2026
Merged

feat(web): Add email agent support (DB, API, UI, tests)#335
cungminh2710 merged 4 commits intomainfrom
codex/implement-inbound-email-generation-feature

Conversation

@cungminh2710
Copy link
Copy Markdown
Contributor

Motivation

  • Introduce an inbound email agent feature so organizations can receive translation requests via a unique workspace email address.

Description

  • Add a Drizzle SQL migration 0004_large_email_agent.sql and update the migration journal to add email_agent_enabled and inbound_email_alias columns and a unique index on inbound_email_alias for organizations.
  • Extend the DB schema in schema.ts to include emailAgentEnabled and inboundEmailAlias columns and the corresponding unique index declaration.`
  • Implement createAgentEmailRoutes in agent-email.route.ts providing authenticated GET and PATCH endpoints that generate and persist a unique alias (with retry on unique-constraint conflicts) and return emailAgent state.`
  • Wire the new route into the API (app.ts), add frontend support in AgentPageContent to fetch and toggle the email agent via react-query, show loading Skeleton, copy address to clipboard, and show toasts, and add an API integration test (agent-email.test.ts).

Testing

  • Ran the new API route unit test src/api/routes/agent-email/agent-email.test.ts which exercised enable/disable flows and alias persistence, and it passed.
  • Executed the project test harness (existing route tests) after changes and the test suite completed successfully.

Codex Task

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hyperlocalise Ignored Ignored Apr 25, 2026 2:32am

Request Review

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 25, 2026

Greptile Summary

This PR adds an inbound email agent feature: a DB migration adding email_agent_enabled and inbound_email_alias to organizations, a Hono route (GET/PATCH) with admin gating and collision-retry alias generation, frontend React Query hooks with skeleton loading and error UI, and integration tests.

  • P1 — non-atomic enable flow in agent-email.route.ts (lines 150–191): The re-enable path (alias already exists) is a two-step read-then-write: ensureInboundAlias SELECTs the stale record, then a second UPDATE flips emailAgentEnabled. If the second UPDATE returns no rows (org deleted between the two calls), the handler falls through and returns { enabled: false } with HTTP 200 instead of 404. A single authoritative UPDATE covering both the flag and a 404 guard would fix this.

Confidence Score: 4/5

Safe to merge with the non-atomic re-enable edge case addressed; the bug only triggers if the org is deleted between two DB calls.

One P1 finding: the two-step enable flow can return HTTP 200 with enabled: false when the organization is deleted between the two DB calls. In practice this is unlikely, but it is a real correctness defect on the changed code path. All previous review concerns (admin guard, unused router export, error state UI) appear to have been resolved.

apps/hyperlocalise-web/src/api/routes/agent-email/agent-email.route.ts — enable/re-enable control flow (lines 150–191)

Important Files Changed

Filename Overview
apps/hyperlocalise-web/src/api/routes/agent-email/agent-email.route.ts New authenticated GET + PATCH endpoints for the email agent; admin guard and alias-generation retry loop are present, but the enable path has a non-atomic two-step DB flow that can return stale state or a misleading 200 when the org is concurrently deleted.
apps/hyperlocalise-web/src/api/routes/agent-email/agent-email.test.ts Integration tests cover disabled state, first enable + alias persistence + re-enable, and member-role blocking; implicit role in the second test is a minor clarity gap.
apps/hyperlocalise-web/src/components/app/agent-page-content.tsx React Query hooks for fetch and mutation with loading skeleton, error state, and toast feedback; isError is correctly surfaced to disable the switch and show an inline message.
apps/hyperlocalise-web/drizzle/0004_gigantic_stellaris.sql Adds email_agent_enabled boolean (NOT NULL, default false) and nullable inbound_email_alias text with a unique index; migration looks correct for PostgreSQL NULL semantics on the unique index.
apps/hyperlocalise-web/src/lib/database/schema.ts Schema columns and unique index declaration match the migration; no issues.
apps/hyperlocalise-web/src/api/app.ts New route wired at /orgs/:organizationSlug/agent-email; clean and consistent with other org-scoped routes.

Fix All in Codex

Prompt To Fix All With AI
This is a comment left during a code review.
Path: apps/hyperlocalise-web/src/api/routes/agent-email/agent-email.route.ts
Line: 150-191

Comment:
**Non-atomic re-enable returns stale `enabled: false`**

On the re-enable path (alias already set, `emailAgentEnabled = false`), `ensureInboundAlias` returns a snapshot with `emailAgentEnabled: false` from its SELECT, and the handler then issues a *second* separate UPDATE. If that second UPDATE finds no rows (e.g., the org was just deleted), the code falls through to the final `return` and responds with `{ enabled: false }` and HTTP 200 instead of the expected 404 error. The two-step read-then-write also creates a window where a concurrent disable could win, leaving the response claiming `enabled: true` while the database holds `false`.

A single idempotent `UPDATE ... SET email_agent_enabled = $1 RETURNING ...` (combined with a separate alias-generation step only when the alias is still NULL) would eliminate both issues.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: apps/hyperlocalise-web/src/api/routes/agent-email/agent-email.test.ts
Line: 67-69

Comment:
**Implicit role assumption in enable test**

`fixture.createWorkosIdentity()` is used without an explicit role, relying on the fixture's default to be admin/owner for the PATCH to succeed. Since the PATCH now enforces admin-only (tested explicitly in the third test case), using `createWorkosIdentityWithRole("admin")` here makes the intent clear and guards against a future fixture default change silently breaking the test.

```suggestion
  const identity = fixture.createWorkosIdentityWithRole("admin");
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "." | Re-trigger Greptile

Comment thread apps/hyperlocalise-web/src/api/routes/agent-email/agent-email.route.ts Outdated
Comment thread apps/hyperlocalise-web/src/components/app/agent-page-content.tsx Outdated
@cungminh2710 cungminh2710 changed the title Add email agent support (DB, API, UI, tests) feat(web): Add email agent support (DB, API, UI, tests) Apr 25, 2026
@cungminh2710 cungminh2710 merged commit 6b18baf into main Apr 25, 2026
4 checks passed
@cungminh2710 cungminh2710 deleted the codex/implement-inbound-email-generation-feature branch April 25, 2026 02:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant