-
Notifications
You must be signed in to change notification settings - Fork 1
up #21
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
Conversation
Warning Rate limit exceeded@kodermax has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 13 minutes and 17 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 (12)
📝 WalkthroughWalkthroughВ create-order вычисляется orderUrl из env.SITE_URL и передаётся в OrderCreatedEmail; в payload orderItems добавлено поле price. Добавлен пакет Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API as Web API (create-order)
participant Config as @qco/config
participant Emails as @qco/emails
participant User
Client->>API: POST /orders
API->>API: Создать заказ, собрать orderItems (включая price)
API->>Config: Чтение env.SITE_URL
API->>API: orderUrl = env.SITE_URL ? `${env.SITE_URL}/checkout/success?orderId=${order.id}` : undefined
API->>Emails: OrderCreatedEmail({ order, orderItems, orderUrl })
Emails-->>User: Отправка письма (включает per-item price и ссылку если есть)
API-->>Client: 200 OK (данные заказа)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~15 minutes Possibly related PRs
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
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: 2
🔭 Outside diff range comments (2)
packages/web-api/src/router/orders/create-order.ts (2)
105-108
: Ошибки при отправке email проглатываются — добавьте хотя бы логированиеПолное игнорирование исключений осложнит поддержку и диагностику инцидентов. Предлагаю залогировать предупреждение с ключевым контекстом (замените на ваш логгер при наличии).
} catch (emailError) { - - // Не прерываем выполнение процедуры, если email не удалось отправить + // Не прерываем выполнение процедуры, если email не удалось отправить, + // но логируем для диагностики (замените console.warn на ваш логгер). + console.warn("Failed to send OrderCreatedEmail", { + orderId: order.id, + to: customerInfo.email, + error: emailError, + }); }
70-70
: as any убирает типобезопасностьВ этой точке теряется гарантия типов на элементы корзины. Лучше описать явный DTO для items или расширить возвращаемые типы createOrder, чтобы привести мэппинг к строгой типизации без any.
Готов помочь выделить общий тип для CartItemDTO и убрать приведение к any по всей цепочке.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/web-api/src/router/orders/create-order.ts
(3 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
**/*.{ts,tsx}
: Use strict typing in TypeScript and avoidany
.
Use environment variables or@t3-oss/env-core
for experimental feature flags.
Files:
packages/web-api/src/router/orders/create-order.ts
{packages/web-api/**,packages/api/**,packages/web-validators/**,packages/validators/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
Use the same Zod schemas on both frontend and backend. Import schemas from
/packages/web-validators
(for web) and/packages/validators
(for app) to guarantee unified validation and type safety.
Files:
packages/web-api/src/router/orders/create-order.ts
{packages/web-api/**,packages/api/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
The server must prepare and return clear, frontend-ready data structures. All necessary transformations and formatting should be performed on the server, so that the frontend receives data in the exact shape it needs.
Files:
packages/web-api/src/router/orders/create-order.ts
{packages/web-api/**,packages/api/**,packages/lib/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
Keep business logic decoupled in
/packages/web-api
,/packages/api
, or/packages/lib
.
Files:
packages/web-api/src/router/orders/create-order.ts
**/*.ts
📄 CodeRabbit Inference Engine (.windsurfrules)
Use Zod for validation.
Files:
packages/web-api/src/router/orders/create-order.ts
⚙️ CodeRabbit Configuration File
**/*.ts
: ОСНОВНЫЕ ПРИНЦИПЫ РАЗРАБОТКИ:
Именование и стиль кода:
- Имена файлов обязательно в kebab-case (например: my-component.ts, user-profile.tsx)
- Функции в camelCase, компоненты в PascalCase, константы в UPPER_SNAKE_CASE
- Имена переменных и функций должны четко отражать их назначение и реализацию
- Избегайте сокращений и аббревиатур в именах (кроме общепринятых)
- Поддерживайте консистентность в стиле кода (отступы, пробелы, переносы строк)
- Следуйте принципам чистого кода (DRY, SOLID, KISS)
- Используйте осмысленные имена для булевых переменных (isLoading, hasPermission, canEdit)
TypeScript и типизация:
- Используйте строгую типизацию и избегайте any, unknown и {} где это возможно
- Правильно применяйте дженерики, интерфейсы и типы
- Обеспечивайте корректные определения типов для параметров функций и возвращаемых значений
- Предпочитайте union и intersection типы сложным условным конструкциям
- Используйте утилитарные типы TypeScript (Pick, Omit, Partial, Required)
- Создавайте переиспользуемые типы и интерфейсы
- Избегайте дублирования типов, выносите общие типы в отдельные файлы
Соблюдение правил линтера:
- Следуйте правилам ESLint для React и TypeScript
- Соблюдайте рекомендации Biome по форматированию и анализу кода
- Убедитесь, что код не содержит предупреждений или ошибок линтера
- Используйте автоматическое форматирование кода
Алгоритмы и производительность:
- Пишите понятные и читаемые алгоритмы, которые могут понять другие разработчики
- Оптимизируйте сложность алгоритмов (временную и пространственную)
- Избегайте чрезмерной вложенности и сложности
- Правильно обрабатывайте граничные случаи и ошибки
- Используйте подходящие структуры данных для задач
- Применяйте мемоизацию где это уместно
Безопасность и стабильность:
- Реализуйте правильную валидацию входных данных и защиту от инъекций
- Корректно обрабатывайте ошибки и исключения
- Обеспечивайте...
Files:
packages/web-api/src/router/orders/create-order.ts
🔇 Additional comments (1)
packages/web-api/src/router/orders/create-order.ts (1)
90-101
: Проверка orderUrl: опциональный проп с дефолтомВ
OrderCreatedEmailProps
полеorderUrl
объявлено как опциональное (orderUrl?: string
), а в компоненте задаётся значение по умолчанию (orderUrl = defaultOrderUrl
). ПередачаorderUrl
всегда безопасна, дополнительных правок не требуется.
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: 6
🔭 Outside diff range comments (3)
packages/emails/emails/orders/order-created.tsx (2)
15-19
: Возможная некорректная ссылка при отсутствующем SITE_URL: получится "undefined/orders"Если
env.SITE_URL
не задан,defaultOrderUrl
станет строкой"undefined/orders"
и попадёт в письмо как битая ссылка. Нормализуйте базовый URL и избегайте генерации ссылки в этом случае.Предлагаю правку:
-import { env } from "@qco/config"; +import { env } from "@qco/config"; @@ -const defaultOrderUrl = `${env.SITE_URL}/orders`; +const defaultOrderUrl = + env.SITE_URL && env.SITE_URL.trim().length > 0 + ? `${env.SITE_URL.replace(/\/+$/, "")}/orders` + : undefined;
151-158
: Кнопка с ссылкой рендерится без проверки наличия orderUrlПри пустом
SITE_URL
из конфига (или не переданномorderUrl
) кнопка будет вести наundefined/orders
. Рендерите кнопку только при валидной ссылке.Примените условный рендер:
- <Section className="mb-[32px] mt-[32px] text-center"> - <Button - className="rounded bg-[#000000] px-6 py-3 text-center text-[14px] font-semibold text-white no-underline hover:bg-gray-800" - href={orderUrl} - > - Посмотреть детали заказа - </Button> - </Section> + {orderUrl && ( + <Section className="mb-[32px] mt-[32px] text-center"> + <Button + className="rounded bg-[#000000] px-6 py-3 text-center text-[14px] font-semibold text-white no-underline hover:bg-gray-800" + href={orderUrl} + > + Посмотреть детали заказа + </Button> + </Section> + )}packages/emails/send.ts (1)
60-76
: Унифицировать отправку письма через клиента Resend в sendEmailHtml
- Файл: packages/emails/send.ts (функция sendEmailHtml, строки 60–76)
sendEmailHtml сейчас делает прямой fetch с заголовкомBearer ${env.RESEND_API_KEY}
, даже если ключ не задан. Предлагаю заменить на использование уже созданного клиентаresend
и добавить ранний выход при отсутствии ключа (как в sendEmail).Было:
export const sendEmailHtml = async (email: EmailHtml) => { const from = email.from || env.EMAIL_FROM || DEFAULT_FROM_EMAIL; await fetch("https://api.resend.com/emails", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${env.RESEND_API_KEY}`, }, body: JSON.stringify({ to: email.to, from, subject: email.subject, html: email.html, }), }); };Стало:
export const sendEmailHtml = async (email: EmailHtml) => { const from = email.from || env.EMAIL_FROM || DEFAULT_FROM_EMAIL; - await fetch("https://api.resend.com/emails", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${env.RESEND_API_KEY}`, - }, - body: JSON.stringify({ - to: email.to, - from, - subject: email.subject, - html: email.html, - }), - }); + if (!resend) { + return Promise.resolve(); + } + return resend.emails.send({ + to: email.to, + from, + subject: email.subject, + html: email.html, + }); };Так мы:
- Избежим
Bearer undefined
при отсутствии ключа.- Используем единый механизм отправки через клиент Resend.
♻️ Duplicate comments (3)
packages/emails/emails/auth/email-change-verification.tsx (1)
15-15
: Импорт env из @qco/config — корректноХорошая консолидация конфигурации. Смотри также комментарий в email-verification.tsx о проверке зависимости и экспортов пакета, чтобы не дублировать здесь.
packages/web-api/src/router/orders/create-order.ts (2)
7-7
: Импорт env из @qco/config — архитектурно верноРазвязывает слой web-api от @qco/emails и устраняет риск циклических зависимостей. Хорошее изменение.
81-83
: Собирайте orderUrl через URL API и кодируйте orderId; избегайте двойных слэшейТекущая конкатенация даёт // при SITE_URL со слэшем на конце и не кодирует orderId. Используйте URL API.
Примените дифф:
- const orderUrl = env.SITE_URL - ? `${env.SITE_URL}/checkout/success?orderId=${order.id}` - : undefined; + const orderUrl = env.SITE_URL + ? (() => { + const u = new URL("/checkout/success", env.SITE_URL); + u.searchParams.set("orderId", String(order.id)); + return u.toString(); + })() + : undefined;
🧹 Nitpick comments (6)
packages/emails/emails/welcome.tsx (1)
17-17
: Несоответствие нейминга: username используется как имя и как emailВ тексте письма username выводится как имя ("Здравствуйте, {username}!"), но далее — как адрес email ("письмо отправлено на адрес {username}"). Разделите пропсы на username и email либо скорректируйте текст.
Пример:
export default function WelcomeEmail( { username = "username", email }: { username: string; email: string } ) { ... <Text className="text-[12px] leading-[24px] text-[#666666]"> Это письмо отправлено на адрес <span className="text-black">{email}</span>. </Text> }packages/emails/emails/auth/verification-otp.tsx (2)
15-15
: Задайте явный тип возврата getVerificationInfo и обеспечьте исчерпывающую проверкуЭто улучшит типобезопасность при расширении union-типа и исключит silent-undefined в будущем.
Пример:
type VerificationInfo = { title: string; preview: string; description: string; validity: string; }; const getVerificationInfo = (type: VerificationType): VerificationInfo => { switch (type) { case "sign-in": return { ... }; case "email-verification": return { ... }; case "forget-password": return { ... }; default: { // исчерпывающая проверка на уровне типов const _exhaustive: never = type; throw new Error(`Unknown verification type: ${_exhaustive}`); } } };
15-15
: Нитпик: литерал "forget-password"Если это не связано с публичным API, рассмотрите "forgot-password" для естественного английского. В противном случае оставьте как есть для обратной совместимости.
packages/emails/emails/orders/order-created.tsx (1)
104-113
: Незначительно: ключи элементов спискаИспользование индекса в качестве ключа допустимо для статических списков, но при равных именах товаров и возможных изменениях порядка лучше использовать стабильный ключ (например, сочетание
name + quantity
), чтобы избежать потенциальных артефактов рендеринга.- {items?.map((item, index) => ( - <div key={index} className="mb-[12px] pb-[12px] border-b border-gray-200 last:border-b-0"> + {items?.map((item) => ( + <div key={`${item.name}-${item.quantity}`} className="mb-[12px] pb-[12px] border-b border-gray-200 last:border-b-0">packages/emails/emails/auth/password-reset.tsx (1)
19-26
: Небольшая несогласованность нейминга: username используется как адрес emailВ тексте: приветствие как имени пользователя и далее «Это письмо отправлено на адрес {username}». Если здесь подразумевается адрес, рассмотрите переименование пропа в
-export default function PasswordResetEmail({ - username = "username", - resetLink, -}: { - username: string; - resetLink: string; -}) { +export default function PasswordResetEmail({ + username = "username", + email, + resetLink, +}: { + username: string; + email: string; + resetLink: string; +}) { @@ - Это письмо отправлено на адрес{" "} - <span className="text-black">{username}</span>. Если вы не + Это письмо отправлено на адрес{" "} + <span className="text-black">{email}</span>. Если вы неAlso applies to: 66-69
packages/config/tsup.config.ts (1)
5-11
: Зафиксируйте platform/target/outDir для стабильной сборкиНебольшой апгрейд сборки для предсказуемых артефактов и будущей совместимости.
Примените дифф:
export default defineConfig({ entry: ["src/index.ts"], format: ["esm"], dts: true, splitting: false, sourcemap: false, clean: true, minify: false, + platform: "node", + target: "node18", + outDir: "dist", external: [ "@t3-oss/env-core", "zod" ], });
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lock
is excluded by!**/*.lock
📒 Files selected for processing (21)
packages/config/package.json
(1 hunks)packages/config/src/env.ts
(1 hunks)packages/config/src/index.ts
(1 hunks)packages/config/tsconfig.json
(1 hunks)packages/config/tsup.config.ts
(1 hunks)packages/emails/emails/admin-invitation.tsx
(1 hunks)packages/emails/emails/auth/email-change-verification.tsx
(1 hunks)packages/emails/emails/auth/email-verification.tsx
(1 hunks)packages/emails/emails/auth/otp-sign-in.tsx
(1 hunks)packages/emails/emails/auth/password-reset.tsx
(1 hunks)packages/emails/emails/auth/verification-otp.tsx
(1 hunks)packages/emails/emails/orders/order-created.tsx
(1 hunks)packages/emails/emails/orders/order-status-updated.tsx
(1 hunks)packages/emails/emails/orders/order-updated.tsx
(1 hunks)packages/emails/emails/welcome.tsx
(1 hunks)packages/emails/env.ts
(0 hunks)packages/emails/index.ts
(1 hunks)packages/emails/package.json
(1 hunks)packages/emails/send.ts
(1 hunks)packages/emails/tsup.config.ts
(1 hunks)packages/web-api/src/router/orders/create-order.ts
(3 hunks)
💤 Files with no reviewable changes (1)
- packages/emails/env.ts
✅ Files skipped from review due to trivial changes (1)
- packages/emails/emails/orders/order-updated.tsx
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
**/*.{ts,tsx}
: Use strict typing in TypeScript and avoidany
.
Use environment variables or@t3-oss/env-core
for experimental feature flags.
Files:
packages/config/src/env.ts
packages/config/src/index.ts
packages/emails/emails/auth/email-change-verification.tsx
packages/emails/emails/auth/email-verification.tsx
packages/emails/emails/orders/order-created.tsx
packages/emails/tsup.config.ts
packages/emails/emails/auth/verification-otp.tsx
packages/emails/emails/orders/order-status-updated.tsx
packages/emails/index.ts
packages/emails/emails/auth/otp-sign-in.tsx
packages/emails/emails/auth/password-reset.tsx
packages/config/tsup.config.ts
packages/emails/emails/welcome.tsx
packages/emails/send.ts
packages/web-api/src/router/orders/create-order.ts
packages/emails/emails/admin-invitation.tsx
**/*.ts
📄 CodeRabbit Inference Engine (.windsurfrules)
Use Zod for validation.
Files:
packages/config/src/env.ts
packages/config/src/index.ts
packages/emails/tsup.config.ts
packages/emails/index.ts
packages/config/tsup.config.ts
packages/emails/send.ts
packages/web-api/src/router/orders/create-order.ts
⚙️ CodeRabbit Configuration File
**/*.ts
: ОСНОВНЫЕ ПРИНЦИПЫ РАЗРАБОТКИ:
Именование и стиль кода:
- Имена файлов обязательно в kebab-case (например: my-component.ts, user-profile.tsx)
- Функции в camelCase, компоненты в PascalCase, константы в UPPER_SNAKE_CASE
- Имена переменных и функций должны четко отражать их назначение и реализацию
- Избегайте сокращений и аббревиатур в именах (кроме общепринятых)
- Поддерживайте консистентность в стиле кода (отступы, пробелы, переносы строк)
- Следуйте принципам чистого кода (DRY, SOLID, KISS)
- Используйте осмысленные имена для булевых переменных (isLoading, hasPermission, canEdit)
TypeScript и типизация:
- Используйте строгую типизацию и избегайте any, unknown и {} где это возможно
- Правильно применяйте дженерики, интерфейсы и типы
- Обеспечивайте корректные определения типов для параметров функций и возвращаемых значений
- Предпочитайте union и intersection типы сложным условным конструкциям
- Используйте утилитарные типы TypeScript (Pick, Omit, Partial, Required)
- Создавайте переиспользуемые типы и интерфейсы
- Избегайте дублирования типов, выносите общие типы в отдельные файлы
Соблюдение правил линтера:
- Следуйте правилам ESLint для React и TypeScript
- Соблюдайте рекомендации Biome по форматированию и анализу кода
- Убедитесь, что код не содержит предупреждений или ошибок линтера
- Используйте автоматическое форматирование кода
Алгоритмы и производительность:
- Пишите понятные и читаемые алгоритмы, которые могут понять другие разработчики
- Оптимизируйте сложность алгоритмов (временную и пространственную)
- Избегайте чрезмерной вложенности и сложности
- Правильно обрабатывайте граничные случаи и ошибки
- Используйте подходящие структуры данных для задач
- Применяйте мемоизацию где это уместно
Безопасность и стабильность:
- Реализуйте правильную валидацию входных данных и защиту от инъекций
- Корректно обрабатывайте ошибки и исключения
- Обеспечивайте...
Files:
packages/config/src/env.ts
packages/config/src/index.ts
packages/emails/tsup.config.ts
packages/emails/index.ts
packages/config/tsup.config.ts
packages/emails/send.ts
packages/web-api/src/router/orders/create-order.ts
**/*.json
⚙️ CodeRabbit Configuration File
**/*.json
: РАБОТА С JSON ФАЙЛАМИ:
Структура и форматирование:
- Используйте правильное форматирование JSON
- Поддерживайте консистентную структуру
- Используйте осмысленные ключи
- Избегайте дублирования данных
Валидация:
- Убедитесь в корректности JSON синтаксиса
- Проверяйте типы данных
- Валидируйте обязательные поля
Безопасность:
- Не включайте конфиденциальные данные
- Используйте переменные окружения для секретов
- Валидируйте входящие JSON данные
Files:
packages/config/tsconfig.json
packages/config/package.json
packages/emails/package.json
**/*.{tsx,jsx}
📄 CodeRabbit Inference Engine (.cursor/rules/trpc.mdc)
**/*.{tsx,jsx}
: When using tRPC with React Query, always generate query options usingtrpc.<namespace>.<procedure>.queryOptions()
and pass them touseQuery
instead of calling the procedure directly.
When using tRPC mutations with React Query, always generate mutation options usingtrpc.<namespace>.<procedure>.mutationOptions()
and pass them touseMutation
instead of calling the procedure directly.
After a successful mutation that affects a list, invalidate the relevant query cache usingqueryClient.invalidateQueries
with the correct query key from tRPC.
Display user feedback (such as toast notifications) on mutation success or error using thetoast
function.
Files:
packages/emails/emails/auth/email-change-verification.tsx
packages/emails/emails/auth/email-verification.tsx
packages/emails/emails/orders/order-created.tsx
packages/emails/emails/auth/verification-otp.tsx
packages/emails/emails/orders/order-status-updated.tsx
packages/emails/emails/auth/otp-sign-in.tsx
packages/emails/emails/auth/password-reset.tsx
packages/emails/emails/welcome.tsx
packages/emails/emails/admin-invitation.tsx
**/*.{jsx,tsx}
📄 CodeRabbit Inference Engine (.windsurfrules)
**/*.{jsx,tsx}
: Use Lucide React for icons throughout the application.
Use TanStack Query (react-query) for frontend data fetching.
Use React Hook Form for form handling.
Use React Context for state management.
Use the useTRPC hook for accessing tRPC procedures.
Use queryClient.invalidateQueries for cache invalidation after mutations.
Files:
packages/emails/emails/auth/email-change-verification.tsx
packages/emails/emails/auth/email-verification.tsx
packages/emails/emails/orders/order-created.tsx
packages/emails/emails/auth/verification-otp.tsx
packages/emails/emails/orders/order-status-updated.tsx
packages/emails/emails/auth/otp-sign-in.tsx
packages/emails/emails/auth/password-reset.tsx
packages/emails/emails/welcome.tsx
packages/emails/emails/admin-invitation.tsx
**/*.tsx
⚙️ CodeRabbit Configuration File
**/*.tsx
: ПРИНЦИПЫ РАЗРАБОТКИ REACT КОМПОНЕНТОВ:
Именование и стиль кода:
- Имена файлов обязательно в kebab-case (например: my-component.tsx, user-profile.tsx)
- Компоненты в PascalCase, функции в camelCase, константы в UPPER_SNAKE_CASE
- Имена компонентов должны четко отражать их назначение и функциональность
- Избегайте сокращений в именах компонентов
- Поддерживайте консистентность в стиле кода
- Следуйте принципам чистого кода (DRY, SOLID, KISS)
TypeScript и типизация:
- Используйте строгую типизацию для всех пропсов компонентов
- Избегайте any, unknown и {} где это возможно
- Правильно типизируйте события и колбэки
- Используйте дженерики для переиспользуемых компонентов
- Создавайте интерфейсы для пропсов компонентов
- Типизируйте состояние компонентов
- Используйте утилитарные типы React (ComponentProps, PropsWithChildren, etc.)
React и Next.js лучшие практики:
- Оптимизируйте React компоненты (используйте мемоизацию, поддерживайте правильную структуру)
- Правильно используйте хуки (useEffect, useState, useCallback, useMemo)
- Предотвращайте утечки памяти в useEffect
- Корректно реализуйте серверные и клиентские компоненты в Next.js
- Оптимизируйте стратегии маршрутизации и загрузки данных (SSR, SSG, ISR)
- Используйте React.memo для предотвращения ненужных ре-рендеров
- Правильно управляйте зависимостями в useEffect
- Избегайте создания объектов и функций в рендере
Производительность компонентов:
- Оптимизируйте рендеринг списков с помощью виртуализации при необходимости
- Используйте lazy loading для компонентов
- Минимизируйте количество ре-рендеров
- Правильно используйте key пропы в списках
- Избегайте встроенных объектов и функций в JSX
- Используйте Code Splitting для больших компонентов
Управление состоянием:
- Поднимайте состояние только когда это необходимо
- Используйте локальное состояние где это возможно
- Правильно структурируйте сост...
Files:
packages/emails/emails/auth/email-change-verification.tsx
packages/emails/emails/auth/email-verification.tsx
packages/emails/emails/orders/order-created.tsx
packages/emails/emails/auth/verification-otp.tsx
packages/emails/emails/orders/order-status-updated.tsx
packages/emails/emails/auth/otp-sign-in.tsx
packages/emails/emails/auth/password-reset.tsx
packages/emails/emails/welcome.tsx
packages/emails/emails/admin-invitation.tsx
**/package.json
⚙️ CodeRabbit Configuration File
**/package.json
: УПРАВЛЕНИЕ ЗАВИСИМОСТЯМИ:
Версионирование:
- Используйте семантическое версионирование
- Избегайте уязвимых версий пакетов
- Регулярно обновляйте зависимости
Структура:
- Правильно организуйте scripts
- Разделяйте dependencies и devDependencies
- Используйте точные версии для критических пакетов
Безопасность:
- Проверяйте пакеты на уязвимости
- Используйте только проверенные пакеты
- Регулярно аудируйте зависимости
Files:
packages/config/package.json
packages/emails/package.json
{packages/web-api/**,packages/api/**,packages/web-validators/**,packages/validators/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
Use the same Zod schemas on both frontend and backend. Import schemas from
/packages/web-validators
(for web) and/packages/validators
(for app) to guarantee unified validation and type safety.
Files:
packages/web-api/src/router/orders/create-order.ts
{packages/web-api/**,packages/api/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
The server must prepare and return clear, frontend-ready data structures. All necessary transformations and formatting should be performed on the server, so that the frontend receives data in the exact shape it needs.
Files:
packages/web-api/src/router/orders/create-order.ts
{packages/web-api/**,packages/api/**,packages/lib/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
Keep business logic decoupled in
/packages/web-api
,/packages/api
, or/packages/lib
.
Files:
packages/web-api/src/router/orders/create-order.ts
🧠 Learnings (2)
📚 Learning: 2025-08-01T07:57:26.911Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/code.mdc:0-0
Timestamp: 2025-08-01T07:57:26.911Z
Learning: Applies to **/*.{ts,tsx} : Use environment variables or `t3-oss/env-core` for experimental feature flags.
Applied to files:
packages/config/src/env.ts
packages/config/src/index.ts
packages/emails/tsup.config.ts
packages/config/tsup.config.ts
packages/emails/package.json
📚 Learning: 2025-08-01T07:58:22.450Z
Learnt from: CR
PR: qcohq/qco#0
File: .windsurfrules:0-0
Timestamp: 2025-08-01T07:58:22.450Z
Learning: Applies to packages/db/**/*.{ts,js} : Database schemas are defined in `qco/db`.
Applied to files:
packages/config/tsconfig.json
packages/config/package.json
🧬 Code Graph Analysis (1)
packages/web-api/src/router/orders/create-order.ts (3)
packages/config/src/env.ts (1)
env
(4-27)packages/emails/emails/orders/admin-order-notification.tsx (2)
AdminOrderNotification
(39-166)item
(89-98)packages/emails/emails/orders/order-cancelled.tsx (1)
OrderCancelledEmail
(20-69)
🔇 Additional comments (13)
packages/config/tsconfig.json (1)
1-8
: LGTM! Корректная конфигурация TypeScript для внутреннего пакета.Конфигурация правильно использует базовую настройку для внутренних пакетов и корректно включает директорию
src
. Структура соответствует стандартам монорепозитория.packages/emails/package.json (1)
30-30
: LGTM! Зависимости корректно реорганизованы.Удаление
@t3-oss/env-core
иzod
оправдано, поскольку эти зависимости теперь инкапсулированы в новом пакете@qco/config
. Зависимостьtailwindcss-animate
корректно сохранена.packages/emails/tsup.config.ts (1)
3-3
: LGTM! Правильное использование переменных окружения.Переход к использованию
process.env.NODE_ENV
напрямую является корректным решением, особенно в контексте миграции к централизованному пакету конфигурации. Это упрощает логику сборки и устраняет зависимость от локального модуля env.packages/emails/emails/orders/order-status-updated.tsx (1)
15-15
: LGTM! Корректная миграция на централизованную конфигурацию.Переход к использованию
@qco/config
для импорта переменных окружения соответствует архитектурному решению о централизации конфигурации. Использованиеenv.SITE_URL
на строке 18 остается неизменным, что обеспечивает обратную совместимость.packages/emails/emails/admin-invitation.tsx (1)
17-17
: LGTM! Корректная миграция на централизованную конфигурацию.Импорт
env
из@qco/config
соответствует общей стратегии миграции в этом PR. Использованиеenv.SITE_NAME
в компоненте (строки 40 и 50) остается неизменным, что обеспечивает функциональную совместимость.packages/emails/emails/auth/verification-otp.tsx (1)
15-15
: Импорт env из @qco/config — окМиграция на общий конфиг соответствует архитектурным целям и не влияет на существующую разметку.
packages/config/src/index.ts (1)
1-1
: Экспорт env — корректно и минималистичноПубличная поверхность пакета ровно то, что нужно для потребителей.
packages/emails/index.ts (1)
18-18
: Импорт env из @qco/emails не найден — всё в порядкеЛокальный поиск подтвердил отсутствие:
import { env } from '@qco/emails'
в других пакетах- относительных импортов
from './env'
,from '../env'
,from '../../env'
вpackages/emails
packages/emails/emails/orders/order-created.tsx (1)
15-15
: Централизация env: импорт из @qco/config — окПереход на общий конфиг — правильный шаг для консистентности.
packages/emails/send.ts (1)
7-7
: Импорт env из @qco/config — ок, проверьте зависимостиАктуализируйте зависимости
packages/emails
на@qco/config
и убедитесь, что бандлер правильно резолвит внутренний пакет.Запустите скрипт проверки (аналогичный из email-verification.tsx), он покажет наличие зависимости и экспортов.
packages/emails/emails/auth/password-reset.tsx (1)
17-17
: Импорт env из @qco/config — хорошоКонсолидация конфигурации выглядит корректно. Совместимость типов
env.SITE_NAME
с рендерингом — ок.packages/config/tsup.config.ts (1)
3-15
: Связка tsup ↔ exports: убедитесь, что пакет указывает на dist, а не на srcСборка настроена корректно, но сейчас package.json (см. мой комментарий там) экспортирует ./src/index.ts. Это приведёт к импорту TS-исходников потребителями вместо скомпилированного JS из dist. Выровняйте exports на dist и типы — иначе возможны рантайм-проблемы.
packages/web-api/src/router/orders/create-order.ts (1)
94-94
: Проверено: OrderCreatedEmail принимает опциональный пропсorderUrl
В интерфейсеOrderCreatedEmailProps
полеorderUrl
объявлено с?
и в компоненте задано значение по умолчанию, значит пропс опционален.
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
🔭 Outside diff range comments (10)
packages/web-api/src/router/profile/create-profile-from-order.ts (5)
75-86
: Не возвращайте undefined в customerId при success
newCustomer?.id
может быть undefined (например, если .returning() не вернул строку). Возвращатьsuccess: true
без customerId сломает клиентов. Гарантируйте, чтоnewCustomer
не пустой, иначе кидайте ошибку.Примените проверку после вставки и уберите optional chaining:
- }).returning(); + }).returning(); + if (!newCustomer) { + throw new TRPCError({ + code: "INTERNAL_SERVER_ERROR", + message: "Не удалось создать профиль (БД вернула пустой результат)", + }); + }- customerId: newCustomer?.id, + customerId: newCustomer.id,Also applies to: 107-111
75-106
: Сделайте создание клиента и адреса атомарным (транзакция)Если вставка адреса упадёт, клиент уже будет создан (неатомарность). Оберните создание клиента и, при необходимости, адреса в одну транзакцию.
Примерно так (псевдокод, синтаксис зависит от используемой ORM):
await ctx.db.transaction(async (tx) => { const [newCustomer] = await tx.insert(customers).values({...}).returning(); if (!newCustomer) throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Не удалось создать профиль" }); if (input.saveAddress) { await tx.insert(customerAddresses).values({ id: createId(), customerId: newCustomer.id, // ... }); } });
26-30
: Гонка при проверке e-mail и вставке — используйте upsert/обработку уникального ограниченияМежду проверкой существования и вставкой возможна гонка, которая приведёт к уникальному конфликту по email.
Решения:
- Использовать upsert (on conflict do update returning) по уникальному ключу email.
- Либо ловить ошибку уникальности на вставке и выполнять обновление.
Если используете drizzle-orm (Postgres):
const [row] = await ctx.db .insert(customers) .values(values) .onConflictDoUpdate({ target: customers.email, set: { firstName: input.firstName, lastName: input.lastName, phone: input.phone, isGuest: false, updatedAt: new Date(), }, }) .returning();Also applies to: 72-86
58-60
: Проверьте единственность «дефолтного» адреса клиентаВ текущей схеме в таблице customer_addresses есть лишь обычный индекс на поле is_default, но нет уникального ограничения на пару (customer_id, is_default=true). При каждом вставлении новой записи с
isDefault: true
могут накопиться несколько «дефолтных» адресов.Решения (выберите подходящее или комбинацию):
- Добавить на уровне БД частичный уникальный индекс:
CREATE UNIQUE INDEX uq_customer_default_address ON customer_addresses(customer_id) WHERE is_default = true;
- В коде перед вставкой сбрасывать флаг у предыдущих дефолтных адресов:
затем вставлять новый сawait ctx.db .update(customerAddresses) .set({ isDefault: false }) .where(eq(customerAddresses.customerId, customerId));isDefault: true
.Затронутые места:
- packages/web-api/src/router/profile/create-profile-from-order.ts
• линии 47–60 (вставка адреса для обновления клиента)
• линии 89–102 (вставка адреса для нового клиента)- packages/web-api/src/lib/orders/order-helpers.ts
• линии 165–182 (сохранение дефолтного адреса при создании заказа)
22-24
: Ограничить доступ к createProfileFromOrder (использовать protectedProcedure + проверка email)Текущая реализация на publicProcedure позволяет любому с известным e-mail изменить чужой профиль и снять флаг isGuest. Необходимо:
• В packages/web-api/src/router/profile/create-profile-from-order.ts
– заменить
import { publicProcedure } from "../../trpc";
на
import { protectedProcedure } from "../../trpc";
– заменить
export const createProfileFromOrder = publicProcedure
на
export const createProfileFromOrder = protectedProcedure
– добавить в начале мутации проверку, чтоctx.session.user.email === input.email
, и выбрасывать TRPCError с кодом FORBIDDEN при несовпадении.Пример diff:
-import { publicProcedure } from "../../trpc"; +import { protectedProcedure } from "../../trpc"; … -export const createProfileFromOrder = publicProcedure +export const createProfileFromOrder = protectedProcedure .input(createProfileFromOrderSchema) .mutation(async ({ ctx, input }) => { + if (!ctx.session?.user?.email || ctx.session.user.email !== input.email) { + throw new TRPCError({ code: "FORBIDDEN", message: "Недостаточно прав для изменения профиля" }); + } try { // …packages/web-api/src/router/products/get-sale.ts (2)
70-79
: Избегайте использованияany
в TypeScriptИспользование типа
any
нарушает строгую типизацию и может привести к ошибкам во время выполнения. Следует определить правильные типы дляproduct
и других переменных.Определите правильные типы вместо
any
:interface ProductWithRelations { id: string; brandId: string | null; name: string; slug: string; // ... остальные поля categories?: Array<{ category?: { id: string; name: string; slug: string; }; }>; files?: Array<{ file: { id: string; path: string; }; }>; brand?: { id: string; name: string; slug: string; }; // ... остальные поля } const filteredProducts = productsData.filter((product: ProductWithRelations) => { return product.categories?.some((pc) => pc.category?.slug === categorySlug ); });
120-126
: Неинформативная обработка ошибокБлок
catch
перехватывает ошибку, но не логирует её и не предоставляет контекстную информацию. Это затрудняет отладку в production.Добавьте логирование ошибки и передачу более детальной информации:
} catch (error) { + console.error('Error fetching sale products:', error); + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", - message: "Failed to fetch sale products", + message: `Failed to fetch sale products: ${errorMessage}`, + cause: error, }); }packages/web-api/src/router/products/get-new.ts (3)
75-79
: Использованиеany
нарушает строгую типизациюАналогично файлу
get-sale.ts
, здесь также используется типany
, что противоречит рекомендациям по строгой типизации.Определите правильные типы для всех переменных вместо использования
any
. См. рекомендации для файлаget-sale.ts
.
124-130
: Недостаточная обработка ошибокАналогично
get-sale.ts
, здесь также отсутствует логирование ошибки и детальная информация об ошибке.Добавьте логирование и более информативное сообщение об ошибке:
} catch (error) { + console.error('Error fetching new products:', error); + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", - message: "Failed to fetch new products", + message: `Failed to fetch new products: ${errorMessage}`, + cause: error, }); }
22-22
: Исправить несоответствие slug для категории “women”
Вget-sale.ts
используется women: "zhenschinam", а вget-new.ts
— women: "zhenskaya-odezhda". Такое расхождение приведёт к разным результатам для одного и того же раздела.Пожалуйста, выберите один корректный slug (например, тот, что хранится в БД или уже используется на фронте) и приведите к нему оба эндпоинта:
• packages/web-api/src/router/products/get-sale.ts (строка с women: "zhenschinam")
• packages/web-api/src/router/products/get-new.ts (строка с women: "zhenskaya-odezhda")После этого проверьте, что на фронтенде все вызовы (use-active-root-category, ProductGrid, Brand… и т.п.) используют тот же slug.
🧹 Nitpick comments (4)
packages/web-api/src/router/profile/create-profile-from-order.ts (2)
73-75
: Не используйте устаревший substr при генерации customerCodesubstr устарел. Замените на slice (или используйте более надёжный генератор).
-const customerCode = `CUST-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; +const customerCode = `CUST-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;Опционально: используйте createId()/nanoid для кода, если важна предсказуемая уникальность и длина.
47-63
: Дублирование логики вставки адреса — вынесите в helperКод создания адреса повторяется для существующего и нового клиента. Это затрудняет обслуживание и повышает риск расхождений.
Вынесите сбор значений в функцию/константу и переиспользуйте:
const buildAddressValues = (customerId: string) => ({ id: createId(), customerId, type: "shipping", firstName: input.firstName, lastName: input.lastName, addressLine1: input.address, addressLine2: input.apartment, city: input.city, state: input.state, postalCode: input.postalCode, country: "Россия", isDefault: true, createdAt: new Date(), updatedAt: new Date(), });Затем:
await ctx.db.insert(customerAddresses).values(buildAddressValues(existingCustomer.id));и
await ctx.db.insert(customerAddresses).values(buildAddressValues(newCustomer.id));Also applies to: 90-104
packages/web-api/src/router/products/get-sale.ts (1)
98-99
: Последовательное использование проверки наnull
Для
basePrice
иsalePrice
используется проверка!= null
, в то время как для других полей используется оператор??
. Рекомендуется использовать единообразный подход.Для единообразия можно использовать оператор
??
и с приведением типа:-basePrice: product.basePrice != null ? Number(product.basePrice) : null, -salePrice: product.salePrice != null ? Number(product.salePrice) : null, +basePrice: product.basePrice ? Number(product.basePrice) : null, +salePrice: product.salePrice ? Number(product.salePrice) : null,packages/web-api/src/router/products/get-new.ts (1)
102-103
: Несогласованная проверка наnull
Используется
!= null
для проверки, что может быть заменено на более идиоматичный подход с??
оператором для консистентности с остальным кодом.См. рекомендацию для аналогичного кода в
get-sale.ts
.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lock
is excluded by!**/*.lock
📒 Files selected for processing (6)
packages/auth/env.ts
(0 hunks)packages/emails/package.json
(2 hunks)packages/web-api/package.json
(1 hunks)packages/web-api/src/router/products/get-new.ts
(2 hunks)packages/web-api/src/router/products/get-sale.ts
(2 hunks)packages/web-api/src/router/profile/create-profile-from-order.ts
(2 hunks)
💤 Files with no reviewable changes (1)
- packages/auth/env.ts
✅ Files skipped from review due to trivial changes (1)
- packages/web-api/package.json
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/emails/package.json
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
**/*.{ts,tsx}
: Use strict typing in TypeScript and avoidany
.
Use environment variables or@t3-oss/env-core
for experimental feature flags.
Files:
packages/web-api/src/router/profile/create-profile-from-order.ts
packages/web-api/src/router/products/get-sale.ts
packages/web-api/src/router/products/get-new.ts
{packages/web-api/**,packages/api/**,packages/web-validators/**,packages/validators/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
Use the same Zod schemas on both frontend and backend. Import schemas from
/packages/web-validators
(for web) and/packages/validators
(for app) to guarantee unified validation and type safety.
Files:
packages/web-api/src/router/profile/create-profile-from-order.ts
packages/web-api/src/router/products/get-sale.ts
packages/web-api/src/router/products/get-new.ts
{packages/web-api/**,packages/api/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
The server must prepare and return clear, frontend-ready data structures. All necessary transformations and formatting should be performed on the server, so that the frontend receives data in the exact shape it needs.
Files:
packages/web-api/src/router/profile/create-profile-from-order.ts
packages/web-api/src/router/products/get-sale.ts
packages/web-api/src/router/products/get-new.ts
{packages/web-api/**,packages/api/**,packages/lib/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
Keep business logic decoupled in
/packages/web-api
,/packages/api
, or/packages/lib
.
Files:
packages/web-api/src/router/profile/create-profile-from-order.ts
packages/web-api/src/router/products/get-sale.ts
packages/web-api/src/router/products/get-new.ts
**/*.ts
📄 CodeRabbit Inference Engine (.windsurfrules)
Use Zod for validation.
Files:
packages/web-api/src/router/profile/create-profile-from-order.ts
packages/web-api/src/router/products/get-sale.ts
packages/web-api/src/router/products/get-new.ts
⚙️ CodeRabbit Configuration File
**/*.ts
: ОСНОВНЫЕ ПРИНЦИПЫ РАЗРАБОТКИ:
Именование и стиль кода:
- Имена файлов обязательно в kebab-case (например: my-component.ts, user-profile.tsx)
- Функции в camelCase, компоненты в PascalCase, константы в UPPER_SNAKE_CASE
- Имена переменных и функций должны четко отражать их назначение и реализацию
- Избегайте сокращений и аббревиатур в именах (кроме общепринятых)
- Поддерживайте консистентность в стиле кода (отступы, пробелы, переносы строк)
- Следуйте принципам чистого кода (DRY, SOLID, KISS)
- Используйте осмысленные имена для булевых переменных (isLoading, hasPermission, canEdit)
TypeScript и типизация:
- Используйте строгую типизацию и избегайте any, unknown и {} где это возможно
- Правильно применяйте дженерики, интерфейсы и типы
- Обеспечивайте корректные определения типов для параметров функций и возвращаемых значений
- Предпочитайте union и intersection типы сложным условным конструкциям
- Используйте утилитарные типы TypeScript (Pick, Omit, Partial, Required)
- Создавайте переиспользуемые типы и интерфейсы
- Избегайте дублирования типов, выносите общие типы в отдельные файлы
Соблюдение правил линтера:
- Следуйте правилам ESLint для React и TypeScript
- Соблюдайте рекомендации Biome по форматированию и анализу кода
- Убедитесь, что код не содержит предупреждений или ошибок линтера
- Используйте автоматическое форматирование кода
Алгоритмы и производительность:
- Пишите понятные и читаемые алгоритмы, которые могут понять другие разработчики
- Оптимизируйте сложность алгоритмов (временную и пространственную)
- Избегайте чрезмерной вложенности и сложности
- Правильно обрабатывайте граничные случаи и ошибки
- Используйте подходящие структуры данных для задач
- Применяйте мемоизацию где это уместно
Безопасность и стабильность:
- Реализуйте правильную валидацию входных данных и защиту от инъекций
- Корректно обрабатывайте ошибки и исключения
- Обеспечивайте...
Files:
packages/web-api/src/router/profile/create-profile-from-order.ts
packages/web-api/src/router/products/get-sale.ts
packages/web-api/src/router/products/get-new.ts
🧠 Learnings (7)
📚 Learning: 2025-08-01T07:58:07.363Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/web-api.mdc:0-0
Timestamp: 2025-08-01T07:58:07.363Z
Learning: Applies to apps/web/**/*.tsx : Import Drizzle ORM functions like eq, sql from qco/db, e.g., import { eq, sql } from "qco/db";
Applied to files:
packages/web-api/src/router/products/get-sale.ts
packages/web-api/src/router/products/get-new.ts
📚 Learning: 2025-08-01T07:57:06.890Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/api.mdc:0-0
Timestamp: 2025-08-01T07:57:06.890Z
Learning: Applies to packages/api/**/*.ts : Import functions like eq, sql from qco/db, e.g., import { eq, sql } from "qco/db";
Applied to files:
packages/web-api/src/router/products/get-sale.ts
packages/web-api/src/router/products/get-new.ts
📚 Learning: 2025-08-01T07:58:22.450Z
Learnt from: CR
PR: qcohq/qco#0
File: .windsurfrules:0-0
Timestamp: 2025-08-01T07:58:22.450Z
Learning: Applies to packages/db/**/*.{ts,js} : Database schemas are defined in `qco/db`.
Applied to files:
packages/web-api/src/router/products/get-sale.ts
packages/web-api/src/router/products/get-new.ts
📚 Learning: 2025-08-01T07:58:07.363Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/web-api.mdc:0-0
Timestamp: 2025-08-01T07:58:07.363Z
Learning: Applies to apps/web/**/*.tsx : Import table schemas from qco/db/schema, e.g., import { Category, ProductCategory } from "qco/db/schema";
Applied to files:
packages/web-api/src/router/products/get-sale.ts
packages/web-api/src/router/products/get-new.ts
📚 Learning: 2025-08-01T07:57:06.890Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/api.mdc:0-0
Timestamp: 2025-08-01T07:57:06.890Z
Learning: Applies to packages/api/**/*.ts : Import schemas from qco/db/schema, e.g., import { Category, ProductCategory } from "qco/db/schema";
Applied to files:
packages/web-api/src/router/products/get-sale.ts
packages/web-api/src/router/products/get-new.ts
📚 Learning: 2025-08-01T07:58:07.363Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/web-api.mdc:0-0
Timestamp: 2025-08-01T07:58:07.363Z
Learning: Applies to apps/web/**/*.tsx : Use ctx for database access in tRPC routes to ensure consistent data handling
Applied to files:
packages/web-api/src/router/products/get-sale.ts
packages/web-api/src/router/products/get-new.ts
📚 Learning: 2025-08-01T07:57:06.890Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/api.mdc:0-0
Timestamp: 2025-08-01T07:57:06.890Z
Learning: Applies to packages/api/**/*.ts : Use TRPCError for consistent error handling across all routes.
Applied to files:
packages/web-api/src/router/products/get-sale.ts
packages/web-api/src/router/products/get-new.ts
🧬 Code Graph Analysis (2)
packages/web-api/src/router/profile/create-profile-from-order.ts (2)
apps/web/src/features/checkout/components/checkout-page-client.tsx (1)
data
(137-163)packages/web-api/src/lib/orders/order-helpers.ts (1)
CreateOrderParams
(53-65)
packages/web-api/src/router/products/get-new.ts (1)
apps/web/src/features/products/components/enhanced-catalog-page-new.tsx (1)
EnhancedCatalogPage
(32-241)
⏰ 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: Test API Package
🔇 Additional comments (3)
packages/web-api/src/router/profile/create-profile-from-order.ts (1)
88-88
: LGTM: добавлена проверка наличия newCustomer при сохранении адресаХорошая защита от обращения к undefined при вставке адреса.
packages/web-api/src/router/products/get-sale.ts (1)
2-2
: Неиспользуемый импортasc
Функция
asc
импортируется, но не используется в этом файле. На строке 62 используетсяasc(productFiles.order)
, но это вызов метода объектаasc
, а не импортированной функции.Удалите неиспользуемый импорт:
-import { eq, and, desc, isNotNull, lt, asc } from "@qco/db"; +import { eq, and, desc, isNotNull, lt } from "@qco/db";⛔ Skipped due to learnings
Learnt from: CR PR: qcohq/qco#0 File: .cursor/rules/api.mdc:0-0 Timestamp: 2025-08-01T07:57:06.890Z Learning: Applies to packages/api/**/*.ts : Import functions like eq, sql from qco/db, e.g., import { eq, sql } from "qco/db";
Learnt from: CR PR: qcohq/qco#0 File: .cursor/rules/web-api.mdc:0-0 Timestamp: 2025-08-01T07:58:07.363Z Learning: Applies to apps/web/**/*.tsx : Import Drizzle ORM functions like eq, sql from qco/db, e.g., import { eq, sql } from "qco/db";
Learnt from: CR PR: qcohq/qco#0 File: .windsurfrules:0-0 Timestamp: 2025-08-01T07:58:22.450Z Learning: Applies to packages/db/**/*.{ts,js} : Database schemas are defined in `qco/db`.
packages/web-api/src/router/products/get-new.ts (1)
16-17
: Неиспользуемая логика сcutoffDate
Переменная
cutoffDate
вычисляется, но не используется, так как условие на строке 33 закомментировано. Это создаёт путаницу относительно логики работы функции.Нужно определиться с логикой: либо использовать дату для фильтрации новых товаров, либо удалить неиспользуемый код:
-// Вычисляем дату, начиная с которой товары считаются новыми -const cutoffDate = new Date(); -cutoffDate.setDate(cutoffDate.getDate() - days); // ... в where условии: where: and( eq(products.isActive, true), eq(products.isNew, true), - //gte(products.createdAt, cutoffDate) + gte(products.createdAt, cutoffDate) ),Или полностью удалить логику с датой, если она не нужна.
Also applies to: 33-33
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: 15
🔭 Outside diff range comments (11)
packages/web-api/src/router/category/get-by-slug.ts (2)
26-28
: Используйте TRPCError(NOT_FOUND) вместо Error для консистентности ошибок APIЭто обеспечит корректные HTTP-коды и единый формат обработки ошибок на клиенте.
Примените дифф:
- throw new Error(`Категория со slug "${input.slug}" не найдена`); + throw new TRPCError({ + code: 'NOT_FOUND', + message: `Категория со slug "${input.slug}" не найдена`, + });
1-4
: Добавьте импорт TRPCErrorНеобходим для предыдущей правки обработки ошибок.
Примените дифф:
import { eq } from '@qco/db' import { categories } from '@qco/db/schema' import { categorySlugInputV2, categorySchemaV2 } from '@qco/web-validators' +import { TRPCError } from '@trpc/server' import { publicProcedure } from '../../trpc'
packages/web-api/src/router/products/get-popular-by-category.ts (2)
54-59
: Избавиться от any, сузить выборку и дедуплицировать productIds
- Не нужно тащить
with: { product: true }
, если вам нужен толькоproductId
.- Уберите
any
и упростите типизацию.- Дедуплицируйте
productIds
, чтобы не плодить повторов в IN-выборке.- Привяжите маппинг к конкретному типу (без
any
), используя локальные интерфейсы.- const productCategoriesData = await db.query.productCategories.findMany({ - where: eq(productCategories.categoryId, category.id), - with: { - product: true, - }, - }); + const productCategoriesData = await db.query.productCategories.findMany({ + where: eq(productCategories.categoryId, category.id), + columns: { + productId: true, + }, + });- const productIds = productCategoriesData.map((pc: any) => pc.productId); + const productIds = Array.from( + new Set(productCategoriesData.map((pc) => pc.productId)), + );- return productsData.map((product: any) => { + return productsData.map((product: ProductWithRelations) => {Добавьте рядом с локальными интерфейсами тип результата запроса:
// рядом с ProductFileType / ProductCategoryRelationType type ProductWithRelations = typeof products.$inferSelect & { brand: { name: string } | null; files: ProductFileType[]; categories: ProductCategoryRelationType[]; };Also applies to: 66-66, 92-92
69-74
: Добавить фильтрацию по популярности в get-popular-by-categoryВ текущей реализации в packages/web-api/src/router/products/get-popular-by-category.ts в блоке
where
отсутствует условие по полюisPopular
, из-за чего возвращаются все активные товары категории, а не только популярные.• Файл: packages/web-api/src/router/products/get-popular-by-category.ts
• Строки: 69–74Примените патч:
const productsData = await db.query.products.findMany({ where: and( inArray(products.id, productIds), eq(products.isActive, true), + eq(products.isPopular, true), ), with: {
packages/web-api/src/router/account/orders/get-order-detail.ts (3)
38-43
: Использованиеany
не соответствует принципам строгой типизации TypeScript.Добавление явных типов
any
для параметров колбеков противоречит кодингайдлайнам, которые требуют строгой типизации и избеганияany
. Эти типы можно вывести автоматически или определить более точно на основе схемы базы данных.Примените следующий diff для улучшения типизации:
- .filter((combination: any) => combination.option && combination.optionValue) - .map((combination: any) => ({ + .filter((combination) => combination.option && combination.optionValue) + .map((combination) => ({Либо создайте правильный тип для комбинации:
type OptionCombination = { option: { name: string; slug: string } | null; optionValue: { displayName?: string; value: string } | null; };
20-23
: Несогласованность типизации параметраctx
.Параметр
ctx
типизирован какany
, что нарушает принципы строгой типизации. В других файлах (например, вpackages/api/src/router/orders/by-id.ts
) используется более точный типTRPCContext
.Примените следующий diff для унификации типизации:
-async function getVariantOptions( - ctx: any, - variantId: string -): Promise<Array<{ name: string; value: string; slug: string }>> { +async function getVariantOptions( + ctx: TRPCContext, + variantId: string +): Promise<Array<{ name: string; value: string; slug: string }>> {Также добавьте импорт типа:
+import type { TRPCContext } from "../../../trpc";
17-50
: Дублирование кода функцииgetVariantOptions
.Функция
getVariantOptions
полностью дублируется в нескольких файлах (packages/api/src/router/orders/by-id.ts
,packages/api/src/router/orders/list.ts
и текущем файле). Это нарушает принцип DRY и усложняет сопровождение кода.Рекомендуется вынести эту функцию в общую утилиту, например, в
packages/lib
или создать отдельный модуль вpackages/web-api/src/lib/variant-options.ts
:// packages/web-api/src/lib/variant-options.ts import type { TRPCContext } from "../trpc"; import { eq } from "@qco/db"; import { productVariantOptionCombinations } from "@qco/db/schema"; export async function getVariantOptions( ctx: TRPCContext, variantId: string ): Promise<Array<{ name: string; value: string; slug: string }>> { // реализация функции }Затем импортировать и использовать в нужных файлах.
packages/web-api/src/router/account/orders/get-orders.ts (1)
39-44
: Использованиеany
противоречит принципам строгой типизации.Аналогично предыдущему файлу, добавление явных типов
any
нарушает кодингайдлайны по строгой типизации TypeScript.Примените следующий diff:
- .filter((combination: any) => combination.option && combination.optionValue) - .map((combination: any) => ({ + .filter((combination) => combination.option && combination.optionValue) + .map((combination) => ({packages/web-api/src/router/brands/get-by-id.ts (1)
30-33
: Используйте TRPCError и не теряйте контекст ошибкиСейчас 404 превращается в общий "Failed to fetch...". Верните корректный код NOT_FOUND и не заглушайте TRPCError.
Примените дифф:
@@ - if (!brand) { - throw new Error(`Brand with ID "${id}" not found`); - } + if (!brand) { + throw new TRPCError({ + code: "NOT_FOUND", + message: `Brand with ID "${id}" not found`, + }); + } @@ - } catch (error) { - throw new Error("Failed to fetch brand by ID"); - } + } catch (error) { + if (error instanceof TRPCError) throw error; + throw new TRPCError({ + code: "INTERNAL_SERVER_ERROR", + message: "Failed to fetch brand by ID", + }); + }Добавьте импорт:
import { TRPCError } from "@trpc/server";Also applies to: 62-65
packages/web-api/src/router/checkout/validate-draft.ts (2)
19-26
: Унифицируйте структуру ответа (ключи должны быть стабильными)Сейчас на ошибке возвращаются validation/completeness, а на успехе — data/errors/recommendations (в другом контейнере). Лучше всегда возвращать { success, data, error }, где data либо объект с результатами, либо null.
Примените дифф:
@@ - return { - success: false, - error: "Данные для валидации не переданы", - validation: null, - completeness: null, - }; + return { + success: false, + data: null, + error: "Данные для валидации не переданы", + }; @@ - return { - success: true, - data: { - isValid: validationResult.isValid, - data: validationResult.data, - errors: validationResult.errors, - recommendations: generateRecommendations(validationResult) - }, - error: null - }; + return { + success: true, + data: { + isValid: validationResult.isValid, + data: validationResult.data, + errors: validationResult.errors, + recommendations: generateRecommendations(validationResult), + }, + error: null, + }; @@ - return { - success: false, - error: "Ошибка при валидации данных", - validation: null, - completeness: null, - }; + return { + success: false, + data: null, + error: "Ошибка при валидации данных", + };Also applies to: 32-41, 45-51
57-83
: Типизируйте generateRecommendations без anyИспользуйте DraftValidationResult и ZodIssue, избавьтесь от any и закрепите тип группы ошибок.
Примените дифф:
-function generateRecommendations(validationResult: any) { - const recommendations: string[] = []; +function generateRecommendations(validationResult: DraftValidationResult) { + const recommendations: string[] = []; @@ - if (!validationResult.isValid && validationResult.errors) { - // Группируем ошибки по типам для рекомендаций - const fieldErrors = validationResult.errors.reduce((acc: any, error: any) => { - const field = error.path[0]; - if (!acc[field]) acc[field] = []; - acc[field].push(error.message); - return acc; - }, {}); + if (!validationResult.isValid && validationResult.errors) { + // Группируем ошибки по полям + const fieldErrors = validationResult.errors.reduce((acc: Record<string, string[]>, error: ZodIssue) => { + const field = String(error.path[0] ?? "general"); + if (!acc[field]) acc[field] = []; + acc[field].push(error.message); + return acc; + }, {} as Record<string, string[]>);Добавьте импорты:
import type { DraftValidationResult } from "@qco/web-validators"; import type { ZodIssue } from "zod";
♻️ Duplicate comments (1)
packages/web-api/src/router/account/orders/get-orders.ts (1)
21-51
: Дублирование функцииgetVariantOptions
.Эта функция является точной копией функций из других файлов. Необходимо вынести её в общую утилиту для соблюдения принципа DRY.
См. комментарий к аналогичной функции в файле
packages/web-api/src/router/account/orders/get-order-detail.ts
.
🧹 Nitpick comments (6)
packages/web-api/src/router/products/get-popular-by-category.ts (3)
91-139
: Повторяющийся маппинг товара — вынесите в общий helper/DTOПо описанию PR аналогичный маппинг есть в get-new.ts и get-sale.ts. Поддерживать 3 копии рискованно (расхождение полей, баги). Предлагаю вынести маппер в общий модуль (например, packages/lib/products/mapToListItem.ts) и использовать везде один источник истины.
140-142
: Не проглатывайте ошибки — добавьте логированиеСейчас при исключении вы молча возвращаете пустой массив. Это затрудняет отладку в проде. Минимум — залогировать ошибку и входные параметры.
} catch (error: unknown) { - return []; + // TODO: заменить на централизованный логгер, если он есть в TRPCContext + console.error("getPopularByCategoryFn failed", { slug, limit, error }); + return []; }
41-41
: Дублирование default для limit (8) — оставьте один источник истиныЗначение по умолчанию задано и в параметре функции, и в Zod-схеме. Достаточно в одном месте (рекомендуется в схеме).
- limit = 8, + limit: number,Also applies to: 152-153
packages/web-api/src/router/brands/get-featured.ts (1)
16-16
: Незначительное: сортировка по isFeatured избыточнаwhere уже фильтрует isFeatured = true, сортировка по нему не влияет на порядок.
Примените дифф:
- orderBy: [desc(brands.isFeatured), brands.name], + orderBy: [brands.name],packages/web-api/src/router/checkout/validate-draft.ts (1)
10-16
: Рассмотрите .output-схему для стабильности контрактаСейчас нет .output — добавление её с zod-схемой ответа повысит предсказуемость контракта и защитит от регрессий.
Могу предложить zod-схему для формы:
{ success: boolean; data: { isValid: boolean; data: unknown; errors: ZodIssue[] | null; recommendations: string[] } | null; error: string | null }.packages/web-api/src/lib/draft-utils.ts (1)
82-118
: Опционально: типизируйте ошибки Zod и группыИзбавьтесь от any в groupValidationErrors/hasCriticalErrors для лучшей читаемости и автодополнения.
Пример:
import type { ZodIssue } from "zod"; export function groupValidationErrors(errors: ZodIssue[] | null) { if (!errors) return {}; const groups: Record<"contact"|"shipping"|"payment"|"general", string[]> = { contact: [], shipping: [], payment: [], general: [] }; for (const error of errors) { const field = String(error.path[0] ?? "general"); // ... } return groups; } export function hasCriticalErrors(errors: ZodIssue[] | null): boolean { if (!errors) return false; const criticalFields = ["email", "phone", "address", "city"]; return errors.some(e => criticalFields.includes(String(e.path[0]))); }
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
packages/web-api/src/lib/draft-utils.ts
(2 hunks)packages/web-api/src/router/account/orders/get-order-detail.ts
(1 hunks)packages/web-api/src/router/account/orders/get-orders.ts
(3 hunks)packages/web-api/src/router/brands/get-by-id.ts
(1 hunks)packages/web-api/src/router/brands/get-featured.ts
(2 hunks)packages/web-api/src/router/categories/get-all.ts
(2 hunks)packages/web-api/src/router/category/get-by-slug.ts
(1 hunks)packages/web-api/src/router/checkout/validate-draft.ts
(2 hunks)packages/web-api/src/router/products/get-popular-by-category.ts
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
**/*.{ts,tsx}
: Use strict typing in TypeScript and avoidany
.
Use environment variables or@t3-oss/env-core
for experimental feature flags.
Files:
packages/web-api/src/router/categories/get-all.ts
packages/web-api/src/router/account/orders/get-order-detail.ts
packages/web-api/src/lib/draft-utils.ts
packages/web-api/src/router/brands/get-by-id.ts
packages/web-api/src/router/account/orders/get-orders.ts
packages/web-api/src/router/category/get-by-slug.ts
packages/web-api/src/router/products/get-popular-by-category.ts
packages/web-api/src/router/checkout/validate-draft.ts
packages/web-api/src/router/brands/get-featured.ts
{packages/web-api/**,packages/api/**,packages/web-validators/**,packages/validators/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
Use the same Zod schemas on both frontend and backend. Import schemas from
/packages/web-validators
(for web) and/packages/validators
(for app) to guarantee unified validation and type safety.
Files:
packages/web-api/src/router/categories/get-all.ts
packages/web-api/src/router/account/orders/get-order-detail.ts
packages/web-api/src/lib/draft-utils.ts
packages/web-api/src/router/brands/get-by-id.ts
packages/web-api/src/router/account/orders/get-orders.ts
packages/web-api/src/router/category/get-by-slug.ts
packages/web-api/src/router/products/get-popular-by-category.ts
packages/web-api/src/router/checkout/validate-draft.ts
packages/web-api/src/router/brands/get-featured.ts
{packages/web-api/**,packages/api/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
The server must prepare and return clear, frontend-ready data structures. All necessary transformations and formatting should be performed on the server, so that the frontend receives data in the exact shape it needs.
Files:
packages/web-api/src/router/categories/get-all.ts
packages/web-api/src/router/account/orders/get-order-detail.ts
packages/web-api/src/lib/draft-utils.ts
packages/web-api/src/router/brands/get-by-id.ts
packages/web-api/src/router/account/orders/get-orders.ts
packages/web-api/src/router/category/get-by-slug.ts
packages/web-api/src/router/products/get-popular-by-category.ts
packages/web-api/src/router/checkout/validate-draft.ts
packages/web-api/src/router/brands/get-featured.ts
{packages/web-api/**,packages/api/**,packages/lib/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
Keep business logic decoupled in
/packages/web-api
,/packages/api
, or/packages/lib
.
Files:
packages/web-api/src/router/categories/get-all.ts
packages/web-api/src/router/account/orders/get-order-detail.ts
packages/web-api/src/lib/draft-utils.ts
packages/web-api/src/router/brands/get-by-id.ts
packages/web-api/src/router/account/orders/get-orders.ts
packages/web-api/src/router/category/get-by-slug.ts
packages/web-api/src/router/products/get-popular-by-category.ts
packages/web-api/src/router/checkout/validate-draft.ts
packages/web-api/src/router/brands/get-featured.ts
**/*.ts
📄 CodeRabbit Inference Engine (.windsurfrules)
Use Zod for validation.
Files:
packages/web-api/src/router/categories/get-all.ts
packages/web-api/src/router/account/orders/get-order-detail.ts
packages/web-api/src/lib/draft-utils.ts
packages/web-api/src/router/brands/get-by-id.ts
packages/web-api/src/router/account/orders/get-orders.ts
packages/web-api/src/router/category/get-by-slug.ts
packages/web-api/src/router/products/get-popular-by-category.ts
packages/web-api/src/router/checkout/validate-draft.ts
packages/web-api/src/router/brands/get-featured.ts
⚙️ CodeRabbit Configuration File
**/*.ts
: ОСНОВНЫЕ ПРИНЦИПЫ РАЗРАБОТКИ:
Именование и стиль кода:
- Имена файлов обязательно в kebab-case (например: my-component.ts, user-profile.tsx)
- Функции в camelCase, компоненты в PascalCase, константы в UPPER_SNAKE_CASE
- Имена переменных и функций должны четко отражать их назначение и реализацию
- Избегайте сокращений и аббревиатур в именах (кроме общепринятых)
- Поддерживайте консистентность в стиле кода (отступы, пробелы, переносы строк)
- Следуйте принципам чистого кода (DRY, SOLID, KISS)
- Используйте осмысленные имена для булевых переменных (isLoading, hasPermission, canEdit)
TypeScript и типизация:
- Используйте строгую типизацию и избегайте any, unknown и {} где это возможно
- Правильно применяйте дженерики, интерфейсы и типы
- Обеспечивайте корректные определения типов для параметров функций и возвращаемых значений
- Предпочитайте union и intersection типы сложным условным конструкциям
- Используйте утилитарные типы TypeScript (Pick, Omit, Partial, Required)
- Создавайте переиспользуемые типы и интерфейсы
- Избегайте дублирования типов, выносите общие типы в отдельные файлы
Соблюдение правил линтера:
- Следуйте правилам ESLint для React и TypeScript
- Соблюдайте рекомендации Biome по форматированию и анализу кода
- Убедитесь, что код не содержит предупреждений или ошибок линтера
- Используйте автоматическое форматирование кода
Алгоритмы и производительность:
- Пишите понятные и читаемые алгоритмы, которые могут понять другие разработчики
- Оптимизируйте сложность алгоритмов (временную и пространственную)
- Избегайте чрезмерной вложенности и сложности
- Правильно обрабатывайте граничные случаи и ошибки
- Используйте подходящие структуры данных для задач
- Применяйте мемоизацию где это уместно
Безопасность и стабильность:
- Реализуйте правильную валидацию входных данных и защиту от инъекций
- Корректно обрабатывайте ошибки и исключения
- Обеспечивайте...
Files:
packages/web-api/src/router/categories/get-all.ts
packages/web-api/src/router/account/orders/get-order-detail.ts
packages/web-api/src/lib/draft-utils.ts
packages/web-api/src/router/brands/get-by-id.ts
packages/web-api/src/router/account/orders/get-orders.ts
packages/web-api/src/router/category/get-by-slug.ts
packages/web-api/src/router/products/get-popular-by-category.ts
packages/web-api/src/router/checkout/validate-draft.ts
packages/web-api/src/router/brands/get-featured.ts
🧠 Learnings (5)
📚 Learning: 2025-08-01T07:58:07.363Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/web-api.mdc:0-0
Timestamp: 2025-08-01T07:58:07.363Z
Learning: Applies to apps/web/**/*.tsx : Import Drizzle ORM functions like eq, sql from qco/db, e.g., import { eq, sql } from "qco/db";
Applied to files:
packages/web-api/src/router/categories/get-all.ts
📚 Learning: 2025-08-01T07:57:06.890Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/api.mdc:0-0
Timestamp: 2025-08-01T07:57:06.890Z
Learning: Applies to packages/api/**/*.ts : Import functions like eq, sql from qco/db, e.g., import { eq, sql } from "qco/db";
Applied to files:
packages/web-api/src/router/categories/get-all.ts
📚 Learning: 2025-08-01T07:58:07.363Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/web-api.mdc:0-0
Timestamp: 2025-08-01T07:58:07.363Z
Learning: Applies to apps/web/**/*.tsx : Import table schemas from qco/db/schema, e.g., import { Category, ProductCategory } from "qco/db/schema";
Applied to files:
packages/web-api/src/router/categories/get-all.ts
📚 Learning: 2025-08-01T07:57:06.890Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/api.mdc:0-0
Timestamp: 2025-08-01T07:57:06.890Z
Learning: Applies to packages/api/**/*.ts : Import schemas from qco/db/schema, e.g., import { Category, ProductCategory } from "qco/db/schema";
Applied to files:
packages/web-api/src/router/categories/get-all.ts
📚 Learning: 2025-08-01T07:58:22.450Z
Learnt from: CR
PR: qcohq/qco#0
File: .windsurfrules:0-0
Timestamp: 2025-08-01T07:58:22.450Z
Learning: Applies to packages/db/**/*.{ts,js} : Database schemas are defined in `qco/db`.
Applied to files:
packages/web-api/src/router/categories/get-all.ts
🧬 Code Graph Analysis (7)
packages/web-api/src/router/categories/get-all.ts (1)
packages/web-api/src/router/category/list.ts (1)
categoriesQuery
(8-39)
packages/web-api/src/router/account/orders/get-order-detail.ts (2)
packages/api/src/router/orders/by-id.ts (2)
combination
(38-42)getVariantOptions
(20-48)packages/api/src/router/orders/list.ts (2)
combination
(38-42)getVariantOptions
(19-49)
packages/web-api/src/lib/draft-utils.ts (1)
packages/web-validators/src/checkout.ts (2)
CheckoutDraftPartialValues
(247-247)validateDraftData
(206-221)
packages/web-api/src/router/brands/get-by-id.ts (2)
apps/web/src/components/category-hero-section.tsx (2)
Banner
(24-37)BannerFile
(11-22)apps/web/src/components/hero-section.tsx (2)
Banner
(24-42)BannerFile
(11-22)
packages/web-api/src/router/account/orders/get-orders.ts (3)
packages/api/src/router/orders/list.ts (2)
getVariantOptions
(19-49)acc
(136-139)packages/api/src/router/orders/by-id.ts (1)
getVariantOptions
(20-48)packages/web-api/src/router/products/get-by-slug.ts (1)
variant
(259-298)
packages/web-api/src/router/category/get-by-slug.ts (1)
packages/web-api/src/router/category/list.ts (1)
category
(27-38)
packages/web-api/src/router/checkout/validate-draft.ts (2)
packages/web-validators/src/checkout.ts (1)
validateDraftData
(206-221)apps/web/src/features/checkout/components/checkout-page-client.tsx (2)
value
(118-123)draftError
(128-134)
⏰ 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: Test API Package
🔇 Additional comments (5)
packages/web-api/src/router/categories/get-all.ts (2)
1-1
: Импорт isNull из @qco/db — корректноПереход на явный импорт isNull согласуется с практикой Drizzle и с использованием ниже по коду.
16-19
: Правильная замена eq(..., null) на isNull(...)Проверка корневых категорий через isNull(categories.parentId) — корректный и типобезопасный способ для Drizzle. Логика фильтрации осталась неизменной и понятной.
packages/web-api/src/router/category/get-by-slug.ts (2)
30-41
: Явное формирование ответа — читаемо и типобезопасноОтказ от spread в пользу явного маппинга полей повышает предсказуемость структуры ответа и упрощает сопровождение/валидацию схемой Zod.
39-40
: TRPC уже настроен с SuperJSON — проверьте Zod-схему полей createdAt/updatedAtTRPC-конфиг содержит
transformer: superjson
, поэтому даты сериализуются как объекты Date. Однако в текущем репозитории не найденоexport const categorySchemaV2
вpackages/web-validators
, где должны быть описаны типы полей ответа.Пожалуйста, проверьте и скорректируйте:
- Найдите фактическую Zod-схему, отвечающую за маршрут
get-by-slug
(вpackages/web-validators
или аналогичной папке).- Убедитесь, что в этой схеме поля
createdAt
иupdatedAt
описаны какz.date()
(если клиент ожидает объект Date),- либо как
z.string()
(если ожидаются ISO-строки) и фронтенд к этому готов.- При необходимости обновите схему или фронтенд-обработку, чтобы типы совпадали.
packages/web-api/src/router/brands/get-by-id.ts (1)
59-61
: Поле banner уже включено в brandDetailSchema
В файле packages/web-validators/src/brands.ts (строка 105) определеноbanner: z.string().nullable(), // Дополнительное поле для фронтендаТаким образом, возврат
banner: null
соответствует схеме.
packages/web-api/src/router/products/get-popular-by-category.ts
Outdated
Show resolved
Hide resolved
packages/web-api/src/router/products/get-popular-by-category.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.
Actionable comments posted: 4
🔭 Outside diff range comments (2)
packages/api/src/router/orders/create.ts (1)
47-70
: Сделать создание заказа и позиций атомарным (транзакция) и вставлять позиции батчем.Сейчас заказ создаётся отдельно, а позиции — в цикле вне транзакции. При сбое получите частично созданные данные. Кроме того, батч-вставка быстрее и чище.
Предлагаемый рефактор:
- const [order] = await ctx.db.insert(orders).values(values).returning(); - - if (!order) { - throw new TRPCError({ - code: "INTERNAL_SERVER_ERROR", - message: "Failed to create order", - }); - } - - // Create order items - for (const item of items) { - await ctx.db.insert(orderItems).values({ - orderId: order.id, - productId: item.productId, - variantId: item.variantId, - quantity: item.quantity, - unitPrice: item.unitPrice, - totalPrice: item.totalPrice, - productName: item.productName, - productSku: item.productSku, - variantName: item.variantName, - - }); - } - - return order; + const createdOrder = await ctx.db.transaction(async (tx) => { + const [order] = await tx.insert(orders).values(values).returning(); + if (!order) { + throw new TRPCError({ + code: "INTERNAL_SERVER_ERROR", + message: "Failed to create order", + }); + } + + if (items.length > 0) { + await tx.insert(orderItems).values( + items.map((item) => ({ + orderId: order.id, + productId: item.productId, + variantId: item.variantId, + quantity: item.quantity, + unitPrice: item.unitPrice, + totalPrice: item.totalPrice, + productName: item.productName, + productSku: item.productSku, + variantName: item.variantName, + })), + ); + } + return order; + }); + + return createdOrder;packages/api/src/router/orders/list.ts (1)
20-20
: Рекомендуется заменитьany
на более строгие типы.Согласно руководящим принципам разработки, следует избегать использования
any
и применять строгую типизацию. Рекомендуется создать интерфейсы для типизации параметров.Создайте типы для улучшения типобезопасности:
+interface OptionCombination { + option: { name: string; slug: string } | null; + optionValue: { displayName?: string; value: string } | null; +} + +interface OrderItem { + productId: string; + variantId?: string; + productSku?: string; + variantName?: string; + // добавьте другие необходимые поля +} + +interface Order { + items?: OrderItem[]; + customer?: any; // определите интерфейс для customer + // добавьте другие поля заказа +} async function getVariantOptions( - ctx: any, + ctx: { db: any }, // или используйте правильный тип контекста variantId: string ): Promise<Array<{ name: string; value: string; slug: string }>> { // ... const variantOptions = optionCombinations - .filter((combination: any) => combination.option && combination.optionValue) - .map((combination: any) => ({ + .filter((combination: OptionCombination) => combination.option && combination.optionValue) + .map((combination: OptionCombination) => ({ // ... -return await Promise.all(data.map(async (order: any) => ({ +return await Promise.all(data.map(async (order: Order) => ({ // ... - items: await Promise.all(order.items?.map(async (item: any) => { + items: await Promise.all(order.items?.map(async (item: OrderItem) => {Also applies to: 129-129, 143-143, 145-145
♻️ Duplicate comments (2)
packages/config/package.json (2)
6-13
: Экспорт на собранные артефакты из dist — отлично, это исправляет прежнюю проблемуТеперь потребители не будут тянуть .ts-файлы; корректные
exports
,main
иtypes
указывают наdist
.
24-27
: Пины версий зависимостей выглядят уместноДля критичных пакетов (
@t3-oss/env-core
,zod
) фиксированные версии — разумно. Совместимость env-core 0.13.x с Zod v4 подтверждена в предыдущем обсуждении.
🧹 Nitpick comments (5)
packages/config/package.json (3)
4-4
: Подтвердите private:true; если пакет планируется к публикации — снимите private и задайте publishConfigС текущим
"private": true
пакет не будет опубликован, что ок для внутреннего workspace-зависимого пакета. Подтвердите намерение. Если публикация нужна — примените:- "private": true, + "private": false, + "publishConfig": { + "access": "public" + },
1-5
: Добавьте поле license (для private пакета — UNLICENSED)Явная лицензия улучшает соответствие инструментам и требованиям комплаенса.
{ "name": "@qco/config", "version": "0.0.0", "private": true, + "license": "UNLICENSED", "type": "module",
28-36
: Зафиксируйте поддерживаемую версию Node через enginesЭто поможет избежать конфликтов окружений в монорепозитории и CI.
"devDependencies": { "@qco/eslint-config": "workspace:*", "@qco/prettier-config": "workspace:*", "@qco/tsconfig": "workspace:*", "eslint": "9.32.0", "prettier": "3.6.2", "tsup": "8.5.0", "typescript": "5.9.2" }, + "engines": { + "node": ">=18" + }, "prettier": "@qco/prettier-config"packages/api/src/router/orders/get-by-customer.ts (1)
28-31
: Уточнить приведение типа статуса к типу столбца БД (и опционально валидировать значение).Привязка к объекту OrderStatus в приведения типа избыточна и хрупка. Надёжнее сузить тип до фактического типа столбца: typeof orders.$inferSelect["status"].
Прямой фикс (без дополнительной валидации):
- whereConditions.push(eq(orders.status, status as typeof OrderStatus[keyof typeof OrderStatus])); + // Узкое приведение к типу столбца БД, без зависимости от объекта OrderStatus + whereConditions.push(eq(orders.status, status as typeof orders.$inferSelect["status"]));Дополнительно (вне этого блока) можно валидировать входной статус и бросать BAD_REQUEST:
const allowedStatuses = Object.values(OrderStatus) as Array<typeof orders.$inferSelect["status"]>; if (!allowedStatuses.includes(status as any)) { throw new TRPCError({ code: "BAD_REQUEST", message: "Invalid status" }); }packages/api/src/router/orders/create.ts (1)
4-4
: Можно упростить типизацию и избавиться от лишних импортов enum’ов.Сейчас типизация полей основана на импортированных DB-enum’ах. Чтобы убрать лишние зависимости и дублирование, можно приводить к типам столбцов через orders.$inferInsert[...] и удалить импорты PaymentMethod/PaymentStatus/ShippingMethod.
Изменить импорт:
-import { orders, orderItems, customers, PaymentMethod, PaymentStatus, ShippingMethod } from "@qco/db/schema"; +import { orders, orderItems, customers } from "@qco/db/schema";И приведения типов в values:
- paymentMethod: orderData.paymentMethod as typeof PaymentMethod[keyof typeof PaymentMethod] | undefined, - shippingMethod: orderData.shippingMethod as typeof ShippingMethod[keyof typeof ShippingMethod] | undefined, + paymentMethod: orderData.paymentMethod as typeof orders.$inferInsert["paymentMethod"] | undefined, + shippingMethod: orderData.shippingMethod as typeof orders.$inferInsert["shippingMethod"] | undefined,- paymentStatus: orderData.paymentStatus as typeof PaymentStatus[keyof typeof PaymentStatus] | undefined, + paymentStatus: orderData.paymentStatus as typeof orders.$inferInsert["paymentStatus"] | undefined,
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
packages/api/src/router/orders/create.ts
(2 hunks)packages/api/src/router/orders/get-by-customer.ts
(3 hunks)packages/api/src/router/orders/list.ts
(2 hunks)packages/api/src/router/product-attribute-values/upsert.ts
(2 hunks)packages/config/package.json
(1 hunks)packages/web-api/src/router/products/get-new.ts
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/web-api/src/router/products/get-new.ts
🧰 Additional context used
📓 Path-based instructions (10)
packages/api/**/*.ts
📄 CodeRabbit Inference Engine (.cursor/rules/api.mdc)
packages/api/**/*.ts
: Import schemas from @qco/db/schema, e.g., import { Category, ProductCategory } from "@qco/db/schema";
Import functions like eq, sql from @qco/db, e.g., import { eq, sql } from "@qco/db";
Use Zod for input and output validation, importing from @qco/validators.
Use TRPCError for consistent error handling across all routes.
Files:
packages/api/src/router/product-attribute-values/upsert.ts
packages/api/src/router/orders/list.ts
packages/api/src/router/orders/create.ts
packages/api/src/router/orders/get-by-customer.ts
packages/api/src/router/**/*.ts
📄 CodeRabbit Inference Engine (.cursor/rules/api.mdc)
Use ctx for database access in tRPC routes to ensure consistent data handling.
Files:
packages/api/src/router/product-attribute-values/upsert.ts
packages/api/src/router/orders/list.ts
packages/api/src/router/orders/create.ts
packages/api/src/router/orders/get-by-customer.ts
packages/api/src/router/*/*.ts
📄 CodeRabbit Inference Engine (.cursor/rules/api.mdc)
Each tRPC route should be in a separate file within a group folder under packages/api/src/router/{group-name}/, named {action}.ts (e.g., create.ts, list.ts, update.ts, delete.ts).
Files:
packages/api/src/router/product-attribute-values/upsert.ts
packages/api/src/router/orders/list.ts
packages/api/src/router/orders/create.ts
packages/api/src/router/orders/get-by-customer.ts
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
**/*.{ts,tsx}
: Use strict typing in TypeScript and avoidany
.
Use environment variables or@t3-oss/env-core
for experimental feature flags.
Files:
packages/api/src/router/product-attribute-values/upsert.ts
packages/api/src/router/orders/list.ts
packages/api/src/router/orders/create.ts
packages/api/src/router/orders/get-by-customer.ts
{packages/web-api/**,packages/api/**,packages/web-validators/**,packages/validators/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
Use the same Zod schemas on both frontend and backend. Import schemas from
/packages/web-validators
(for web) and/packages/validators
(for app) to guarantee unified validation and type safety.
Files:
packages/api/src/router/product-attribute-values/upsert.ts
packages/api/src/router/orders/list.ts
packages/api/src/router/orders/create.ts
packages/api/src/router/orders/get-by-customer.ts
{packages/web-api/**,packages/api/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
The server must prepare and return clear, frontend-ready data structures. All necessary transformations and formatting should be performed on the server, so that the frontend receives data in the exact shape it needs.
Files:
packages/api/src/router/product-attribute-values/upsert.ts
packages/api/src/router/orders/list.ts
packages/api/src/router/orders/create.ts
packages/api/src/router/orders/get-by-customer.ts
{packages/web-api/**,packages/api/**,packages/lib/**}
📄 CodeRabbit Inference Engine (.cursor/rules/code.mdc)
Keep business logic decoupled in
/packages/web-api
,/packages/api
, or/packages/lib
.
Files:
packages/api/src/router/product-attribute-values/upsert.ts
packages/api/src/router/orders/list.ts
packages/api/src/router/orders/create.ts
packages/api/src/router/orders/get-by-customer.ts
**/*.ts
📄 CodeRabbit Inference Engine (.windsurfrules)
Use Zod for validation.
Files:
packages/api/src/router/product-attribute-values/upsert.ts
packages/api/src/router/orders/list.ts
packages/api/src/router/orders/create.ts
packages/api/src/router/orders/get-by-customer.ts
⚙️ CodeRabbit Configuration File
**/*.ts
: ОСНОВНЫЕ ПРИНЦИПЫ РАЗРАБОТКИ:
Именование и стиль кода:
- Имена файлов обязательно в kebab-case (например: my-component.ts, user-profile.tsx)
- Функции в camelCase, компоненты в PascalCase, константы в UPPER_SNAKE_CASE
- Имена переменных и функций должны четко отражать их назначение и реализацию
- Избегайте сокращений и аббревиатур в именах (кроме общепринятых)
- Поддерживайте консистентность в стиле кода (отступы, пробелы, переносы строк)
- Следуйте принципам чистого кода (DRY, SOLID, KISS)
- Используйте осмысленные имена для булевых переменных (isLoading, hasPermission, canEdit)
TypeScript и типизация:
- Используйте строгую типизацию и избегайте any, unknown и {} где это возможно
- Правильно применяйте дженерики, интерфейсы и типы
- Обеспечивайте корректные определения типов для параметров функций и возвращаемых значений
- Предпочитайте union и intersection типы сложным условным конструкциям
- Используйте утилитарные типы TypeScript (Pick, Omit, Partial, Required)
- Создавайте переиспользуемые типы и интерфейсы
- Избегайте дублирования типов, выносите общие типы в отдельные файлы
Соблюдение правил линтера:
- Следуйте правилам ESLint для React и TypeScript
- Соблюдайте рекомендации Biome по форматированию и анализу кода
- Убедитесь, что код не содержит предупреждений или ошибок линтера
- Используйте автоматическое форматирование кода
Алгоритмы и производительность:
- Пишите понятные и читаемые алгоритмы, которые могут понять другие разработчики
- Оптимизируйте сложность алгоритмов (временную и пространственную)
- Избегайте чрезмерной вложенности и сложности
- Правильно обрабатывайте граничные случаи и ошибки
- Используйте подходящие структуры данных для задач
- Применяйте мемоизацию где это уместно
Безопасность и стабильность:
- Реализуйте правильную валидацию входных данных и защиту от инъекций
- Корректно обрабатывайте ошибки и исключения
- Обеспечивайте...
Files:
packages/api/src/router/product-attribute-values/upsert.ts
packages/api/src/router/orders/list.ts
packages/api/src/router/orders/create.ts
packages/api/src/router/orders/get-by-customer.ts
**/*.json
⚙️ CodeRabbit Configuration File
**/*.json
: РАБОТА С JSON ФАЙЛАМИ:
Структура и форматирование:
- Используйте правильное форматирование JSON
- Поддерживайте консистентную структуру
- Используйте осмысленные ключи
- Избегайте дублирования данных
Валидация:
- Убедитесь в корректности JSON синтаксиса
- Проверяйте типы данных
- Валидируйте обязательные поля
Безопасность:
- Не включайте конфиденциальные данные
- Используйте переменные окружения для секретов
- Валидируйте входящие JSON данные
Files:
packages/config/package.json
**/package.json
⚙️ CodeRabbit Configuration File
**/package.json
: УПРАВЛЕНИЕ ЗАВИСИМОСТЯМИ:
Версионирование:
- Используйте семантическое версионирование
- Избегайте уязвимых версий пакетов
- Регулярно обновляйте зависимости
Структура:
- Правильно организуйте scripts
- Разделяйте dependencies и devDependencies
- Используйте точные версии для критических пакетов
Безопасность:
- Проверяйте пакеты на уязвимости
- Используйте только проверенные пакеты
- Регулярно аудируйте зависимости
Files:
packages/config/package.json
🧠 Learnings (9)
📚 Learning: 2025-08-01T07:58:07.363Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/web-api.mdc:0-0
Timestamp: 2025-08-01T07:58:07.363Z
Learning: Applies to apps/web/**/*.tsx : Import Drizzle ORM functions like eq, sql from qco/db, e.g., import { eq, sql } from "qco/db";
Applied to files:
packages/api/src/router/orders/create.ts
packages/api/src/router/orders/get-by-customer.ts
📚 Learning: 2025-08-01T07:57:06.890Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/api.mdc:0-0
Timestamp: 2025-08-01T07:57:06.890Z
Learning: Applies to packages/api/**/*.ts : Import functions like eq, sql from qco/db, e.g., import { eq, sql } from "qco/db";
Applied to files:
packages/api/src/router/orders/create.ts
packages/api/src/router/orders/get-by-customer.ts
📚 Learning: 2025-08-01T07:58:22.450Z
Learnt from: CR
PR: qcohq/qco#0
File: .windsurfrules:0-0
Timestamp: 2025-08-01T07:58:22.450Z
Learning: Applies to packages/db/**/*.{ts,js} : Database schemas are defined in `qco/db`.
Applied to files:
packages/api/src/router/orders/create.ts
packages/api/src/router/orders/get-by-customer.ts
packages/config/package.json
📚 Learning: 2025-08-01T07:57:06.890Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/api.mdc:0-0
Timestamp: 2025-08-01T07:57:06.890Z
Learning: Applies to packages/api/**/*.ts : Use TRPCError for consistent error handling across all routes.
Applied to files:
packages/api/src/router/orders/create.ts
packages/api/src/router/orders/get-by-customer.ts
📚 Learning: 2025-08-01T07:58:22.450Z
Learnt from: CR
PR: qcohq/qco#0
File: .windsurfrules:0-0
Timestamp: 2025-08-01T07:58:22.450Z
Learning: Applies to backend/**/*.{ts,js} : Use Drizzle ORM for database operations.
Applied to files:
packages/api/src/router/orders/create.ts
packages/api/src/router/orders/get-by-customer.ts
📚 Learning: 2025-08-01T07:57:06.890Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/api.mdc:0-0
Timestamp: 2025-08-01T07:57:06.890Z
Learning: Applies to packages/api/**/*.ts : Import schemas from qco/db/schema, e.g., import { Category, ProductCategory } from "qco/db/schema";
Applied to files:
packages/api/src/router/orders/create.ts
📚 Learning: 2025-08-01T07:58:22.450Z
Learnt from: CR
PR: qcohq/qco#0
File: .windsurfrules:0-0
Timestamp: 2025-08-01T07:58:22.450Z
Learning: Applies to backend/**/*.{ts,js} : Use Drizzle for database access.
Applied to files:
packages/api/src/router/orders/create.ts
📚 Learning: 2025-08-01T07:58:07.363Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/web-api.mdc:0-0
Timestamp: 2025-08-01T07:58:07.363Z
Learning: Applies to apps/web/**/*.tsx : Use ctx for database access in tRPC routes to ensure consistent data handling
Applied to files:
packages/api/src/router/orders/get-by-customer.ts
📚 Learning: 2025-08-01T07:57:06.890Z
Learnt from: CR
PR: qcohq/qco#0
File: .cursor/rules/api.mdc:0-0
Timestamp: 2025-08-01T07:57:06.890Z
Learning: Applies to packages/api/**/*.ts : Use Zod for input and output validation, importing from qco/validators.
Applied to files:
packages/config/package.json
🧬 Code Graph Analysis (3)
packages/api/src/router/orders/list.ts (2)
packages/web-api/src/router/account/orders/get-order-detail.ts (2)
getVariantOptions
(20-50)acc
(91-94)packages/api/src/router/orders/by-id.ts (1)
combination
(38-42)
packages/api/src/router/orders/create.ts (2)
packages/web-validators/src/orders.ts (3)
PaymentMethod
(179-179)ShippingMethod
(178-178)PaymentStatus
(183-183)packages/web-api/src/lib/orders/order-helpers.ts (2)
createPaymentMethod
(543-550)tx
(235-243)
packages/api/src/router/orders/get-by-customer.ts (3)
packages/api/src/router/orders/update-status.ts (1)
input
(10-150)packages/api/src/router/orders/update-delivery-status.ts (1)
input
(9-111)packages/web-api/src/router/orders/get-orders.ts (1)
input
(22-154)
⏰ 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: Test API Package
🔇 Additional comments (10)
packages/config/package.json (1)
14-15
: files/sideEffects настроены корректно
"files": ["dist"]
ограничивает публикуемый набор, а"sideEffects": false
улучшает tree-shaking.packages/api/src/router/orders/get-by-customer.ts (4)
2-2
: Импорт eq/and из @qco/db — соответствует правилам репозитория.Это корректная миграция с drizzle-orm на пакетную реэкспорт-обёртку.
4-4
: Импорт схем из @qco/db/schema — ок.Соответствует гайдлайнам: схемы должны приходить из @qco/db/schema.
53-53
: Возможный breaking change: totalAmount сериализуется строкой. Проверьте согласованность API.В других эндпоинтах суммы отдаются числом (см. packages/api/src/router/account/orders/get-orders.ts — Number(order.totalAmount)). Если фронт ожидает число, текущее String(...) поломает типы/схемы.
Предлагаемый фикс (если договорённость — числа):
- totalAmount: String(order.totalAmount), + totalAmount: Number(order.totalAmount),Пожалуйста, подтвердите:
- что getOrdersByCustomerOutputSchema ожидает число (а не строку),
- и что типы согласованы с web-валидаторами.
56-56
: Нормализованная сериализация cancelledAt — ок.Явная проверка вместо
?. || null
делает намерение читаемым и не меняет поведение.packages/api/src/router/orders/create.ts (3)
2-2
: Импорт eq из @qco/db — ок.Соответствует принятым правилам импорта ORM-хелперов.
32-33
: Проверьте соответствие значения статуса enum’у в БД.Хардкод "pending" может не совпадать с реальным набором значений (например, "PENDING"). Лучше использовать enum из схемы или сузить литерал до типа столбца.
Варианты:
- Если в @qco/db/schema есть константа: OrderStatus.PENDING
- status: "pending", + status: OrderStatus.PENDING,
- Минимальный безопасный вариант (без импорта enum’а):
- status: "pending", + status: "pending" as typeof orders.$inferInsert["status"],Пожалуйста, подтвердите фактическое значение статуса и обновите при необходимости.
44-45
: paymentStatus теперь не дефолтится. Убедитесь, что это ожидаемо.Ранее значение по умолчанию могло быть "PENDING". Если фронт не присылает paymentStatus, проверьте:
- есть ли дефолт на уровне БД, или
- нужно ли здесь выставлять начальный статус явно.
Если нужен дефолт в коде:
- paymentStatus: orderData.paymentStatus as typeof orders.$inferInsert["paymentStatus"] | undefined, + paymentStatus: (orderData.paymentStatus ?? "PENDING") as typeof orders.$inferInsert["paymentStatus"],Иначе — задокументируйте, что поле может быть undefined, и синхронизируйте схему валидатора.
packages/api/src/router/orders/list.ts (2)
37-42
: Добавлена явная типизация параметров для улучшения читаемости кода.Хорошее изменение для обеспечения согласованности с другими частями кодовой базы. Аналогичная типизация применена в
packages/web-api/src/router/account/orders/get-order-detail.ts
иpackages/web-api/src/router/account/orders/get-orders.ts
.
143-145
: Добавлена явная типизация для callback функций в map.Изменения соответствуют паттерну явной типизации inline callback'ов, применяемому в других маршрутах. Это улучшает читаемость и согласованность кода.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Summary by CodeRabbit
Новые возможности
Исправления