TuBrief
구독 채널
비디오
커뮤니티

Как безопасно интегрировать UI-код, созданный Claude Code, в существующий проект

TuBrief 편집팀
2026년 9월 12일
0
Computing/Software

원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.

Русский한국어EnglishEspañol中文हिन्दीDeutschFrançaisالعربيةPortuguêsBahasa Indonesia日本語

관련 영상

Claude Code получил крупнейшее обновление дизайна за год (и вот как им овладеть)10:58

Claude Code получил крупнейшее обновление дизайна за год (и вот как им овладеть)

Chase AI

커뮤니티의 다른 글

사내 시스템에 llm api 붙일 때 마주하는 현실적인 한계와 대응법

2026년 9월 13일

레거시 백엔드에 GPT-6 Astra 붙일 때 예산 승인과 보안 통과를 먼저 끝내는 법이 있습니다

2026년 9월 13일

에이전트끼리 대화하다 6천만 원 청구서가 나오는 이유

2026년 9월 13일

사내 RAG 벡터 검색에 Okta 권한 필터를 직접 거는 방법

2026년 9월 13일

브라우저 에이전트에게 내 구글 계정을 통째로 넘기면 안 되는 이유

2026년 9월 12일

Apple Won the AI Race

2026년 9월 12일

댓글 (0)

Log in to leave a comment

아직 작성된 글이 없습니다

© 2026 . All rights reserved.

TuBrief
구독 채널
비디오
커뮤니티
로그인

Как безопасно интегрировать UI-код, созданный Claude Code, в существующий проект

Запустив Claude Code в терминале и введя /design, можно получить черновик интерфейса всего за пару секунд. Для разработчика-одиночки это удобно, так как экономит силы. Проблема начинается в тот момент, когда этот код открывают.

Инструмент совершенно не обращает внимания на компоненты shadcn/ui, которые уже настроены в проекте, и генерирует новые «сырые» теги <button>. Вместо семантических цветов из палитры он разбрасывает по файлам произвольные шестнадцатеричные коды вроде bg-[#1e293b]. На создание каждого экрана уходит по 40 минут только на то, чтобы исправить поврежденные пути импорта и удалить инлайн-стили.

Это не просто ощущение. Согласно исследованию GitClear за 2024 год, в котором проанализировали 211 миллионов строк коммитов, после внедрения ИИ-инструментов доля кода, который полностью выбрасывается или переписывается в течение двух недель, выросла почти вдвое — с 3.1% до 5.7%. Доля рефакторинга упала с 25% ниже 10%. Технический долг растет с той же скоростью, с какой увеличивается объем кода. Стоит оставить надежду на то, что модель сама будет соблюдать существующую дизайн-систему, и связать ей руки на системном уровне.


Фиксация путей компонентов с помощью файла правил проекта

Причина, по которой Claude Code игнорирует существующий код, проста. Чтобы сэкономить контекстное окно, он просматривает только необходимые файлы выборочно. Без каких-либо ограничений модель собирает экраны из самых примитивных HTML-тегов.

Файлы конфигурации в корне сеанса сохраняются на уровне около 10% от базовой стоимости ввода благодаря кэшированию промптов. Они не исчезают даже при сбросе или сжатии диалога. Если прописать здесь правила повторного использования компонентов, можно предотвратить генерацию моделью произвольных «сырых» тегов.

Пути к общим компонентам и правила стилизации прописываются в файле CLAUDE.md в корне проекта.

`markdown

Design System Guidelines

  1. Component Reuse (STRICT)
  • DO NOT use raw DOM tags (, , ).
  • MUST import from @/components/ui:
    • Button: import { Button } from "@/components/ui/button"
    • Input: import { Input } from "@/components/ui/input"
    • Card: import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"
    • Dialog: import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"
  • If a component does not exist in @/components/ui, ask to run: "npx shadcn@latest add ".
  1. Token Boundaries
  • NEVER use arbitrary hex codes or pixel widths: NO bg-[#...], NO w-[...px].
  • Use Semantic CSS variables:
    • Surfaces: bg-background, bg-card, bg-muted
    • Text: text-foreground, text-muted-foreground, text-primary
    • Borders: border-border, border-input

`

Нет необходимости каждый раз передавать в промпт целиком глобальный CSS-файл на тысячи строк. Достаточно выбрать имена токенов из конфигурации Tailwind и выгрузить их в формате JSON.

`javascript
// scripts/extract-tokens.mjs
import fs from 'fs';
import resolveConfig from 'tailwindcss/resolveConfig.js';
import tailwindConfig from '../tailwind.config.js';

const fullConfig = resolveConfig(tailwindConfig);
const semanticTokens = {
colors: Object.keys(fullConfig.theme.colors || {}).filter(
(name) => !['inherit', 'current', 'transparent'].includes(name)
),
spacing: Object.keys(fullConfig.theme.spacing || {}),
borderRadius: Object.keys(fullConfig.theme.borderRadius || {}),
};

if (!fs.existsSync('.claude')) {
fs.mkdirSync('.claude');
}

fs.writeFileSync(
'.claude/design-tokens.json',
JSON.stringify(semanticTokens, null, 2)
);

`

Этот скрипт добавляется в секции postinstall и predev файла package.json.

`json
{
"scripts": {
"postinstall": "node scripts/extract-tokens.mjs",
"predev": "node scripts/extract-tokens.mjs"
}
}

`

Список доступных классов обновляется при каждой сборке. Ручное время, ранее уходившее на исправление ошибочных классов стилей, сокращается до нуля.


Автоматическая замена произвольных стилей с помощью хук-скриптов

Сколько бы предупреждений ни было указано в промпте, модель время от времени выдает некорректные значения. Если передать ей скриншот и попросить создать экран, она подстраивается под пропорции изображения и жестко прописывает фиксированную ширину вроде w-[380px]. Это главная причина возникновения горизонтальной прокрутки на мобильных устройствах.

Чтобы соответствовать стандартам WCAG 2.1 AA, необходимо четко указывать стандарты для каждого разрешения и проводить принудительную проверку линтером сразу после создания файла.

Область проверки Целевой стандарт Обязательные классы Tailwind Условия блокировки
Мобильные 390px (base) flex-col, w-full, grid-cols-1 Горизонтальная прокрутка из-за фиксированной ширины w-[...px]
Планшеты 768px (md:) md:flex-row, md:grid-cols-2, md:p-6 Сохранение одноколоночной мобильной структуры на широких экранах
Десктопы 1440px (xl:) xl:max-w-7xl, mx-auto, xl:grid-cols-4 Неограниченное расширение контейнера макета на высоком разрешении
Темная тема Селектор .dark bg-background, text-foreground Использование стандартных классов вроде bg-white, text-black в одиночку
Доступность WCAG 2.1 AA aria-label, <main>, focus-visible:ring-2 Отсутствие альтернативного текста для скринридеров у кнопок-иконок

Для контроля непослушной модели надежнее всего использовать хуки жизненного цикла. Хук PostToolUse в Claude Code позволяет запускать скрипт сразу после записи файла на диск.

Команда хука регистрируется в .claude/settings.json.

`json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/ast-lint-guard.mjs",
"timeout": 30
}
]
}
]
}
}

`

Затем создается скрипт проверки. С помощью регулярных выражений распространенные шестнадцатеричные коды заменяются на токены проекта, а плагин Tailwind ESLint обеспечивает соблюдение правил.

`javascript
// .claude/hooks/ast-lint-guard.mjs
import fs from 'fs';
import readline from 'readline';
import { execSync } from 'child_process';

const rl = readline.createInterface({ input: process.stdin });
let inputBuffer = '';

rl.on('line', (line) => { inputBuffer += line; });
rl.on('close', () => {
try {
const payload = JSON.parse(inputBuffer);
const filePath = payload.tool_input?.file_path || payload.tool_input?.path;

if (!filePath || !/\.(tsx|jsx)$/.test(filePath) || !fs.existsSync(filePath)) {
  process.exit(0);
}

let code = fs.readFileSync(filePath, 'utf-8');
let changed = false;

const replacementMap = {
  '#ffffff': 'bg-background',
  '#000000': 'text-foreground',
  '#020817': 'bg-background',
  '#0f172a': 'bg-card',
  '#1e293b': 'bg-muted',
  '#64748b': 'text-muted-foreground',
  '#2563eb': 'bg-primary',
};

for (const [hex, token] of Object.entries(replacementMap)) {
  const regex = new RegExp(`(bg|text|border)-\-[${hex}\]`, 'gi');
  if (regex.test(code)) {
    code = code.replace(regex, token);
    changed = true;
  }
}

if (changed) {
  fs.writeFileSync(filePath, code, 'utf-8');
}

execSync(`npx eslint "${filePath}" --rule "tailwindcss/no-arbitrary-value: error"`, {
  stdio: 'pipe',
});

process.exit(0);

} catch (error) {
const failureLog = error.stdout?.toString() || error.stderr?.toString() || error.message;
console.error([Lint Pipeline Block] Нарушение правил стилизации:\n${failureLog});
process.exit(1);
}
});

`

Плагин линтера устанавливается в проект.

`bash
npm install -D eslint-plugin-tailwindcss

`

Если скрипт возвращает код завершения 1, Claude Code считывает лог ошибки и на следующем этапе исправляет код с использованием семантических классов. Это сокращает время борьбы с поврежденным дизайном на этапе QA.


Физическое отделение представлений от бизнес-логики

При поручении Claude Code создания экрана он часто смешивает в одном файле функцию fetch, огромные объекты с фиктивными данными и JSX. Для последующего подключения реального API приходится переписывать даже код рендеринга.

Код интерфейса не должен знать о способах изменения состояния. Безопаснее разделять одну директорию функционала на 4 файла и предварительно фиксировать схемы данных.

Сначала определяется структура данных.

`typescript
// src/components/features/dashboard-card/schema.ts
import { z } from "zod";

export const MetricItemSchema = z.object({
id: z.string(),
label: z.string(),
value: z.string(),
changePercentage: z.number(),
trend: z.enum(["up", "down", "neutral"]),
});

export const DashboardCardSchema = z.object({
title: z.string().min(1),
metrics: z.array(MetricItemSchema),
});

export type DashboardCardData = z.infer;

export interface DashboardCardViewProps {
data: DashboardCardData;
isLoading?: boolean;
onActionClick?: (metricId: string) => void;
}

`

Затем при вызове Claude Code в терминале строго запрещается использование внутреннего состояния.

`bash
claude "Создай чистый UI-компонент src/components/features/dashboard-card/dashboard-card-view.tsx, реализующий DashboardCardViewProps из src/components/features/dashboard-card/schema.ts. Ни в коем случае не используй внутри useState, useEffect и fetch, делай интерфейс адаптивным, используя исключительно переданные Props и элементы @/components/ui."

`

Для подключения данных используется хук. Мок-данные и функции вызова реального API создаются в единой структуре.

`typescript
// src/components/features/dashboard-card/use-dashboard-card.ts
import { useQuery } from "@tanstack/react-query";
import { DashboardCardData } from "./schema";

const MOCK_DATA: DashboardCardData = {
title: "Месячные показатели активности",
metrics: [
{ id: "m-1", label: "Новый приток", value: "1,240 чел.", changePercentage: 12.5, trend: "up" },
{ id: "m-2", label: "Показатель отказов", value: "2.1%", changePercentage: -0.4, trend: "down" },
],
};

export const useDashboardCard = (cardId: string, useMock = false) => {
return useQuery({
queryKey: ["dashboard-card", cardId],
queryFn: async () => {
if (useMock) {
return MOCK_DATA;
}
const res = await fetch(/api/dashboard/${cardId});
if (!res.ok) throw new Error("Не удалось получить данные");
return res.json();
},
});
};

`

Они объединяются в компоненте-контейнере.

`typescript
// src/components/features/dashboard-card/index.tsx
"use client";

import React from "react";
import "./dashboard-card-view";
import { useDashboardCard } from "./use-dashboard-card";

export function DashboardCardContainer({ cardId, useMock = false }: { cardId: string; useMock?: boolean }) {
const { data, isLoading } = useDashboardCard(cardId, useMock);

if (!data) return null;

return (
<DashboardCardView
data={data}
isLoading={isLoading}
onActionClick={(id) => console.log(id)}
/>
);
}

`

До появления бэкенда интерфейс дорабатывается с флагом useMock={true}. После завершения работы над API флаг просто удаляется. Код представлений не потребует никаких изменений.


Изоляция рабочего дерева и выборочный перенос изменений

В ходе долгого диалога с моделью в терминале и экспериментов с интерфейсом нередко оказывается, что поврежден исправный файл глобальной конфигурации, а по всей директории разбросаны временные файлы. Удобнее создавать директорию исключительно для экспериментов, оставляя рабочее пространство нетронутым.

Git worktree позволяет запускать Claude Code в полностью изолированной папке.

`bash
git worktree add ../saas-ui-sandbox -b experiment/ai-dashboard-ui
cd ../saas-ui-sandbox
claude

`

Если эксперимент провалился, папку можно без сомнений удалить целиком.

`bash
cd ../saas-platform
git worktree remove ../saas-ui-sandbox --force
git branch -D experiment/ai-dashboard-ui

`

Если результат устраивает, ветку не стоит объединять целиком — лучше перенести только фрагменты кода файла представления в интерактивном режиме.

`bash
git checkout main
git checkout -p experiment/ai-dashboard-ui -- src/components/features/dashboard-card/dashboard-card-view.tsx

`

Просматривая блоки кода в терминале, можно нажимать y для подходящих частей и n для отклонения странных правок.

Если сессия превышает 5 шагов, контекст размывается, и модель начинает выдавать бессмыслицу. Сессии необходимо регулярно упорядочивать.

  1. Проверка типов: после создания отдельного компонента сразу запускается npx tsc --noEmit. Переход к следующему промпту возможен только при нуле ошибок типизации.
  2. Сжатие контекста: при удлинении диалога без колебаний вводится /compact для уменьшения расхода токенов.
  3. Очистка сеанса: по завершении работы над экраном создается коммит, а память полностью очищается командой /clear. При путанице с помощью /rewind можно вернуться к предыдущей контрольной точке.

Высокие способности модели к генерации кода и пригодность этого кода для продакшена — совершенно разные вещи. Ограничение входных путей через CLAUDE.md, проверка выходного кода с помощью хуков жизненного цикла и разделение рабочей среды через worktree позволяют избежать ночных исправлений кода, сгенерированного ИИ.