-
-
Notifications
You must be signed in to change notification settings - Fork 292
feat: contact books public api #336
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: contact books public api #336
Conversation
|
@magicspon is attempting to deploy a commit to the kmkoushik's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Warning Rate limit exceeded@magicspon has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 16 minutes and 33 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughThis pull request adds a Contact Books feature: five new HTTP endpoints (GET list, POST create, GET retrieve, PATCH update, DELETE delete) and corresponding route handlers registered in the public API bootstrap. It introduces a Zod ContactBookSchema, service-backed handler implementations that coerce properties to Record<string,string>, updates API reference docs and navigation with five new MDX files, and extends the OpenAPI specification with the new paths. No existing endpoints or functionality are removed or modified. Pre-merge checks❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3 issues found across 14 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="apps/web/src/server/public-api/api/contact-books/get-contact-book.ts">
<violation number="1" location="apps/web/src/server/public-api/api/contact-books/get-contact-book.ts:30">
P2: The 403 response is documented in the OpenAPI spec but never returned by the implementation. The query filters by both `id` and `teamId`, so when a contact book exists but belongs to another team, it returns 404 instead of 403. Either remove the 403 response definition (if returning 404 for security reasons is intentional) or update the logic to first check existence, then authorization.</violation>
</file>
<file name="apps/web/src/server/public-api/api/contact-books/create-contact-book.ts">
<violation number="1" location="apps/web/src/server/public-api/api/contact-books/create-contact-book.ts:40">
P2: Remove debug `console.log` statement before merging. This will output team data to production logs.</violation>
</file>
<file name="apps/docs/api-reference/contact-books/list-contact-books.mdx">
<violation number="1" location="apps/docs/api-reference/contact-books/list-contact-books.mdx:2">
P2: URL path naming convention inconsistent with existing API endpoints. Existing API documentation uses camelCase (`/v1/contactBooks/...`) for the contact books resource, but this new file uses kebab-case (`/v1/contact-books`). Consider using `/v1/contactBooks` for consistency.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| }, | ||
| description: "Retrieve the contact book", | ||
| }, | ||
| 403: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: The 403 response is documented in the OpenAPI spec but never returned by the implementation. The query filters by both id and teamId, so when a contact book exists but belongs to another team, it returns 404 instead of 403. Either remove the 403 response definition (if returning 404 for security reasons is intentional) or update the logic to first check existence, then authorization.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/server/public-api/api/contact-books/get-contact-book.ts, line 30:
<comment>The 403 response is documented in the OpenAPI spec but never returned by the implementation. The query filters by both `id` and `teamId`, so when a contact book exists but belongs to another team, it returns 404 instead of 403. Either remove the 403 response definition (if returning 404 for security reasons is intentional) or update the logic to first check existence, then authorization.</comment>
<file context>
@@ -0,0 +1,85 @@
+ },
+ description: "Retrieve the contact book",
+ },
+ 403: {
+ content: {
+ "application/json": {
</file context>
| const team = c.var.team; | ||
| const body = c.req.valid("json"); | ||
|
|
||
| console.log({ team }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Remove debug console.log statement before merging. This will output team data to production logs.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/server/public-api/api/contact-books/create-contact-book.ts, line 40:
<comment>Remove debug `console.log` statement before merging. This will output team data to production logs.</comment>
<file context>
@@ -0,0 +1,67 @@
+ const team = c.var.team;
+ const body = c.req.valid("json");
+
+ console.log({ team });
+
+ const contactBook = await createContactBookService(team.id, body.name);
</file context>
✅ Addressed in 8a8be80
| @@ -0,0 +1,3 @@ | |||
| --- | |||
| openapi: get /v1/contact-books | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: URL path naming convention inconsistent with existing API endpoints. Existing API documentation uses camelCase (/v1/contactBooks/...) for the contact books resource, but this new file uses kebab-case (/v1/contact-books). Consider using /v1/contactBooks for consistency.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/docs/api-reference/contact-books/list-contact-books.mdx, line 2:
<comment>URL path naming convention inconsistent with existing API endpoints. Existing API documentation uses camelCase (`/v1/contactBooks/...`) for the contact books resource, but this new file uses kebab-case (`/v1/contact-books`). Consider using `/v1/contactBooks` for consistency.</comment>
<file context>
@@ -0,0 +1,3 @@
+---
+openapi: get /v1/contact-books
+---
</file context>
✅ Addressed in 3a5a8df
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
apps/docs/api-reference/contact-books/create-contact-book.mdxapps/docs/api-reference/contact-books/delete-contact-book.mdxapps/docs/api-reference/contact-books/get-contact-book.mdxapps/docs/api-reference/contact-books/list-contact-books.mdxapps/docs/api-reference/contact-books/update-contact-book.mdxapps/docs/api-reference/openapi.jsonapps/docs/docs.jsonapps/web/src/lib/zod/contact-book-schema.tsapps/web/src/server/public-api/api/contact-books/create-contact-book.tsapps/web/src/server/public-api/api/contact-books/delete-contact-book.tsapps/web/src/server/public-api/api/contact-books/get-contact-book.tsapps/web/src/server/public-api/api/contact-books/get-contact-books.tsapps/web/src/server/public-api/api/contact-books/update-contact-book.tsapps/web/src/server/public-api/index.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
Include all required imports and ensure proper naming of key components in React/NextJS code
Files:
apps/web/src/server/public-api/api/contact-books/get-contact-books.tsapps/web/src/server/public-api/api/contact-books/create-contact-book.tsapps/web/src/lib/zod/contact-book-schema.tsapps/web/src/server/public-api/api/contact-books/update-contact-book.tsapps/web/src/server/public-api/api/contact-books/delete-contact-book.tsapps/web/src/server/public-api/index.tsapps/web/src/server/public-api/api/contact-books/get-contact-book.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Use TypeScript-first approach with 2-space indent and semicolons enabled by Prettier in apps/web (Next.js), apps/marketing, apps/smtp-server, and all packages
Never use dynamic imports; always import on the top level
Run ESLint via @usesend/eslint-config and ensure no warnings remain before submitting PRs
Files:
apps/web/src/server/public-api/api/contact-books/get-contact-books.tsapps/web/src/server/public-api/api/contact-books/create-contact-book.tsapps/web/src/lib/zod/contact-book-schema.tsapps/web/src/server/public-api/api/contact-books/update-contact-book.tsapps/web/src/server/public-api/api/contact-books/delete-contact-book.tsapps/web/src/server/public-api/index.tsapps/web/src/server/public-api/api/contact-books/get-contact-book.ts
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use alias
~/for src imports in apps/web (e.g.,import { x } from "~/utils/x")
Files:
apps/web/src/server/public-api/api/contact-books/get-contact-books.tsapps/web/src/server/public-api/api/contact-books/create-contact-book.tsapps/web/src/lib/zod/contact-book-schema.tsapps/web/src/server/public-api/api/contact-books/update-contact-book.tsapps/web/src/server/public-api/api/contact-books/delete-contact-book.tsapps/web/src/server/public-api/index.tsapps/web/src/server/public-api/api/contact-books/get-contact-book.ts
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/**/*.{ts,tsx}: Prefer to use TRPC for client-server communication unless explicitly asked otherwise in apps/web
Use Prisma for database access in apps/web
Files:
apps/web/src/server/public-api/api/contact-books/get-contact-books.tsapps/web/src/server/public-api/api/contact-books/create-contact-book.tsapps/web/src/lib/zod/contact-book-schema.tsapps/web/src/server/public-api/api/contact-books/update-contact-book.tsapps/web/src/server/public-api/api/contact-books/delete-contact-book.tsapps/web/src/server/public-api/index.tsapps/web/src/server/public-api/api/contact-books/get-contact-book.ts
**/*.{ts,tsx,md}
📄 CodeRabbit inference engine (AGENTS.md)
Run Prettier 3 for code formatting on TypeScript, TSX, and Markdown files
Files:
apps/web/src/server/public-api/api/contact-books/get-contact-books.tsapps/web/src/server/public-api/api/contact-books/create-contact-book.tsapps/web/src/lib/zod/contact-book-schema.tsapps/web/src/server/public-api/api/contact-books/update-contact-book.tsapps/web/src/server/public-api/api/contact-books/delete-contact-book.tsapps/web/src/server/public-api/index.tsapps/web/src/server/public-api/api/contact-books/get-contact-book.ts
🧬 Code graph analysis (5)
apps/web/src/server/public-api/api/contact-books/get-contact-books.ts (4)
apps/web/src/lib/zod/contact-book-schema.ts (1)
ContactBookSchema(3-23)apps/web/src/server/service/contact-book-service.ts (1)
getContactBooks(6-18)apps/web/src/server/public-api/index.ts (1)
app(30-30)apps/web/src/server/public-api/hono.ts (1)
PublicAPIApp(136-136)
apps/web/src/server/public-api/api/contact-books/create-contact-book.ts (4)
apps/web/src/lib/zod/contact-book-schema.ts (1)
ContactBookSchema(3-23)apps/web/src/server/service/contact-book-service.ts (2)
createContactBook(20-40)updateContactBook(69-81)apps/web/src/server/public-api/index.ts (1)
app(30-30)apps/web/src/server/public-api/hono.ts (1)
PublicAPIApp(136-136)
apps/web/src/server/public-api/api/contact-books/update-contact-book.ts (6)
apps/web/src/lib/zod/contact-book-schema.ts (1)
ContactBookSchema(3-23)apps/web/src/server/service/contact-book-service.ts (1)
updateContactBook(69-81)apps/web/src/server/public-api/index.ts (1)
app(30-30)apps/web/src/server/public-api/hono.ts (1)
PublicAPIApp(136-136)apps/web/src/server/db.ts (1)
db(20-20)apps/web/src/server/public-api/api-error.ts (1)
UnsendApiError(62-75)
apps/web/src/server/public-api/api/contact-books/delete-contact-book.ts (5)
apps/web/src/server/service/contact-book-service.ts (1)
deleteContactBook(83-87)apps/web/src/server/public-api/index.ts (1)
app(30-30)apps/web/src/server/public-api/hono.ts (1)
PublicAPIApp(136-136)apps/web/src/server/db.ts (1)
db(20-20)apps/web/src/server/public-api/api-error.ts (1)
UnsendApiError(62-75)
apps/web/src/server/public-api/index.ts (2)
apps/web/src/server/service/contact-book-service.ts (4)
getContactBooks(6-18)createContactBook(20-40)updateContactBook(69-81)deleteContactBook(83-87)apps/web/src/server/public-api/api-utils.ts (1)
getContactBook(5-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: cubic · AI code reviewer
🔇 Additional comments (13)
apps/docs/api-reference/contact-books/update-contact-book.mdx (1)
1-3: LGTM! Documentation structure is correct.The MDX file correctly references the PATCH operation for updating contact books. The structure follows the expected pattern for OpenAPI-based documentation.
apps/docs/api-reference/contact-books/list-contact-books.mdx (1)
1-3: LGTM! Documentation structure is correct.The MDX file correctly references the GET operation for listing contact books. The structure is consistent with the other Contact Books API documentation files.
apps/docs/api-reference/contact-books/create-contact-book.mdx (1)
1-3: LGTM! Documentation structure is correct.The MDX file correctly references the POST operation for creating contact books. The structure follows the expected pattern.
apps/docs/api-reference/contact-books/delete-contact-book.mdx (1)
1-3: LGTM! Documentation structure is correct.The MDX file correctly references the DELETE operation for removing contact books. The structure is consistent with the other endpoint documentation files.
apps/docs/api-reference/contact-books/get-contact-book.mdx (1)
1-3: LGTM! Verification confirms consistency across OpenAPI spec, MDX docs, and route implementations.All five contact-books operations are properly defined and consistently implemented:
- GET /v1/contact-books (list)
- POST /v1/contact-books (create)
- GET /v1/contact-books/{id} (the reviewed file - get single)
- PATCH /v1/contact-books/{id} (update)
- DELETE /v1/contact-books/{id} (delete)
The MDX file correctly references the operation, and all routes are properly registered in the public API.
apps/web/src/server/public-api/index.ts (2)
24-28: LGTM!The contact book endpoint imports follow the established pattern and are correctly structured.
55-60: LGTM!The contact book API registration follows the existing pattern and is properly organized with a descriptive comment header.
apps/docs/docs.json (1)
68-76: LGTM!The new Contact Books API documentation group is well-structured and consistent with existing API reference groups.
apps/web/src/server/public-api/api/contact-books/get-contact-books.ts (1)
1-37: LGTM!The implementation is clean and follows best practices. The properties sanitization ensures type safety for the API response.
apps/web/src/lib/zod/contact-book-schema.ts (1)
1-23: LGTM! Well-structured schema with comprehensive OpenAPI metadata.The ContactBookSchema is properly defined with clear descriptions and examples for all fields. The optional
_countfield appropriately handles cases where contact counts may not be included in the response.apps/web/src/server/public-api/api/contact-books/delete-contact-book.ts (1)
62-76: Check-then-delete pattern is acceptable but slightly redundant.The preliminary existence check (lines 62-74) provides a clear NOT_FOUND error before calling the delete service. While the delete operation itself would fail if the record doesn't exist, the explicit check enables a more specific error message and consistent error handling across endpoints.
This pattern is acceptable for API endpoints, though technically the check could be omitted if the service layer returned a more specific error.
apps/docs/api-reference/openapi.json (1)
1698-2036: LGTM! Comprehensive and well-structured OpenAPI definitions for Contact Books API.The new endpoints provide complete CRUD operations with:
- Consistent schema definitions across all operations
- Proper error responses (403 Forbidden, 404 Not Found)
- Appropriate inclusion of
_countmetadata in GET responses- Clear descriptions and examples
- Correct required field annotations
The OpenAPI spec aligns well with the implementation and provides clear documentation for API consumers.
apps/web/src/server/public-api/api/contact-books/get-contact-book.ts (1)
54-83: The type cast is necessary but reveals a runtime safety concern.The
propertiesfield is defined asJsonin the Prisma schema, which Prisma resolves to an untyped value. The explicit cast toRecord<string, string>is required for TypeScript compilation. However, this cast assumes the stored JSON matches the expected structure without runtime validation. Consider either:
- Adding runtime validation to ensure the JSON structure matches
Record<string, string>, or- Documenting the assumption that
propertiesmust conform to this shape
apps/web/src/server/public-api/api/contact-books/create-contact-book.ts
Outdated
Show resolved
Hide resolved
apps/web/src/server/public-api/api/contact-books/update-contact-book.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 issues found across 3 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="apps/web/src/server/public-api/api/contact-books/delete-contact-book.ts">
<violation number="1" location="apps/web/src/server/public-api/api/contact-books/delete-contact-book.ts:61">
P0: Parameter name mismatch: `getContactBook` expects a path param named `contactBookId`, but this route uses `id`. This will cause all delete requests to fail with "contactBookId is mandatory" error. Either change the route param to `contactBookId` or pass the `contactBookId` explicitly to a modified utility function.</violation>
</file>
<file name="apps/web/src/server/public-api/api/contact-books/update-contact-book.ts">
<violation number="1" location="apps/web/src/server/public-api/api/contact-books/update-contact-book.ts:72">
P1: The `getContactBook` utility expects a route param named `contactBookId`, but this route uses `{id}`. This will always fail with "contactBookId is mandatory". Either rename the route param to `{contactBookId}` or revert to the original inline check that uses `c.req.valid("param").id`.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| const team = c.var.team; | ||
| const contactBookId = c.req.valid("param").id; | ||
|
|
||
| await getContactBook(c, team.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P0: Parameter name mismatch: getContactBook expects a path param named contactBookId, but this route uses id. This will cause all delete requests to fail with "contactBookId is mandatory" error. Either change the route param to contactBookId or pass the contactBookId explicitly to a modified utility function.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/server/public-api/api/contact-books/delete-contact-book.ts, line 61:
<comment>Parameter name mismatch: `getContactBook` expects a path param named `contactBookId`, but this route uses `id`. This will cause all delete requests to fail with "contactBookId is mandatory" error. Either change the route param to `contactBookId` or pass the `contactBookId` explicitly to a modified utility function.</comment>
<file context>
@@ -59,19 +58,7 @@ function deleteContactBook(app: PublicAPIApp) {
- message: "Contact book not found",
- });
- }
+ await getContactBook(c, team.id);
const deletedContactBook = await deleteContactBookService(contactBookId);
</file context>
✅ Addressed in 3a5a8df
| const contactBookId = c.req.valid("param").id; | ||
| const body = c.req.valid("json"); | ||
|
|
||
| await getContactBook(c, team.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: The getContactBook utility expects a route param named contactBookId, but this route uses {id}. This will always fail with "contactBookId is mandatory". Either rename the route param to {contactBookId} or revert to the original inline check that uses c.req.valid("param").id.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/server/public-api/api/contact-books/update-contact-book.ts, line 72:
<comment>The `getContactBook` utility expects a route param named `contactBookId`, but this route uses `{id}`. This will always fail with "contactBookId is mandatory". Either rename the route param to `{contactBookId}` or revert to the original inline check that uses `c.req.valid("param").id`.</comment>
<file context>
@@ -70,19 +69,7 @@ function updateContactBook(app: PublicAPIApp) {
- message: "Contact book not found",
- });
- }
+ await getContactBook(c, team.id);
const updated = await updateContactBookService(contactBookId, body);
</file context>
✅ Addressed in 3a5a8df
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 18 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="apps/web/src/server/public-api/api/contacts/update-contact-book.ts">
<violation number="1" location="apps/web/src/server/public-api/api/contacts/update-contact-book.ts:74">
P2: Remove debug `console.log` statement before merging. This appears to be leftover debugging code that shouldn't be in a production API endpoint.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
|
|
||
| await getContactBook(c, team.id); | ||
|
|
||
| console.log({ contactBookId }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Remove debug console.log statement before merging. This appears to be leftover debugging code that shouldn't be in a production API endpoint.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/server/public-api/api/contacts/update-contact-book.ts, line 74:
<comment>Remove debug `console.log` statement before merging. This appears to be leftover debugging code that shouldn't be in a production API endpoint.</comment>
<file context>
@@ -66,11 +66,13 @@ const route = createRoute({
await getContactBook(c, team.id);
+ console.log({ contactBookId });
+
const updated = await updateContactBookService(contactBookId, body);
</file context>
✅ Addressed in b3306e9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
apps/web/src/server/public-api/api/contacts/update-contact-book.ts (1)
72-72: Past review comment appears resolved.The previous comment raised concerns about a parameter name mismatch, but the current code correctly uses
{contactBookId}throughout (route path on line 9, param schema on line 12, and param extraction on line 69), which matches thegetContactBookutility's expectations.apps/web/src/server/public-api/api/contacts/get-contact-book.ts (1)
30-40: Remove 403 response from OpenAPI spec or implement authorization check.The 403 response is documented but never returned by the implementation. The query on lines 59-63 filters by both
idandteamIdsimultaneously, so both "resource doesn't exist" and "resource exists but belongs to another team" scenarios return 404.Returning 404 in both cases is actually a security best practice (prevents information disclosure about resource existence). However, the OpenAPI specification should accurately reflect the implementation.
🔎 Recommended fix: Remove the 403 response definition
}, - 403: { - content: { - "application/json": { - schema: z.object({ - error: z.string(), - }), - }, - }, - description: - "Forbidden - API key doesn't have access to this contact book", - },
🧹 Nitpick comments (3)
apps/web/src/server/public-api/api/contacts/delete-contact-book.ts (1)
56-71: Consider using the return value fromgetContactBookto avoid redundant parameter extraction.Line 59 extracts
contactBookIdfrom the validated params, then line 61 callsgetContactBookwhich internally extracts the same parameter again viac.req.param("contactBookId"). The returned contact book is discarded, andcontactBookIdis re-used on line 63.🔎 Proposed refactor to eliminate redundancy
function deleteContactBook(app: PublicAPIApp) { app.openapi(route, async (c) => { const team = c.var.team; - const contactBookId = c.req.valid("param").contactBookId; - await getContactBook(c, team.id); + const contactBook = await getContactBook(c, team.id); - const deletedContactBook = await deleteContactBookService(contactBookId); + const deletedContactBook = await deleteContactBookService(contactBook.id); return c.json({ id: deletedContactBook.id,apps/web/src/server/public-api/api/contacts/get-contact-books.ts (1)
6-19: Consider exposing search query parameter.The underlying service function
getContactBooksServicesupports an optionalsearchparameter for filtering contact books by name (see apps/web/src/server/service/contact-book-service.ts lines 5-17), but the route definition doesn't expose this capability. Consider adding a query parameter to enable search functionality.🔎 Proposed enhancement to add search support
const route = createRoute({ method: "get", path: "/v1/contactBooks", + request: { + query: z.object({ + search: z.string().optional().openapi({ + description: "Search contact books by name", + example: "Newsletter" + }), + }), + }, responses: {Then update the handler:
function getContactBooks(app: PublicAPIApp) { app.openapi(route, async (c) => { const team = c.var.team; + const { search } = c.req.valid("query"); - const contactBooks = await getContactBooksService(team.id); + const contactBooks = await getContactBooksService(team.id, search);apps/web/src/server/public-api/api/contacts/create-contact-book.ts (1)
38-63: Consider refactoring to reduce database calls.The current implementation creates the contact book (line 43), then conditionally updates it with emoji/properties (lines 46-50), resulting in two database operations when emoji or properties are provided.
While this works correctly, it could be optimized by enhancing
createContactBookServiceto accept optionalemojiandpropertiesparameters, allowing everything to be created in a single database operation.💡 Suggested refactor (requires service function update)
Update the service function signature at apps/web/src/server/service/contact-book-service.ts:
export async function createContactBook( teamId: number, name: string, emoji?: string, properties?: Record<string, string> )Then simplify the handler:
function createContactBook(app: PublicAPIApp) { app.openapi(route, async (c) => { const team = c.var.team; const body = c.req.valid("json"); - const contactBook = await createContactBookService(team.id, body.name); - - // Update emoji and properties if provided - if (body.emoji || body.properties) { - const updated = await updateContactBook(contactBook.id, { - emoji: body.emoji, - properties: body.properties, - }); - - return c.json({ - ...updated, - properties: updated.properties as Record<string, string>, - }); - } + const contactBook = await createContactBookService( + team.id, + body.name, + body.emoji, + body.properties + ); return c.json({ ...contactBook,
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
apps/docs/api-reference/contacts/create-contact-book.mdxapps/docs/api-reference/contacts/delete-contact-book.mdxapps/docs/api-reference/contacts/get-contact-book.mdxapps/docs/api-reference/contacts/list-contact-books.mdxapps/docs/api-reference/contacts/update-contact-book.mdxapps/docs/api-reference/openapi.jsonapps/docs/docs.jsonapps/web/src/server/public-api/api/contacts/create-contact-book.tsapps/web/src/server/public-api/api/contacts/delete-contact-book.tsapps/web/src/server/public-api/api/contacts/get-contact-book.tsapps/web/src/server/public-api/api/contacts/get-contact-books.tsapps/web/src/server/public-api/api/contacts/update-contact-book.tsapps/web/src/server/public-api/index.ts
✅ Files skipped from review due to trivial changes (3)
- apps/docs/api-reference/contacts/delete-contact-book.mdx
- apps/docs/api-reference/contacts/update-contact-book.mdx
- apps/docs/api-reference/contacts/list-contact-books.mdx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
Include all required imports and ensure proper naming of key components in React/NextJS code
Files:
apps/web/src/server/public-api/api/contacts/get-contact-books.tsapps/web/src/server/public-api/api/contacts/delete-contact-book.tsapps/web/src/server/public-api/api/contacts/get-contact-book.tsapps/web/src/server/public-api/api/contacts/create-contact-book.tsapps/web/src/server/public-api/index.tsapps/web/src/server/public-api/api/contacts/update-contact-book.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Use TypeScript-first approach with 2-space indent and semicolons enabled by Prettier in apps/web (Next.js), apps/marketing, apps/smtp-server, and all packages
Never use dynamic imports; always import on the top level
Run ESLint via @usesend/eslint-config and ensure no warnings remain before submitting PRs
Files:
apps/web/src/server/public-api/api/contacts/get-contact-books.tsapps/web/src/server/public-api/api/contacts/delete-contact-book.tsapps/web/src/server/public-api/api/contacts/get-contact-book.tsapps/web/src/server/public-api/api/contacts/create-contact-book.tsapps/web/src/server/public-api/index.tsapps/web/src/server/public-api/api/contacts/update-contact-book.ts
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use alias
~/for src imports in apps/web (e.g.,import { x } from "~/utils/x")
Files:
apps/web/src/server/public-api/api/contacts/get-contact-books.tsapps/web/src/server/public-api/api/contacts/delete-contact-book.tsapps/web/src/server/public-api/api/contacts/get-contact-book.tsapps/web/src/server/public-api/api/contacts/create-contact-book.tsapps/web/src/server/public-api/index.tsapps/web/src/server/public-api/api/contacts/update-contact-book.ts
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/**/*.{ts,tsx}: Prefer to use TRPC for client-server communication unless explicitly asked otherwise in apps/web
Use Prisma for database access in apps/web
Files:
apps/web/src/server/public-api/api/contacts/get-contact-books.tsapps/web/src/server/public-api/api/contacts/delete-contact-book.tsapps/web/src/server/public-api/api/contacts/get-contact-book.tsapps/web/src/server/public-api/api/contacts/create-contact-book.tsapps/web/src/server/public-api/index.tsapps/web/src/server/public-api/api/contacts/update-contact-book.ts
**/*.{ts,tsx,md}
📄 CodeRabbit inference engine (AGENTS.md)
Run Prettier 3 for code formatting on TypeScript, TSX, and Markdown files
Files:
apps/web/src/server/public-api/api/contacts/get-contact-books.tsapps/web/src/server/public-api/api/contacts/delete-contact-book.tsapps/web/src/server/public-api/api/contacts/get-contact-book.tsapps/web/src/server/public-api/api/contacts/create-contact-book.tsapps/web/src/server/public-api/index.tsapps/web/src/server/public-api/api/contacts/update-contact-book.ts
🧠 Learnings (1)
📚 Learning: 2025-11-28T21:14:07.734Z
Learnt from: CR
Repo: usesend/useSend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T21:14:07.734Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Never use dynamic imports; always import on the top level
Applied to files:
apps/web/src/server/public-api/api/contacts/create-contact-book.ts
🧬 Code graph analysis (5)
apps/web/src/server/public-api/api/contacts/get-contact-books.ts (4)
apps/web/src/lib/zod/contact-book-schema.ts (1)
ContactBookSchema(3-23)apps/web/src/server/service/contact-book-service.ts (1)
getContactBooks(6-18)apps/web/src/server/public-api/index.ts (1)
app(30-30)apps/web/src/server/public-api/hono.ts (1)
PublicAPIApp(136-136)
apps/web/src/server/public-api/api/contacts/get-contact-book.ts (6)
apps/web/src/lib/zod/contact-book-schema.ts (1)
ContactBookSchema(3-23)apps/web/src/server/public-api/api-utils.ts (1)
getContactBook(5-27)apps/web/src/server/public-api/index.ts (1)
app(30-30)apps/web/src/server/public-api/hono.ts (1)
PublicAPIApp(136-136)apps/web/src/server/db.ts (1)
db(20-20)apps/web/src/server/public-api/api-error.ts (1)
UnsendApiError(62-75)
apps/web/src/server/public-api/api/contacts/create-contact-book.ts (3)
apps/web/src/lib/zod/contact-book-schema.ts (1)
ContactBookSchema(3-23)apps/web/src/server/service/contact-book-service.ts (2)
createContactBook(20-40)updateContactBook(69-81)apps/web/src/server/public-api/hono.ts (1)
PublicAPIApp(136-136)
apps/web/src/server/public-api/index.ts (2)
apps/web/src/server/service/contact-book-service.ts (4)
getContactBooks(6-18)createContactBook(20-40)updateContactBook(69-81)deleteContactBook(83-87)apps/web/src/server/public-api/api-utils.ts (1)
getContactBook(5-27)
apps/web/src/server/public-api/api/contacts/update-contact-book.ts (5)
apps/web/src/lib/zod/contact-book-schema.ts (1)
ContactBookSchema(3-23)apps/web/src/server/service/contact-book-service.ts (1)
updateContactBook(69-81)apps/web/src/server/public-api/index.ts (1)
app(30-30)apps/web/src/server/public-api/hono.ts (1)
PublicAPIApp(136-136)apps/web/src/server/public-api/api-utils.ts (1)
getContactBook(5-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: cubic · AI code reviewer
🔇 Additional comments (11)
apps/docs/api-reference/contacts/create-contact-book.mdx (1)
1-3: LGTM!The MDX front matter correctly references the OpenAPI operation. Note: the path convention (
/v1/contactBooks) has been flagged for verification in the main implementation file.apps/docs/api-reference/contacts/get-contact-book.mdx (1)
1-3: LGTM!The MDX front matter correctly references the GET operation for a single contact book. Path convention has been flagged for verification in the implementation file.
apps/web/src/server/public-api/index.ts (2)
24-28: LGTM!The imports for the five Contact Book endpoints follow the established pattern and are correctly organized.
55-60: LGTM!The Contact Book API registration follows the established pattern of other API groups. The endpoints are registered in a logical order (list, create, get, update, delete) and the section comment is consistent with other sections.
apps/docs/docs.json (1)
68-76: LGTM!The new "Contact Books" group is well-positioned in the navigation structure and includes all five CRUD operations in a logical order. The naming and structure are consistent with other API Reference groups.
apps/web/src/server/public-api/api/contacts/update-contact-book.ts (1)
7-19: Verify API path naming convention with PR description.The PR description states the endpoint should be
PATCH /v1/contact-books/{id}, but the implementation usesPATCH /v1/contactBooks/{contactBookId}.While the current implementation is consistent with all other contact book endpoints (
get-contact-book,delete-contact-book,create-contact-book), there's an inconsistency across the API: domains and emails endpoints use kebab-case paths (/v1/domains,/v1/emails), while all contact endpoints use camelCase (/v1/contactBooks).Clarify which convention is correct:
- If
/v1/contact-books/{id}is the intended design, update this route and all other contact endpoints to kebab-case- If
/v1/contactBooks/{contactBookId}is correct, update the PR descriptionapps/web/src/server/public-api/api/contacts/delete-contact-book.ts (2)
6-54: LGTM!The route definition is well-structured with proper OpenAPI metadata and response schemas for all expected status codes.
61-61: Past review comment is no longer valid.The previous concern about parameter name mismatch between the route and
getContactBookutility has been resolved. The route correctly usescontactBookIdas the path parameter (line 8), which matches what thegetContactBookutility expects when extracting viac.req.param("contactBookId").apps/web/src/server/public-api/api/contacts/get-contact-books.ts (1)
21-35: LGTM!The handler correctly fetches contact books scoped to the team and sanitizes the
propertiesfield for type compatibility between Prisma'sJsonValueand the schema'sRecord<string, string>.apps/web/src/server/public-api/api/contacts/get-contact-book.ts (1)
78-81: LGTM!The response correctly casts the
propertiesfield for type compatibility with the ContactBookSchema.apps/web/src/server/public-api/api/contacts/create-contact-book.ts (1)
1-36: LGTM! Dynamic import issue resolved.All imports are now at the top level, complying with the coding guideline: "Never use dynamic imports; always import on the top level". The route definition is properly structured with appropriate request/response schemas.
As per coding guidelines.
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
Outdated
Show resolved
Hide resolved
…ontact-book.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
Include all required imports and ensure proper naming of key components in React/NextJS code
Files:
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Use TypeScript-first approach with 2-space indent and semicolons enabled by Prettier in apps/web (Next.js), apps/marketing, apps/smtp-server, and all packages
Never use dynamic imports; always import on the top level
Run ESLint via @usesend/eslint-config and ensure no warnings remain before submitting PRs
Files:
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use alias
~/for src imports in apps/web (e.g.,import { x } from "~/utils/x")
Files:
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/**/*.{ts,tsx}: Prefer to use TRPC for client-server communication unless explicitly asked otherwise in apps/web
Use Prisma for database access in apps/web
Files:
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
**/*.{ts,tsx,md}
📄 CodeRabbit inference engine (AGENTS.md)
Run Prettier 3 for code formatting on TypeScript, TSX, and Markdown files
Files:
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
🧬 Code graph analysis (1)
apps/web/src/server/public-api/api/contacts/update-contact-book.ts (5)
apps/web/src/lib/zod/contact-book-schema.ts (1)
ContactBookSchema(3-23)apps/web/src/server/service/contact-book-service.ts (1)
updateContactBook(69-81)apps/web/src/server/public-api/index.ts (1)
app(30-30)apps/web/src/server/public-api/hono.ts (1)
PublicAPIApp(136-136)apps/web/src/server/public-api/api-utils.ts (1)
getContactBook(5-27)
🪛 Biome (2.1.2)
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
[error] 76-76: Shouldn't redeclare 'updated'. Consider to delete it or rename it.
'updated' is defined here:
(lint/suspicious/noRedeclare)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: cubic · AI code reviewer
🔇 Additional comments (2)
apps/web/src/server/public-api/api/contacts/update-contact-book.ts (2)
1-64: Route definition looks well-structured.The imports follow coding guidelines using the
~/alias, and the OpenAPI route definition properly validates params, request body, and defines comprehensive response schemas for success and error cases.
78-85: Response transformation and export are correct.The handler properly transforms the updated contact book with properties coerced to
Record<string, string>to match the schema, and the default export follows the expected pattern for route registration.
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
Outdated
Show resolved
Hide resolved
…t-book.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
Include all required imports and ensure proper naming of key components in React/NextJS code
Files:
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Use TypeScript-first approach with 2-space indent and semicolons enabled by Prettier in apps/web (Next.js), apps/marketing, apps/smtp-server, and all packages
Never use dynamic imports; always import on the top level
Run ESLint via @usesend/eslint-config and ensure no warnings remain before submitting PRs
Files:
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use alias
~/for src imports in apps/web (e.g.,import { x } from "~/utils/x")
Files:
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/**/*.{ts,tsx}: Prefer to use TRPC for client-server communication unless explicitly asked otherwise in apps/web
Use Prisma for database access in apps/web
Files:
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
**/*.{ts,tsx,md}
📄 CodeRabbit inference engine (AGENTS.md)
Run Prettier 3 for code formatting on TypeScript, TSX, and Markdown files
Files:
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
🧬 Code graph analysis (1)
apps/web/src/server/public-api/api/contacts/update-contact-book.ts (4)
apps/web/src/lib/zod/contact-book-schema.ts (1)
ContactBookSchema(3-23)apps/web/src/server/service/contact-book-service.ts (1)
updateContactBook(69-81)apps/web/src/server/public-api/hono.ts (1)
PublicAPIApp(136-136)apps/web/src/server/public-api/api-utils.ts (1)
getContactBook(5-27)
🪛 Biome (2.1.2)
apps/web/src/server/public-api/api/contacts/update-contact-book.ts
[error] 78-78: expected : but instead found c
Remove c
(parse)
[error] 81-81: expected , but instead found ;
Remove ;
(parse)
Summary by cubic
Adds a public Contact Books API with full CRUD so external clients can list, create, read, update, and delete contact books. Updates the OpenAPI spec and docs to expose these endpoints.
Written for commit 6f524ab. Summary will update on new commits.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.