Комментарии 17
Here are the real problems I found in a quick pass. Ordered roughly by impact.
High impact
SSR is broken — entire page is empty until hydration. src/app/ClientShell.tsx:35-37 returns null until hydrated === true. Since ClientShell wraps {children} in the root layout, every server-rendered HTML response is an empty
. You lose SEO, lose initial paint, and break crawlers — for a product catalog this is the worst of both worlds (SSG pages built but never sent to the client). Fix: render the tree on the server too, and only guard the truly client-only bits (theme class, drawer state).
/api/order trusts client-supplied totals. src/app/api/order/route.ts:21-66 validates types but never recomputes subtotal, deliveryCost, or total from the catalog. A client can POST { items: […], total: 0 } and pass
validation. Even as a mock, the shape of this API teaches the wrong pattern. Fix: look up prices server-side from getAllProducts() and ignore the client’s totals.Quantity is added by a loop instead of passed in. src/app/product/[slug]/ProductPageClient.tsx:38-40:
for (let i = 0; i < quantity; i++) { addItem(productData);
}
cartStore.addItem already takes a quantity argument (cartStore.ts:37). The loop triggers N store updates / N re-renders for one user action. Fix: addItem(product, quantity).mounted flag in ProductPageClient is wrong. ProductPageClient.tsx:23-29 uses useState(() => typeof window !== “undefined”). The lazy initializer runs once per render on each environment: false on the server, true on the very
first client render. That mismatch is exactly what causes hydration warnings — the standard fix is useState(false) + useEffect(() => setMounted(true), []). Right now you may be papering over a hydration error rather than avoiding it.
Medium
Double error toast on contact form failure. ContactForm.tsx:83-87 toasts “Ошибка отправки”, but the page-level handleSubmit (contact/page.tsx:27-33) already toasted “Ошибка валидации” with the field list. User sees two toasts. Pick one layer to own error UI.
cartStore.migrate mutates its input and returns the wrong type. cartStore.ts:118-127 casts persistedState to Record<string, unknown>, mutates it, and returns it as unknown. The signature should be (state, version) => CartState. Mutating persistedState is also brittle — return a new object.
Hardcoded 5 for delivery cost in two places. cartStore.ts:107 (getDeliveryCost) and cart/CartPageClient.tsx:139 (). They will drift. Single source of truth.
Module-level products cache never invalidates. lib/products.ts:20 keeps the parsed Markdown in memory forever per server instance. Fine for prod SSG, but in next dev you’ll edit a .md file and not see the change without a
server restart unless clearProductsCache is called.Redundant store calls re-run on every state change. cart/CartPageClient.tsx:31-33:
const subtotal = useCartStore((state) => state.getSubtotal()); The selector recomputes for every change anywhere in the store (delivery toggles, etc.), and Zustand re-renders only because the result is shallow-equal. Works for primitives, dangerous if you ever return an object. Cleaner: const items = useCartStore(s => s.items) and compute subtotal locally with useMemo.
Minor
package.json name is “pinapple-pi-2.0” (missing a p) — directory and project name are pineapple-pi-2.0.
Three files use eslint-disable react-hooks/set-state-in-effect (ClientShell.tsx, Header.tsx, CookieBanner.tsx). The pattern they’re disabling — setState inside useEffect to mark “hydrated” — is the same SSR anti-pattern as #1; the lint rule is telling you something real.
src/app/favicon.ico and metadata.icons.icon: “/favicon.svg” both exist; Next will auto-pick favicon.ico for / while metadata insists on .svg. Pick one.
ProductCard.tsx:58-68 wraps a
marked token cast in lib/markdown.ts:109 (as import(“marked”).Tokens.List & { items: … }) — fragile if marked changes shapes. Use the official Tokens.ListItem type.
The top three (SSR, server-side price trust, quantity loop) are the ones I’d fix first. Want me to patch any of them?
>За 4 дня работы удалось сделать вполне нормальный фронт для Интернет-магазина
выглядит может и нормально, а под капотом, судя по всему не очень. в целом, фронт нейросети уже давно делают, что с бэком, деплоем, интеграциями?
Фронт нормально они научились не так и давно.
Ну так посмотрите код, ссылку на репо я оставил и после этого уже можете говорить, что под капотом "не очень". Я так понимаю ревью вы тоже провели нейросетью.
А не пытались сравнить с написанием одним LLM, есть ли смысл в этой своре агентов?
Метрики. Время создания, стоимость, качество, вмешательство человека
Судя по таймингу вы больше боролись со сворой агентов, чем решали практические задачи
LLM была одна - Qwen3.6 Plus, просто несколько ролей, с которыми я работал последовательно. Время создания я указал в статье. Вмешательство от меня было не сильно большим (15% правок). Скорей это немного утомительно - постоянно проводить ревью.
Есть большая необходимость назначать роли и использовать субагентов.
Субагент работает только в своём контекстном окне и строго по своим правилам. Делая ревью таким образом, он находит массу ошибок после условного субагента кодера.
Параграф Цитата Удалить Параграф Цитата Удалить а откуда новость про закрытие доступа? Вы через что подключались? Почему именно cli, а не готовая Lingma IDE от Alibaba?
Так Qwen CLI больше не работает через OAuth. Только через токены, а это дорого.
Ну 4 дня активные работы не выглядит как прорыв от ии автоматизации, и сайт выглядит обычно.
Какие MCP подключали? Каждому агенту свой? Или что-то общее? Что посоветуете?
Вопрос номер раз, вы общались с Агентами в терминале через это узинькое окошко в 2 строки на протяжении всего проекта?
Ставил qwen cli, но все попытки подключить его к телеге как openclaw не увенчались успехом. А работать просто в терминала, с телефона, прям неудобно
Хотелось бы уточнить по агентам - это точно были несколько агентов с разделением контекста и т.д или это был один агент со сменой ролей? Как вообще достигается это разделение? Знаю что по фолдерам можно md разбросать - этого достаточно?

Разработка фронтенда интернет-магазина через Qwen 3.6 Plus и Qwen ClI