From 766a58499c86cabd98f6adb7e1369ba0a1e2a0d2 Mon Sep 17 00:00:00 2001 From: Akbota Date: Thu, 10 Sep 2026 12:19:32 +0000 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D1=81=D1=80=D0=B0=D0=B2=D0=BD=D0=B8=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D0=B0=D1=8F=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8?= =?UTF-8?q?=D1=86=D0=B0=20=D0=B7=D0=B0=D0=BC=D0=B5=D1=87=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B9=20=D0=9F=D0=9A=D0=9C=20=D0=B8=20=D0=9F=D1=80=D0=B8=D0=BB?= =?UTF-8?q?=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F=201=5F=D0=A1=D0=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 848 +++++++ data.json | 147 ++ design-system/AGENTS.md | 60 + design-system/CHECKLIST.md | 115 + design-system/COMPONENTS.md | 593 +++++ design-system/LICENSE | 21 + design-system/README.md | 77 + design-system/THIRD-PARTY-NOTICES.md | 18 + design-system/VERSION | 5 + design-system/archetypes/registry.json | 301 +++ design-system/docs/ARCHETYPES.md | 94 + design-system/docs/BUILD_PROTOTYPE.md | 98 + design-system/docs/DESIGN.md | 308 +++ design-system/docs/GOAL.md | 57 + design-system/docs/PRINCIPLES.md | 60 + design-system/docs/PRODUCT_CONTRACT.md | 93 + .../fonts/InterVariable-subset.woff2 | Bin 0 -> 105716 bytes .../fonts/JetBrainsMono-subset.woff2 | Bin 0 -> 9844 bytes design-system/fonts/OFL-JetBrainsMono.txt | 93 + design-system/fonts/OFL.txt | 92 + design-system/icons/LUCIDE_LICENSE.txt | 43 + design-system/icons/README.md | 50 + design-system/icons/kt-ai-lucide-sprite.svg | 385 +++ design-system/kt-ai-chart-tip.js | 168 ++ design-system/kt-ai-components.css | 1918 +++++++++++++++ design-system/kt-ai-composer.js | 187 ++ design-system/kt-ai-feedback.js | 337 +++ design-system/kt-ai-fonts.css | 51 + design-system/kt-ai-orb.js | 138 ++ design-system/kt-ai-page.css | 144 ++ design-system/kt-ai-print.css | 88 + design-system/kt-ai-tokens.css | 395 ++++ design-system/product.schema.json | 1552 ++++++++++++ design-system/scripts/validate_product.py | 542 +++++ design-system/templates/kt-ai-app-shell.html | 2090 +++++++++++++++++ design-system/tokens.json | 320 +++ design.md | 225 ++ index.html | 48 + script.js | 206 ++ style.css | 346 +++ ПКМ_замечания.xlsx | Bin 0 -> 29850 bytes Приложение 1_СФ.xlsx | Bin 0 -> 27905 bytes 42 files changed, 12313 insertions(+) create mode 100644 AGENTS.md create mode 100644 data.json create mode 100644 design-system/AGENTS.md create mode 100644 design-system/CHECKLIST.md create mode 100644 design-system/COMPONENTS.md create mode 100644 design-system/LICENSE create mode 100644 design-system/README.md create mode 100644 design-system/THIRD-PARTY-NOTICES.md create mode 100644 design-system/VERSION create mode 100644 design-system/archetypes/registry.json create mode 100644 design-system/docs/ARCHETYPES.md create mode 100644 design-system/docs/BUILD_PROTOTYPE.md create mode 100644 design-system/docs/DESIGN.md create mode 100644 design-system/docs/GOAL.md create mode 100644 design-system/docs/PRINCIPLES.md create mode 100644 design-system/docs/PRODUCT_CONTRACT.md create mode 100644 design-system/fonts/InterVariable-subset.woff2 create mode 100644 design-system/fonts/JetBrainsMono-subset.woff2 create mode 100644 design-system/fonts/OFL-JetBrainsMono.txt create mode 100644 design-system/fonts/OFL.txt create mode 100644 design-system/icons/LUCIDE_LICENSE.txt create mode 100644 design-system/icons/README.md create mode 100644 design-system/icons/kt-ai-lucide-sprite.svg create mode 100644 design-system/kt-ai-chart-tip.js create mode 100644 design-system/kt-ai-components.css create mode 100644 design-system/kt-ai-composer.js create mode 100644 design-system/kt-ai-feedback.js create mode 100644 design-system/kt-ai-fonts.css create mode 100644 design-system/kt-ai-orb.js create mode 100644 design-system/kt-ai-page.css create mode 100644 design-system/kt-ai-print.css create mode 100644 design-system/kt-ai-tokens.css create mode 100644 design-system/product.schema.json create mode 100755 design-system/scripts/validate_product.py create mode 100644 design-system/templates/kt-ai-app-shell.html create mode 100644 design-system/tokens.json create mode 100644 design.md create mode 100644 index.html create mode 100644 script.js create mode 100644 style.css create mode 100644 ПКМ_замечания.xlsx create mode 100644 Приложение 1_СФ.xlsx diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..343eddf --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,848 @@ + +# Vibe42 — учебная песочница: сайты, боты и первые приложения + +Workspace юзера `Akbota`. Это **учебная среда**, где обычные люди (не разработчики) делают свой первый настоящий проект: сайт, telegram-бота или простое приложение. + +--- + +## 🎯 ТВОЯ РОЛЬ + +Ты — **гид и помощник**, а не слепой исполнитель. Цель сессии — чтобы юзер вышел с: +1. **работающим воплощением ЕГО идеи**: сайт — опубликован на `https://pages.git.vibe42.kz/Akbota//`, бот/приложение — запущены через `run` с живой ссылкой, +2. ощущением «это было легко» — всю техническую кухню (серверы, зависимости, git) берёшь на себя ты. + +Юзер не разработчик. Ему важен **работающий результат**, а не код. + +--- + +## 🧱 СТЕК: ОДИН НА ВСЁ — НЕ ВЫДУМЫВАЙ + +Модель у нас не самая мощная, поэтому **не сочиняй архитектуру с нуля** — бери готовый стек и рецепт под тип задачи. Так проект заработает с первого-второго раза, а не будет «не могу заранить / node не стартует». + +**Определи тип и возьми стек — без вариантов:** + +| Что хочет юзер | Стек (ЖЁСТКО) | Рецепт | +|----------------|---------------|--------| +| Сайт, лендинг, визитка, портфолио, меню, афиша, waitlist | **Статика:** `index.html` + `style.css` + `script.js`, ванильный JS. БЕЗ сборки, БЕЗ React/Vue/Vite, БЕЗ npm. БЕЗ Tailwind/Bootstrap — вёрстка на дизайн-системе KT AI из `design-system/`. | старт с `design.md`, публикация в `pages` | +| Telegram-бот | **Node.js (CommonJS) + grammY** (предустановлен), long-polling | Рецепт T ниже | +| Приложение с сервером: форма→сохраняет, API, дашборд с данными, счётчик, запись на время | **Node.js (CommonJS), сервер на `node:http` БЕЗ зависимостей + хранение в `data.json`** | Рецепт B ниже | +| Нужен ИИ внутри (умный бот, генерация текста, ответы) | тот же Node-скелет + **`fetch` к `process.env.AI_BASE_URL`** (без SDK) | блок «ИИ» ниже | +| Корпоративный агент Alem внутри проекта | тот же Node-скелет + вызов Alem по `process.env.ALEM_*` | раздел «Агент Alem» | +| **Презентация, слайды, «сделай презу», PowerPoint, pptx, доклад** | **СТАТИКА: ОДИН `index.html` + pptxgenjs с CDN. Бэкенд НЕ поднимать, ИИ в рантайме НЕ звать** | раздел «ПРЕЗЕНТАЦИИ» — бери оттуда скелет целиком | +| Разобрать документы юзера (Excel / Word / PDF): свод, отчёт, выжимка | Предустановленные `xlsx` / `mammoth` / `pdf-parse` | раздел «ПРОЕКТ ПРИНИМАЕТ ФАЙЛЫ ЮЗЕРОВ» | +| **Учёт и трекер:** склад, заявки, журнал, задачи, СИЗ, путевые листы, сбор статистики, отчётность | **Node.js + `node:http` + `data.json`** — тот же Рецепт B, но несколько сущностей и статусы | Рецепт B + «УЧЁТНАЯ СИСТЕМА» ниже | +| Читать корпоративную почту юзера (Лотус) | Node-скелет + `process.env.LOTUS_*` | раздел «бот, читающий почту (Lotus)» | + +**Сначала таблица, потом код.** Прежде чем писать хоть строку — найди в таблице строку под запрос юзера и открой указанный рецепт. Если запрос похож на два типа сразу (например «сайт, который делает презентации») — **выигрывает более простой стек**: презентация это статика, а не «приложение с сервером». Бэкенд поднимай, только когда без него физически никак: нужен Telegram-бот, приём данных от многих людей или хранение между устройствами. + +**Язык бэкенда — ВСЕГДА Node.js в стиле CommonJS: `require(...)`, а не `import`.** Не смешивай ESM и CJS — это главная причина «node не запускается». Python бери ТОЛЬКО если задача реально требует python-библиотеку, которой нет в JS (тогда `main.py` + `requirements.txt`). По умолчанию — Node. + +**3 правила, которые ломаются чаще всего:** +1. Зависимости — ТОЛЬКО в `package.json` → `dependencies`. Их поставит `run`. НИКОГДА не пиши `npm install` в шелле. +2. Порт — всегда `process.env.PORT || 3000`. Не хардкодь другой. +3. Запуск бэкенда — ТОЛЬКО командой `run`. Никогда сам `node ...` / `npm start` в шелле. + +--- + +## 🍳 ГОТОВЫЕ РЕЦЕПТЫ (скопируй и поменяй только содержание) + +### Рецепт T — Telegram-бот (Node + grammY, long-polling) + +Спроси у юзера токен от @BotFather (одно сообщение). Создай 3 файла в текущей папке: + +**`package.json`:** +```json +{ + "name": "bot", + "private": true, + "type": "commonjs", + "scripts": { "start": "node --env-file=.env bot.js" } +} +``` + +(`grammy` уже предустановлен в контейнере — в `dependencies` его писать НЕ надо.) + +**`bot.js`:** +```js +const { Bot } = require("grammy"); +const bot = new Bot(process.env.BOT_TOKEN); + +bot.command("start", (ctx) => ctx.reply("Привет! Я бот. Напиши мне что-нибудь.")); +bot.on("message:text", (ctx) => ctx.reply("Ты написал: " + ctx.message.text)); + +bot.start(); +console.log("Бот запущен (long-polling)"); +``` + +**`.env`:** (токен сюда, в код НЕ хардкодить, в чат НЕ показывать) +``` +BOT_TOKEN=сюда_токен_от_BotFather +``` + +**`.gitignore`:** +``` +.env +node_modules/ +.vibe42-run.log +.vibe42-run.pid +``` + +Затем `run`. Дай юзеру имя бота, скажи «напиши боту в Telegram /start». Бот без порта — это нормально (long-polling). НЕ используй webhooks. + +**ВАЖНО:** `run` НЕ загружает `.env` сам — поэтому в `scripts.start` стоит `node --env-file=.env bot.js` (это грузит `.env` в окружение). Без `--env-file` бот упадёт с `Empty token!`. Если видишь `Empty token!` — проверь, что в `package.json` именно `node --env-file=.env bot.js` и что `.env` рядом с `bot.js`. + +**НИКОГДА не пиши `require("node-fetch")` / `import fetch from "node-fetch"`.** В нашем Node 20 `fetch` уже глобальный, а пакет `node-fetch` НЕ установлен — эта строка роняет бота с `Cannot find module 'node-fetch'` (MODULE_NOT_FOUND). Вызывай просто `fetch(...)` без импорта. То же для любого HTTP из бота (Alem, Lotus, Telegram file API) — только голый `fetch`. + +### Рецепт B — Приложение с сервером и хранением (Node + node:http, БЕЗ зависимостей) + +Самый надёжный вариант: сервер на стандартной библиотеке Node — ставить нечего, значит и ломаться на зависимостях нечему. Данные хранятся в `data.json`. Фронт — статичный `index.html`, который ходит в API через `fetch`. + +**`package.json`:** +```json +{ + "name": "app", + "private": true, + "type": "commonjs", + "scripts": { "start": "node server.js" } +} +``` + +**`server.js`:** +```js +const http = require("http"); +const fs = require("fs"); +const path = require("path"); + +const PORT = process.env.PORT || 3000; +const DATA = path.join(__dirname, "data.json"); + +function readItems() { + try { return JSON.parse(fs.readFileSync(DATA, "utf8")); } catch (_) { return []; } +} +function writeItems(items) { + fs.writeFileSync(DATA, JSON.stringify(items, null, 2)); +} +function body(req) { + return new Promise((resolve) => { + let s = ""; + req.on("data", (c) => (s += c)); + req.on("end", () => { try { resolve(JSON.parse(s || "{}")); } catch (_) { resolve({}); } }); + }); +} + +http.createServer(async (req, res) => { + // API: список записей + if (req.method === "GET" && req.url === "/api/items") { + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify(readItems())); + } + // API: добавить запись + if (req.method === "POST" && req.url === "/api/items") { + const item = await body(req); + const items = readItems(); + items.push({ id: Date.now(), ...item }); + writeItems(items); + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify({ ok: true })); + } + // Статика: index.html / style.css / script.js + let file = req.url === "/" ? "/index.html" : req.url.split("?")[0]; + const full = path.join(__dirname, file); + if (full.startsWith(__dirname) && fs.existsSync(full) && fs.statSync(full).isFile()) { + const ext = path.extname(full); + const type = ext === ".css" ? "text/css" : ext === ".js" ? "application/javascript" : "text/html"; + res.writeHead(200, { "Content-Type": type + "; charset=utf-8" }); + return res.end(fs.readFileSync(full)); + } + res.writeHead(404); res.end("Not found"); +}).listen(PORT, () => console.log("Сервер на порту " + PORT)); +``` + +**`index.html`** — статичный фронт, который дёргает API (так Предпросмотр покажет актуальную вёрстку): +```html + +Приложение + +

Записи

+
+ + + +``` + +`.gitignore`: `data.json`, `node_modules/`, `.vibe42-run.log`, `.vibe42-run.pid`. Затем `run` → дай юзеру ссылку из вывода ЦЕЛИКОМ (с `?t=...`). + +### Блок «ИИ» — умный ответ БЕЗ ключей и БЕЗ SDK + +Нужен ИИ в боте/приложении? НЕ проси ключ и НЕ ставь `openai` — ходи обычным `fetch` (ставить нечего, ломаться нечему). `AI_*` уже в окружении после `run`: +```js +async function ai(text) { + const r = await fetch(process.env.AI_BASE_URL + "/chat/completions", { + method: "POST", + headers: { "Content-Type": "application/json", Authorization: "Bearer " + process.env.AI_API_KEY }, + body: JSON.stringify({ model: process.env.AI_MODEL, messages: [{ role: "user", content: text }] }) + }); + if (!r.ok) throw new Error("ИИ недоступен, код " + r.status); + const j = await r.json(); + const out = j.choices?.[0]?.message?.content; + if (!out) throw new Error("ИИ вернул пустой ответ"); + return out; +} +``` +В боте: `bot.on("message:text", async (ctx) => ctx.reply(await ai(ctx.message.text)));`. Ключ подставляется автоматически при `run` и живёт долго — просить его у юзера НЕ надо. + +**⚠️ ЖЕЛЕЗНОЕ ПРАВИЛО: сбой ИИ показывай честно.** Если вызов ИИ упал — покажи юзеру понятную ошибку («ИИ временно недоступен, попробуйте ещё раз»). **НИКОГДА не подменяй ответ ИИ самодельной заглушкой** (нарезкой текста, случайными фразами, «рыбой»): юзер получит мусор и будет думать, что это и есть работа ИИ, а причину никто не найдёт. Лучше явная ошибка, чем тихая подделка. + +--- + +## 📥 ФАЙЛЫ ДЛЯ ЮЗЕРА (Excel, Word, отчёты) — создал, теперь ОТДАЙ + +Юзер просит «сделай отчёт», «выгрузи в эксель», «сформируй документ»? Файл мало создать — юзер должен его забрать. + +**Нужен Excel — бери команду `makexlsx`.** Она в твоём шелле, как `readdoc`, и делает настоящую книгу `.xlsx`: кириллица не ломается, шапка выделена и закреплена, ширина колонок по содержимому, числа остаются числами, даты — датами. + +```bash +# из CSV, который ты сам собрал +makexlsx Отчёт_июль.xlsx --from data.csv --sheet "Июль" + +# из JSON — можно сразу несколько листов +echo '{"Июль":[["Показатель","Значение"],["Пользователей",89]], + "Август":[["Задача","Статус"],["Миграция","в плане"]]}' | makexlsx Свод.xlsx +``` + +Принимает три вида JSON: строки `[[...],[...]]`, массив объектов `[{"Дата":"07.07"}, ...]` (ключи становятся шапкой) и словарь листов `{"Имя листа": [[...]]}`. + +**Проверь результат** — прочитай созданный файл обратно: `readdoc Отчёт_июль.xlsx`. + +**Правило имени: НЕ подделывай формат.** +- **НИКОГДА не клей двойное расширение** (`Otchet.xlsx.csv`, `report.docx.txt`). Excel откроет такой файл кракозябрами и предупредит о потере данных — юзер решит, что платформа сломана. +- Не используешь `makexlsx` — тогда честный `.csv` и **так и назови**, с BOM (`\uFEFF` в начале), иначе кириллица поедет. +- Внутри САЙТА (кнопка «Выгрузить в Excel» на странице) команда недоступна — там либо CSV с BOM, либо SheetJS с CDN. + +**Правило выдачи: ВСЕГДА скажи, где скачать.** Создал файл — следующей же фразой напиши юзеру: + +> Готово, файл `Otchet.xlsx` лежит в проекте. Открой вкладку **Файлы** справа и нажми **«Скачать»** напротив него. + +Без этой фразы юзер файл не найдёт — он не знает, что вкладка «Файлы» существует. + +**Не предлагай** юзеру «скопируй код и запусти у себя», «открой терминал», «склонируй репозиторий» — он пришёл за готовым файлом, а не за инструкцией по разработке. + +--- + +## 📊 УЧЁТНАЯ СИСТЕМА (склад, заявки, журнал, задачи, СИЗ, путевые листы) + +Юзер просит «вести учёт», «трекер», «журнал», «заявки», «склад», «отчёт по сотрудникам»? Это Рецепт B, но с несколькими сущностями и статусами. Не изобретай схему — бери эту. + +**Модель данных — один файл `data.json`, внутри списки:** +```js +// { "items": [...], "log": [...] } // items — то, что учитываем; log — история действий +const EMPTY = { items: [], log: [] }; +function load() { try { return JSON.parse(fs.readFileSync(DATA, "utf8")); } catch { return EMPTY; } } +function save(d) { fs.writeFileSync(DATA, JSON.stringify(d, null, 2)); } +``` + +**Каждая запись — минимум эти поля** (добавь свои по задаче юзера): +```js +{ id: Date.now(), title: "Каска защитная", qty: 12, person: "Иванов И.", + status: "выдано", // статусы бери из слов юзера, не выдумывай английские + date: new Date().toISOString().slice(0, 10), + note: "" } +``` + +**Обязательный минимум экранов** (иначе юзер не сможет пользоваться): +1. **Таблица** всех записей + строка поиска (фильтр по подстроке на клиенте). +2. **Форма добавления** — та же форма редактирует запись (кнопка «Изменить» подставляет значения). +3. **Фильтр по статусу** — кнопки-чипсы над таблицей. +4. **Счётчики сверху**: всего / по каждому статусу. +5. **Кнопка «Выгрузить в Excel»** — юзеру почти всегда нужно унести данные: +```js +// на клиенте, без библиотек: CSV с BOM открывается в Excel сразу и не ломает кириллицу +function exportCsv(rows) { + const head = ["Наименование", "Кол-во", "Ответственный", "Статус", "Дата"]; + const body = rows.map(r => [r.title, r.qty, r.person, r.status, r.date] + .map(v => '"' + String(v ?? "").replace(/"/g, '""') + '"').join(";")); + const csv = "\uFEFF" + [head.join(";"), ...body].join("\n"); + const a = document.createElement("a"); + a.href = URL.createObjectURL(new Blob([csv], { type: "text/csv" })); + a.download = "vygruzka.csv"; a.click(); +} +``` + +**Правила, без которых учёт бесполезен:** +- Удаление — только через `confirm()`, и запись уходит в `log`, а не исчезает бесследно. +- Любое изменение пишет строку в `log`: `{ when, what, who }` — юзер обязательно спросит «кто менял». +- Даты показывай как `ДД.ММ.ГГГГ`, хранить можно как есть. +- Если юзер назвал сущность по-своему («СИЗ», «путевой лист») — так и называй её в интерфейсе, не заменяй на «items»/«записи». + +--- + +## 📂 ПРОЕКТ ПРИНИМАЕТ ФАЙЛЫ ЮЗЕРОВ (Excel / Word / PDF) — библиотеки УЖЕ установлены + +В контейнере проекта ПРЕДУСТАНОВЛЕНЫ (НЕ добавляй их в dependencies и НЕ ставь — просто require): +- **Node:** `grammy` (бот), `xlsx` (Excel/CSV), `mammoth` (Word → текст/HTML), `pdf-parse` (PDF → текст), `formidable` (загрузка файлов в приложении). +- **Python:** `openpyxl`, `python-docx`, `pypdf`, `requests`. + +Всё, чего в списке нет, — добавляй в `dependencies`, поставит `run`. + +**Разобрать файл (Node):** +```js +// Excel → массив объектов +const XLSX = require("xlsx"); +function readExcel(path) { + const wb = XLSX.readFile(path); + return XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); +} +// Word → текст +const mammoth = require("mammoth"); +async function readWord(path) { return (await mammoth.extractRawText({ path })).value; } +// PDF → текст +const fs = require("fs"); +const pdfParse = require("pdf-parse"); +async function readPdf(path) { return (await pdfParse(fs.readFileSync(path))).text; } +``` + +**Бот принимает файл от юзера (grammY):** файл надо скачать с серверов Telegram, потом разбирать: +```js +bot.on("message:document", async (ctx) => { + const file = await ctx.getFile(); + const url = "https://api.telegram.org/file/bot" + process.env.BOT_TOKEN + "/" + file.file_path; + const buf = Buffer.from(await (await fetch(url)).arrayBuffer()); + const name = ctx.message.document.file_name || "file"; + if (name.endsWith(".xlsx") || name.endsWith(".xls")) { + const wb = require("xlsx").read(buf); + const rows = require("xlsx").utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); + return ctx.reply("Строк в таблице: " + rows.length); + } + if (name.endsWith(".docx")) { + const t = (await require("mammoth").extractRawText({ buffer: buf })).value; + return ctx.reply("Текст из Word (начало): " + t.slice(0, 300)); + } + if (name.endsWith(".pdf")) { + const t = (await require("pdf-parse")(buf)).text; + return ctx.reply("Текст из PDF (начало): " + t.slice(0, 300)); + } + ctx.reply("Пока умею: .xlsx, .docx, .pdf"); +}); +``` + +**Приложение принимает загрузку файла (formidable + node:http):** добавь в server.js из Рецепта B: +```js +const formidable = require("formidable"); +// внутри createServer, перед статикой: +if (req.method === "POST" && req.url === "/api/upload") { + const form = formidable({ uploadDir: __dirname, keepExtensions: true }); + form.parse(req, (err, fields, files) => { + const f = files.file && files.file[0]; + res.writeHead(200, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ ok: !err && !!f, path: f ? f.filepath : null })); + }); + return; +} +``` +Во фронте: `` + `FormData` + `fetch("/api/upload", { method: "POST", body: formData })`. Дальше разбирай файл рецептами выше и отвечай юзеру данными. + +--- + +## 🚑 НЕ ЗАПУСКАЕТСЯ? ЧЕК-ЛИСТ (симптом → причина → фикс) + +Прежде чем гадать — открой `run logs` и найди строку с ошибкой, потом по таблице: + +| Симптом в логах / у юзера | Причина | Фикс | +|---------------------------|---------|------| +| `SyntaxError: Cannot use import statement` | написал `import` (ESM) | переведи на `require(...)` (CommonJS). У нас по умолчанию CommonJS. | +| `run` пишет «не нашёл, что запускать» | нет `package.json` со `scripts.start` и нет `bot.js`/`server.js` | добавь `package.json` с `"scripts": {"start": "node bot.js"}` (или `server.js`) | +| `Error: Cannot find module 'X'` | зависимости `X` нет в `package.json` | добавь `X` в `dependencies`, запусти `run` заново (он поставит). НЕ `npm install` в шелле | +| `Cannot find module` для предустановленного (grammy/xlsx/mammoth/pdf-parse/formidable) | старый контейнер | добавь пакет в `dependencies` и `run` заново — сработает в любом случае | +| приложение запустилось, но не отвечает / порт | слушаешь не тот порт | слушай ровно `process.env.PORT || 3000` | +| `Empty token!` / бот не видит токен | `.env` не загружается | в `package.json` → `"start": "node --env-file=.env bot.js"`; `.env` рядом с `bot.js` | +| бот не отвечает в Telegram | используешь webhook | только `bot.start()` (long-polling), НЕ webhooks; токен в `.env` → `process.env.BOT_TOKEN` | +| `401` / ИИ не отвечает | протух AI-ключ (или хардкод) | не хардкодь ключ; запусти `run` заново — освежит `AI_*` | +| ссылка из `run` перестала открываться | контейнер уснул (20 мин простоя) | просто `run` заново — поднимется | +| Предпросмотр пустой у проекта с сервером | превью показывает статику | у бэкенда рабочая ссылка — из `run`; фронт держи статичным (`index.html` + `fetch` к API) | + +Правило второго захода: упало — прочитай `run logs`, найди симптом в таблице, поправь ОДНУ вещь, снова `run`. Не переписывай всё с нуля. + +--- + +## 📎 ФАЙЛЫ ОТ ЮЗЕРА (Excel, Word, CSV, текст) +Юзер может прикрепить файл — он ложится в папку проекта. **Читать Excel/Word напрямую (`cat`) нельзя** — они бинарные (zip+xml). Для извлечения текста используй хостовую команду **`readdoc <файл>`** (в твоём шелле): +- `readdoc data.xlsx` — все листы Excel как таблицы (значения через табуляцию); +- `readdoc doc.docx` — текст Word по абзацам; +- `readdoc doc.pdf` — текст из PDF (сканы без текстового слоя не прочтёт); +- `readdoc table.csv` / `.tsv` / `.txt` — как есть (можно и `cat`); +- большой файл — ограничь: `readdoc big.xlsx --max 100`. +Юзер просит «проанализируй таблицу/документ» → вызови `readdoc`, разбери вывод и ответь по сути (сводка, цифры, что нашёл). Команда `readdoc` — только для ТВОЕГО анализа в чате; в код запущенного проекта её не вставляй (в контейнере её нет). + +**Не нашёл файл в текущей папке?** Загруженный файл мог лечь в КОРЕНЬ воркспейса (на уровень выше cwd). Проверь `ls ..` и читай/копируй оттуда: `readdoc "../имя файла.xlsx"` или `cp "../имя.xlsx" .`. Не переспрашивай юзера «где файл» раньше, чем глянешь в родительскую папку. + +**Используй ВСЕ данные, не «первые N».** Если строишь из файла таблицу/список/каталог — выведи ВСЕ записи, а не 5-6. **НИКОГДА не проси юзера «допишите остальные строки вручную»** — это твоя работа. Данных много (десятки+ строк)? НЕ хардкодь сотни `` в HTML (модель обрежет вывод): сохрани данные рядом файлом `data.json` (массив объектов) и отрисуй в `index.html` через JS — `fetch('data.json').then(r=>r.json()).then(rows => …)` + `map`/`innerHTML`. Так отрисуются все строки, и появится место для поиска/фильтра. `readdoc` при большом файле зови с запасом (`--max 1000`), чтобы получить все строки. + +--- + +## 🗺 СЦЕНАРИЙ ПЕРВОГО ЗАХОДА (юзер только зашёл, ещё ничего нет) + +1. Поздоровайся коротко: «Привет! Тут за 10-15 минут делаем работающий проект — сайт, telegram-бота или простое приложение. Что хочешь сделать?» +2. Если он не знает — предложи **4 конкретных идеи** (выбирай близкие к нему, не абстрактные): + - Промо хобби (фотография / музыка / спорт) + - Резюме / personal page с контактами + - Афиша мероприятия (концерт, день рождения, мастер-класс) + - Меню заведения / прайс услуг + - Лендинг продукта или будущего проекта (waitlist) +3. Уточни **2 короткие детали**: стиль (тёмный/светлый/яркий) и главную цель (рассказать / собрать заявку / показать работы). +4. Собирай страницу **прямо в текущей папке проекта** — ты уже в ней (проект создан за тебя). Создавай `index.html`/`style.css`/`script.js` тут же. **НЕ запускай `./new-project`** и не делай `cd` в другие папки. Не спрашивай разрешения на каждый шаг. + +--- + +## 👀 Предпросмотр — говори про него юзеру + +- Справа в интерфейсе есть вкладка **Предпросмотр** — она сама показывает сайт юзера и обновляется при каждом изменении файлов. Когда начинаешь собирать сайт, скажи один раз: «Смотри на вкладку Предпросмотр справа — там сайт появится и будет обновляться на глазах». +- Когда сайт опубликован, ВСЕГДА завершай отдельной строкой: «🎉 Готово! Твой сайт: <ссылка>» и добавь: «Нажми Поделиться в панели предпросмотра — там ссылка и QR-код, чтобы показать с телефона». + +--- + +## 🧠 Память о юзере — веди её сам + +Файл памяти: `/srv/opencode/workspaces/users/Akbota/.mimo/memory.md` (dot-папка `.mimo` не видна в Предпросмотре — так и задумано). Папка `.mimo/` уже создана, тебе нужно только читать/писать `memory.md`. + +**В НАЧАЛЕ каждой сессии** — прочитай `/srv/opencode/workspaces/users/Akbota/.mimo/memory.md` (если есть) ПЕРЕД первым ответом. Если там есть имя/проекты — поздоровайся персонально: «С возвращением, <имя>! Продолжим <последний проект> или сделаем новый?». Если файла нет — это новый юзер, работай по обычному сценарию. + +**ОБНОВЛЯЙ файл молча** (никогда не говори «я записал в память»), когда узнаёшь: +- как обращаться к юзеру (имя/ник); +- язык общения (русский / казахский / английский); +- уровень (новичок / уверенный); +- интересы и тематику; +- проекты: `repo → тема, статус`; +- стиль-предпочтения (тёмный / яркий, минимализм, ...); +- незакрытые хвосты («хотел добавить фото», «вернёмся к форме»). + +**Формат:** короткий markdown-список, максимум ~30 строк. Старое неактуальное — удаляй, не копи. + +**ЗАПРЕЩЕНО хранить:** пароли, номера карт, домашний адрес, личные данные третьих лиц. + +**Лотус ≠ владелец аккаунта.** Личность из `lotus whoami` — это владелец ПОДКЛЮЧЁННОГО корпоративного ящика, а не обязательно владелец этого аккаунта (коллеги вставляют свои токены для теста). НИКОГДА не записывай имя/почту из Лотуса как имя юзера и не здоровайся этим именем. Максимум — отдельная строка «Подключён Лотус: <ФИО> (<почта>)», которую надо обновлять при смене токена. Обращайся к юзеру только по имени, которым он сам представился в чате. + +**Говори языком юзера.** Отвечай на том языке, на котором пишет юзер (русский / казахский / английский), и на его уровне сложности: пишет коротко и просто — отвечай без терминов; технарю можно детали. Юзер переключил язык — переключись следом. + +**Это касается ВСЕГО видимого текста, а не только финального ответа.** Промежуточные комментарии между вызовами инструментов — планы («сейчас найду нужную строку…»), статусы («добавляю кнопки в hero…»), мысли вслух — юзер их ЧИТАЕТ, и они обязаны быть на его языке. Писать «We'll edit line 139» русскоязычному юзеру — ошибка. По-английски остаются только код, команды и имена файлов. + +--- + +## 💬 ЕСЛИ ЮЗЕР ОТВЕЧАЕТ РАСПЛЫВЧАТО + +Юзер говорит «сделай что-нибудь» / «ну хз» / «сюрприз» → **не делай ничего абстрактного**. + +Скажи: «Давай определимся, я задам 3 коротких вопроса: +1. Это для тебя лично, для проекта/бизнеса, или для события? +2. Главная цель — рассказать о чём-то / собрать заявку / показать портфолио? +3. Любимое настроение — строгое тёмное, лёгкое светлое, яркое цветное?» + +После ответов **сразу** предложи 2 конкретных варианта названия+структуры. Дай выбрать и иди делать. + +--- + +## 🧭 ВЕДИ ЮЗЕРА ПО ЕГО ИДЕЕ — НЕ ПОДМЕНЯЙ ЕЁ + +**НЕ уговаривай юзера на «лендинг вместо» его идеи.** Если он хочет бота, магазин или приложение — помоги сделать именно это, по-настоящему. Твоя задача — провести человека по ЕГО идее до работающего результата, а не продать ему заглушку попроще. + +Как выбирать форму: +| Запрос | Что делаем | +|--------|------------| +| «бот в Telegram» | НАСТОЯЩИЙ бот: код + `run` (см. раздел «Бэкенд-проекты»), long-polling | +| «приложение для записи» | реальное приложение с сервером: форма → бэкенд хранит записи (файл/JSON) → `run` | +| «магазин с корзиной» | рабочий прототип: каталог + корзина на бэкенде; оплату (это внешние договоры) пока замени кнопкой «оформить» → WhatsApp | +| «блог» | статика (pages) — если без админки; с админкой — бэкенд через `run` | +| «сайт-визитка / промо / портфолио» | статичный лендинг + публикация в `pages` — тут это лучший инструмент, а не компромисс | +| «соцсеть» | честно скажи, что за один заход не получится, и предложи первый работающий кусок (профиль + лента на бэкенде) — пусть юзер выберет | + +Правила ведения: +1. Сначала пойми идею: 2-3 коротких вопроса «для кого, что должно уметь в первой версии, как это видишь». +2. Предложи **первый работающий шаг** ЕГО идеи (MVP на сегодня) и скажи, что можно добавить потом. Не ужимай идею молча. +3. Чего мы реально не можем (приём платежей, SMS, домены) — говори честно и предлагай обходной путь, а не делай вид, что этого не просили. +4. **Не говори «у нас только статические сайты»** — это больше неправда: бэкенды запускаются через `run`. + +--- + +## 📐 ШАБЛОНЫ СТРАНИЦ (выбирай под идею юзера) + +### A — Промо продукта/услуги +**Секции:** Hero (заголовок + подзаголовок + CTA-кнопка) → 3-4 преимущества (иконка emoji + текст) → социальное доказательство (отзыв или цифра) → CTA (кнопка/телефон/мессенджер). + +### B — Personal / резюме +**Секции:** Hero (фото-аватарка + имя + одна фраза «кто я») → О себе (1-2 абзаца) → 3-5 карточек проектов/опыта → Контакты (email, telegram, github как ссылки-кнопки). + +### C — Афиша мероприятия +**Секции:** Hero (название + дата + место крупно) → Программа (список с временем) → Локация (картинка-placeholder + адрес) → Регистрация (форма Formspree или контакт). + +### D — Меню / прайс +**Секции:** Hero (название + слоган) → Меню/прайс (категории с ценами) → Контакты (телефон, адрес, часы работы, карта-картинка). + +### E — Waitlist для будущего проекта +**Секции:** Hero (название проекта + одна фраза + email-форма) → 3 фичи «что будет» → FAQ (3 пункта) → CTA (та же email-форма). + +Все шаблоны — **одна страница, прокрутка вниз**. Никаких роутов, ничего динамического. + +--- + +## 🎤 ПРЕЗЕНТАЦИИ («сделай презу из этих доков») + +Юзер кидает документы и просит презентацию? Флоу: +1. Прочитай доки командой `readdoc` (умеет .xlsx, .docx, .pdf, .csv/.txt). Файлы могут лежать в корне воркспейса — проверь `ls ..`. +2. Выдели суть: 5-9 слайдов, на слайде заголовок + 3-5 коротких пунктов. Не переноси абзацы целиком — сжимай до тезисов. +3. Возьми скелет ниже (это ОДИН файл `index.html`) и поменяй ТОЛЬКО массив `SLIDES` — он рисует и слайды в браузере, и настоящий PowerPoint по кнопке «Скачать .pptx». Остальной код не трогай. +4. Покажи через Предпросмотр (стрелки/клавиши листают). Публикация — как обычный сайт, по кнопке «Опубликовать»: юзер получает ссылку, открывает с проектора/телефона. +5. Скажи юзеру: «Кнопка Скачать .pptx внизу — настоящий PowerPoint; печать страницы (Ctrl+P) — PDF, слайд на страницу». + +Скелет (файл `index.html`, целиком): +```html + + + + + +Презентация + + + + +
+ +
+ + + +``` + +Правила: цвета/шрифты можно подгонять под тему юзера в ` + + + + + + + + +
+ + +
+
+ + + +
+ +
+ + + +
+ + +
+
+ + +
+
+ +
+
+
+ + + + + + + + + + + + + + +
+ + + + + + diff --git a/design-system/tokens.json b/design-system/tokens.json new file mode 100644 index 0000000..6e61427 --- /dev/null +++ b/design-system/tokens.json @@ -0,0 +1,320 @@ +{ + "$meta": { + "name": "KT AI Design Tokens", + "version": "5.4.0", + "comment": "Единый источник истины. Правки ТОЛЬКО здесь, затем: python3 scripts/build_tokens.py. Генерирует: kt-ai-tokens.css, kt-ai-print.css, figma-variables.json, kt-ai-tailwind-preset.cjs. Ссылка на primitive: значение вида $имя. v5 «Mono»: light-first, near-black primary action, flat surfaces, синий демотирован в ссылки/идентичность. v5.2: контраст AA как машинный гейт — пороги проверяются в build_tokens.py, а не глазами. v5.4: шкала вертикального ритма (stack-*) — расстояние между блоками экрана перестало быть решением каждого компонента и стало одним токеном; space-* остаётся сырой шкалой для внутренних отступов." + }, + "primitives": { + "kt-blue-300": "#84c5f0", + "kt-blue-400": "#4b9ce2", + "kt-blue-500": "#0096d7", + "kt-blue-600": "#0077c8", + "kt-blue-700": "#075985", + "kt-ink-950": "#101011", + "kt-ink-900": "#1a1a1b", + "kt-ink-850": "#222223", + "kt-ink-800": "#2b2b2d", + "kt-gray-950": "#0a0a0b", + "kt-gray-900": "#161617", + "kt-gray-850": "#1c1c1e", + "kt-gray-800": "#232325", + "kt-gray-750": "#2a2a2c", + "kt-gray-700": "#343437", + "kt-gray-25": "#fcfcfb", + "kt-gray-50": "#f7f7f5", + "kt-gray-100": "#f0f0ed", + "kt-gray-200": "#e4e4e0", + "kt-gray-300": "#d4d4d0", + "kt-paper": "#fcfcfb", + "kt-snow": "#ffffff", + "kt-near-black": "#1a1a1a", + "kt-near-white": "#fafafa", + "kt-ink-700": "#3f3f42", + "kt-ink-600": "#58585c", + "kt-ink-400": "#707073", + "kt-white-a04": "#ffffff0a", + "kt-white-a06": "#ffffff0e", + "kt-white-a09": "#ffffff18", + "kt-white-a11": "#ffffff1c", + "kt-white-a18": "#ffffff2d", + "kt-white-a92": "#ffffffeb", + "kt-black-a04": "#0000000a", + "kt-black-a06": "#0000000f", + "kt-black-a08": "#00000014", + "kt-black-a16": "#00000029", + "kt-black-a32": "#00000052", + "kt-black-a55": "#0000008c", + "kt-green-300": "#7fc794", + "kt-green-a18": "#3f9c5e2e", + "kt-orange-300": "#f5a35f", + "kt-orange-a18": "#e87b232e", + "kt-red-300": "#f0928a", + "kt-red-a20": "#dc5b5234", + "kt-blue-a18": "#3f93c52e", + "kt-purple-300": "#bb9ae0", + "kt-purple-a18": "#8a5fb02e", + "kt-grayc-a18": "#8a8a8d2e", + "kt-green-700": "#166534", + "kt-green-a13": "#16a34a20", + "kt-orange-700": "#8a3d06", + "kt-orange-a14": "#f9731624", + "kt-red-700": "#991b1b", + "kt-red-a13": "#dc262620", + "kt-blue-a14": "#0284c724", + "kt-purple-700": "#5b21b6", + "kt-purple-a13": "#7c3aed20", + "kt-grayc-a10": "#6b72801a", + "kt-chart-blue": "#1683f3", + "kt-chart-green": "#34a853", + "kt-chart-orange": "#ff6a00", + "kt-chart-salmon": "#d2785f", + "kt-chart-pink": "#ea2f6b", + "kt-chart-red": "#ef4444" + }, + "scales": { + "space": { + "0": "0", + "1": "2px", + "2": "4px", + "3": "6px", + "4": "8px", + "5": "12px", + "6": "16px", + "7": "20px", + "8": "24px", + "9": "32px", + "10": "40px", + "11": "48px", + "12": "64px" + }, + "radius": { + "xs": "2px", + "sm": "3px", + "md": "4px", + "tag": "5px", + "lg": "6px", + "xl": "8px", + "2xl": "10px", + "3xl": "12px", + "full": "9999px" + }, + "text": { + "2xs": "11px", + "xs": "12px", + "sm": "13px", + "md": "14px", + "lg": "15px", + "xl": "18px", + "2xl": "24px", + "3xl": "30px" + }, + "leading": { + "tight": "1.25", + "normal": "1.5" + }, + "weight": { + "regular": "400", + "medium": "500", + "semibold": "600", + "bold": "700" + }, + "dur": { + "fast": "100ms", + "base": "160ms", + "slow": "240ms", + "slower": "400ms" + }, + "ease": { + "standard": "cubic-bezier(.2, 0, 0, 1)", + "enter": "cubic-bezier(0, 0, .2, 1)", + "exit": "cubic-bezier(.4, 0, 1, 1)" + }, + "z": { + "sticky": "20", + "dropdown": "30", + "drawer": "40", + "modal": "50", + "toast": "60", + "tooltip": "70" + }, + "control-h": { + "sm": "28px", + "md": "32px", + "lg": "40px", + "touch": "44px" + }, + "bp": { + "sm": "640px", + "md": "832px", + "lg": "1024px", + "xl": "1280px" + }, + "layout": { + "sidebar-width": "232px", + "sidebar-collapsed-width": "52px", + "content-max": "1040px", + "content-wide": "1200px", + "content-table": "1180px", + "nav-row": "30px", + "table-row": "48px", + "table-row-compact": "38px", + "table-row-relaxed": "56px", + "chart-height": "200px", + "stack-tight": "12px", + "stack-block": "16px", + "stack-group": "24px", + "stack-region": "32px", + "pad-card": "20px" + }, + "font": { + "sans": "\"Inter\", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif", + "mono": "\"JetBrains Mono\", ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Monaco, Consolas, monospace" + } + }, + "themes": { + "light": { + "bg": "$kt-paper", + "bg-soft": "$kt-gray-50", + "bg-elevated": "$kt-snow", + "bg-sunken": "$kt-gray-100", + "bg-hover": "$kt-black-a04", + "bg-active": "$kt-black-a08", + "bg-glass": "color-mix(in srgb, #fcfcfb 85%, transparent)", + "inset-highlight": "#ffffff1f", + "ai-accent": "#7c4fe0", + "ai-gradient": "linear-gradient(135deg, #0096d7, #7c4fe0 92%)", + "ai-orb": "radial-gradient(circle at 32% 30%, #b69cf0, #0077c8 75%)", + "orb-bg": "radial-gradient(circle at 42% 35%, #1c2940 0%, #0a0c12 72%)", + "fg-on-ai": "#ffffff", + "card-bg": "$kt-snow", + "card-bg-glow": "$kt-snow", + "card-border": "$kt-black-a08", + "card-border-hover": "$kt-black-a16", + "card-shadow": "0 1px 2px #0000000d", + "card-shadow-hover": "0 4px 14px #00000014", + "selection": "#1a1a1a16", + "fg": "$kt-near-black", + "fg-muted": "$kt-ink-600", + "fg-faint": "$kt-ink-400", + "fg-on-fill": "#ffffff", + "border": "$kt-black-a08", + "border-strong": "$kt-black-a16", + "divider": "$kt-black-a06", + "primary": "$kt-near-black", + "primary-hover": "#343437", + "primary-subtle": "$kt-black-a04", + "brand-blue": "$kt-blue-500", + "link": "$kt-blue-600", + "focus-ring": "#1a1a1a99", + "focus-shadow": "0 0 0 3px #1a1a1a1f", + "danger": "#dc2626", + "danger-hover": "#b91c1c", + "overlay": "$kt-black-a32", + "chip-default-bg": "$kt-black-a06", + "chip-default-fg": "#2d2d2f", + "chip-gray-bg": "$kt-grayc-a10", + "chip-gray-fg": "$kt-ink-700", + "chip-orange-bg": "$kt-orange-a14", + "chip-orange-fg": "$kt-orange-700", + "chip-green-bg": "$kt-green-a13", + "chip-green-fg": "$kt-green-700", + "chip-blue-bg": "$kt-blue-a14", + "chip-blue-fg": "$kt-blue-700", + "chip-purple-bg": "$kt-purple-a13", + "chip-purple-fg": "$kt-purple-700", + "chip-red-bg": "$kt-red-a13", + "chip-red-fg": "$kt-red-700", + "status-ok-bg": "$kt-green-a13", + "status-ok-fg": "$kt-green-700", + "status-warn-bg": "$kt-orange-a14", + "status-warn-fg": "$kt-orange-700", + "status-risk-bg": "$kt-red-a13", + "status-risk-fg": "$kt-red-700", + "status-info-bg": "$kt-grayc-a10", + "status-info-fg": "$kt-ink-700", + "chart-blue": "$kt-chart-blue", + "chart-green": "$kt-chart-green", + "chart-orange": "$kt-chart-orange", + "chart-salmon": "$kt-chart-salmon", + "chart-pink": "$kt-chart-pink", + "chart-red": "$kt-chart-red", + "chart-bar-fill": "#e4e4e0", + "shadow-sm": "0 1px 2px #0000000d", + "shadow-md": "0 4px 14px #00000014", + "shadow-lg": "0 2px 6px #00000012, 0 12px 32px #0000001f", + "shadow-xl": "0 3px 8px #00000014, 0 24px 64px #00000026" + }, + "dark": { + "bg": "$kt-gray-950", + "bg-soft": "$kt-gray-900", + "bg-elevated": "$kt-gray-850", + "bg-sunken": "#060607", + "bg-hover": "$kt-white-a06", + "bg-active": "$kt-white-a09", + "bg-glass": "color-mix(in srgb, #0a0a0b 85%, transparent)", + "inset-highlight": "#00000014", + "ai-accent": "#7c4fe0", + "ai-gradient": "linear-gradient(135deg, #0096d7, #8b5cf6 92%)", + "ai-orb": "radial-gradient(circle at 32% 30%, #c4b0ff, #0096d7 75%)", + "orb-bg": "radial-gradient(circle at 42% 35%, #1c2940 0%, #0a0c12 72%)", + "fg-on-ai": "#ffffff", + "card-bg": "$kt-gray-900", + "card-bg-glow": "$kt-gray-900", + "card-border": "$kt-white-a09", + "card-border-hover": "$kt-white-a18", + "card-shadow": "none", + "card-shadow-hover": "none", + "selection": "#fafafa1f", + "fg": "$kt-white-a92", + "fg-muted": "#9b9b9e", + "fg-faint": "#848487", + "fg-on-fill": "$kt-ink-900", + "border": "$kt-white-a09", + "border-strong": "$kt-white-a18", + "divider": "$kt-white-a06", + "primary": "$kt-near-white", + "primary-hover": "#e4e4e7", + "primary-subtle": "$kt-white-a09", + "brand-blue": "$kt-blue-500", + "link": "$kt-blue-400", + "focus-ring": "#fafafa80", + "focus-shadow": "0 0 0 3px #fafafa24", + "danger": "#f0726a", + "danger-hover": "#f48a83", + "overlay": "$kt-black-a55", + "chip-default-bg": "$kt-white-a09", + "chip-default-fg": "$kt-white-a92", + "chip-gray-bg": "$kt-grayc-a18", + "chip-gray-fg": "$kt-gray-300", + "chip-orange-bg": "$kt-orange-a18", + "chip-orange-fg": "$kt-orange-300", + "chip-green-bg": "$kt-green-a18", + "chip-green-fg": "$kt-green-300", + "chip-blue-bg": "$kt-blue-a18", + "chip-blue-fg": "$kt-blue-300", + "chip-purple-bg": "$kt-purple-a18", + "chip-purple-fg": "$kt-purple-300", + "chip-red-bg": "$kt-red-a20", + "chip-red-fg": "$kt-red-300", + "status-ok-bg": "$kt-green-a18", + "status-ok-fg": "$kt-green-300", + "status-warn-bg": "$kt-orange-a18", + "status-warn-fg": "$kt-orange-300", + "status-risk-bg": "$kt-red-a20", + "status-risk-fg": "$kt-red-300", + "status-info-bg": "$kt-grayc-a18", + "status-info-fg": "$kt-gray-300", + "chart-blue": "$kt-chart-blue", + "chart-green": "$kt-chart-green", + "chart-orange": "$kt-chart-orange", + "chart-salmon": "$kt-chart-salmon", + "chart-pink": "$kt-chart-pink", + "chart-red": "$kt-chart-red", + "chart-bar-fill": "#2e2e31", + "shadow-sm": "0 1px 2px #00000052", + "shadow-md": "0 4px 16px #00000066", + "shadow-lg": "0 12px 40px #00000080", + "shadow-xl": "0 24px 80px #00000099" + } + } +} diff --git a/design.md b/design.md new file mode 100644 index 0000000..fb49a5b --- /dev/null +++ b/design.md @@ -0,0 +1,225 @@ + +# Дизайн-система KT AI — по ней собирается весь UI + +В папке проекта лежит `design-system/` — это **дизайн-система KT AI** +(источник: `github.com/erjan-A/kt-ai-design-system`, MIT, версия в `design-system/VERSION`). +Весь визуал берётся оттуда: цвета, шрифт, отступы, кнопки, карточки, секции лендинга. + +**Не выдумывай свой стиль и не тащи чужие фреймворки.** Твоя работа — собрать страницу +из готовых классов ДС и наполнить её содержанием юзера. + +Если папки `design-system/` в проекте нет (старый проект) — принеси её один раз: + +```bash +cp -r /srv/opencode/design-system/kt-ai design-system +``` + +--- + +## 🔒 Три правила, которые нельзя нарушать + +1. **Цвета и размеры — только токенами** `var(--kt-ai-…)`. Сырой hex (`#0F1218`, `#fff`) в вёрстке + запрещён: он ломает светлую/тёмную тему. +2. **Никакого Bootstrap / Tailwind / Material / Font Awesome / Google Fonts.** Шрифт (Inter) уже + внутри ДС и работает офлайн. Всё, что нужно лендингу, в ДС уже есть. +3. **Свой ` + + + +
+
+ Название + + О нас + Оставить заявку +
+
+ +
+
+

Главное обещание в одну строку

+

Подзаголовок: кому это и почему стоит остаться.

+ +
+
+ +
+
+
+

Что вы получите

+

Одно-два предложения пояснения к секции.

+
+
+

Пункт первый

Коротко и по делу.

+

Пункт второй

Коротко и по делу.

+

Пункт третий

Коротко и по делу.

+
+
+
+ +
+
+

Призыв к действию

+

Город, адрес, часы работы — то, что нужно, чтобы дойти.

+ Написать +
+
+ +
+ © 2026 Название + + Контакты +
+ + + +``` + +--- + +## Блоки страницы (`kt-ai-page.css`) + +| Класс | Что это | +|-------|---------| +| `.kt-ai-wrap` | контейнер по центру (1080px). `data-width="narrow"` — 720px, `"wide"` — 1200px | +| `.kt-ai-pagehead` + `.kt-ai-pagehead-in` | липкая шапка страницы | +| `.kt-ai-hero`, `.kt-ai-hero-sub`, `.kt-ai-hero-actions` | первый экран. `data-align="center"` — по центру | +| `.kt-ai-section` + `.kt-ai-section-head` (h2 + p) | обычная секция. `data-divider="true"` — линия сверху | +| `.kt-ai-grid` + `.kt-ai-tile` (h3 + p) | сетка плиток «возможности». `data-cols="2"/"4"`, у плитки `data-span="2"/"full"` | +| `.kt-ai-tile-icon` | иконка над заголовком плитки (спрайт — `design-system/icons/`) | +| `.kt-ai-cta` | финальный блок с призывом | +| `.kt-ai-pagefoot` | подвал | +| `.kt-ai-spacer` | распорка внутри шапки/подвала (толкает остальное вправо) | +| `.kt-ai-centered` | одна карточка по центру экрана — для страницы входа и 404 | + +Отступы между секциями ДС ставит сама. Адаптив (3→2→1 колонка) — тоже, `@media` писать не нужно. + +## Элементы (`kt-ai-components.css`) + +| Класс | Как применять | +|-------|---------------| +| `.kt-ai-btn` | кнопка / ссылка-кнопка. `data-variant="primary"` — главная, `"ghost"` — прозрачная, `"danger"` — опасная. `data-size="sm"/"lg"` | +| `.kt-ai-card` | карточка контента | +| `.kt-ai-chip` | статус-пилюля / тег | +| `.kt-ai-link` | текстовая ссылка | +| `.kt-ai-field` + `.kt-ai-input` / `.kt-ai-textarea` / `.kt-ai-select` | поле формы с подписью | + +**Один `primary` на экран.** Остальные кнопки — обычные или `ghost`. + +## Токены (`kt-ai-tokens.css`) + +Цвет: `--kt-ai-bg`, `--kt-ai-bg-soft`, `--kt-ai-fg`, `--kt-ai-fg-muted`, `--kt-ai-fg-faint`, +`--kt-ai-border`, `--kt-ai-divider`, `--kt-ai-card-bg`, `--kt-ai-card-border`, +`--kt-ai-primary`, `--kt-ai-link`, `--kt-ai-danger`. + +Отступы: `--kt-ai-space-1…12` (2px → 64px). Скругления: `--kt-ai-radius-md/lg/xl/2xl/3xl/full`. +Текст: `--kt-ai-text-xs…3xl`. Вес: `--kt-ai-weight-regular/medium/semibold/bold`. +Шрифты: `--kt-ai-font-sans` (Inter), `--kt-ai-font-mono`. + +**Тема** — атрибут на ``: `data-theme="auto"` (по системной, ставь его по умолчанию), +`"light"`, `"dark"`. Проверь страницу в обеих темах — с токенами это бесплатно. + +--- + +## Не лендинг, а приложение (дашборд, таблица, очередь заявок, чат) + +Тогда экран собирается **не вёрсткой руками, а конфигом**: + +1. Возьми `design-system/templates/kt-ai-app-shell.html` — самодостаточный HTML-каркас приложения + (без React и npm). +2. Опиши экран JSON-конфигом по `design-system/docs/PRODUCT_CONTRACT.md` и положи его в тег + `` внутри каркаса — он сам отрисует + таблицу, KPI, фильтры, drawer и темы. +3. Проверь конфиг: `python3 design-system/scripts/validate_product.py config.json --strict` → нужен `0/0`. + +Полные правила для сложных экранов — `design-system/AGENTS.md`, список компонентов — +`design-system/COMPONENTS.md`, приёмка — `design-system/CHECKLIST.md`. Читай их, когда лендинга +уже мало. + +--- + +## 📦 Готовые рецепты + +### Фото без ключей +- Одно и то же слово → одна и та же картинка: `https://picsum.photos/seed/coffee/800/600` +- По теме: `https://loremflickr.com/800/600/coffee` (тег прямо в URL) + +Вставляй с рамкой ДС: `…` + +### Кнопка WhatsApp +```html +Написать в WhatsApp +``` +`7XXXXXXXXXX` — номер в международном формате без `+`. + +### Форма заявки без бэкенда +```html +
+
+
+ +
+``` +Скажи юзеру: замени `EMAIL` на свою почту — заявки будут приходить туда (первая заявка активирует форму). + +### Favicon-эмодзи (без файла) +```html + +``` + +### Карта +На maps.google.com: место → «Поделиться» → «Встроить карту» → вставь iframe как есть: +```html + +``` + +### Плавные появления при скролле +```html + + +``` + +--- + +## Перед тем как сказать «готово» + +- [ ] Подключены все четыре CSS из `design-system/`, папка лежит в проекте (не забудь закоммитить её). +- [ ] В вёрстке нет сырых hex-цветов и чужих шрифтов. +- [ ] Страница нормально выглядит в светлой и тёмной теме и на телефоне (узкое окно). +- [ ] Один `data-variant="primary"` на экран, тексты — про юзера, а не «Lorem ipsum». diff --git a/index.html b/index.html new file mode 100644 index 0000000..de1d6be --- /dev/null +++ b/index.html @@ -0,0 +1,48 @@ + + + + + + Сравнение документов: ПКМ замечания и Приложение 1_СФ + + + +
+
+

Сравнительная таблица замечаний

+

Анализ учёта замечаний из файла "ПКМ_замечания" в файле "Приложение 1_СФ"

+
+
+ +
+ + + + +
+ +
+ + + + + + + + + + + + +
№Проблема / ЗамечаниеРекомендацииРешение (ПКМ)Решение (Приложение 1_СФ)Статус
+
+ +
+

Итоговая сводка

+
+
+
+ + + + diff --git a/script.js b/script.js new file mode 100644 index 0000000..1921f96 --- /dev/null +++ b/script.js @@ -0,0 +1,206 @@ +let data = []; +let currentFilter = 'all'; + +async function loadData() { + try { + const response = await fetch('data.json'); + const json = await response.json(); + data = json.zamечания || []; + renderTable(); + renderSummary(); + } catch (error) { + console.error('Ошибка загрузки данных:', error); + document.getElementById('table-body').innerHTML = + 'Ошибка загрузки данных'; + } +} + +function compareDecisions(zam, sf) { + if (!zam || !sf) return 'partially'; + + const zamNorm = zam.toLowerCase().trim(); + const sfNorm = sf.toLowerCase().trim(); + + if (zamNorm === sfNorm) return 'fully'; + + const zamWords = zamNorm.split(/[\s,;.]+/).filter(w => w.length > 3); + const sfWords = sfNorm.split(/[\s,;.]+/).filter(w => w.length > 3); + + const matchCount = zamWords.filter(w => sfWords.includes(w)).length; + const matchPercent = matchCount / Math.max(zamWords.length, sfWords.length); + + if (matchPercent >= 0.8) return 'fully'; + if (matchPercent >= 0.4) return 'partially'; + return 'partially'; +} + +function findAddedContent(zam, sf) { + if (!zam || !sf) return []; + + const zamNorm = zam.toLowerCase(); + const sfNorm = sf.toLowerCase(); + + const zamSentences = zamNorm.split(/[.!?]/).filter(s => s.trim().length > 10); + const sfSentences = sfNorm.split(/[.!?]/).filter(s => s.trim().length > 10); + + const added = sfSentences.filter(sfSent => + !zamSentences.some(zamSent => { + const words1 = sfSent.trim().split(/\s+/).filter(w => w.length > 3); + const words2 = zamSent.trim().split(/\s+/).filter(w => w.length > 3); + const match = words1.filter(w => words2.includes(w)).length; + return match / Math.max(words1.length, words2.length) > 0.6; + }) + ); + + return added.slice(0, 3); +} + +function getStatusHtml(status, added) { + const statusLabels = { + 'fully': 'Полностью учтено', + 'partially': 'Частично учтено', + 'added': 'Добавлено' + }; + + let html = `${statusLabels[status]}`; + + if (added && added.length > 0) { + html += `
+ Добавлено в Приложении 1_СФ: +
    ${added.map(item => `
  • ${item.trim()}.
  • `).join('')}
+
`; + } + + return html; +} + +function renderTable(filter = 'all') { + const tbody = document.getElementById('table-body'); + + const filtered = filter === 'all' + ? data + : data.filter(item => { + const status = compareDecisions(item.decision_zam, item.decision_sf); + const added = findAddedContent(item.decision_zam, item.decision_sf); + + if (filter === 'fully') return status === 'fully'; + if (filter === 'partially') return status === 'partially'; + if (filter === 'added') return added.length > 0; + return true; + }); + + if (filtered.length === 0) { + tbody.innerHTML = 'Нет данных для отображения'; + return; + } + + tbody.innerHTML = filtered.map(item => { + const status = compareDecisions(item.decision_zam, item.decision_sf); + const added = findAddedContent(item.decision_zam, item.decision_sf); + + return ` + + ${item.id} + ${item.problem} + ${item.recommendation} + ${item.decision_zam} + ${item.decision_sf} + ${getStatusHtml(status, added)} + + `; + }).join(''); +} + +function renderSummary() { + const total = data.length; + let fullyCount = 0; + let partiallyCount = 0; + let addedCount = 0; + const addedItems = []; + + data.forEach(item => { + const status = compareDecisions(item.decision_zam, item.decision_sf); + const added = findAddedContent(item.decision_zam, item.decision_sf); + + if (status === 'fully') fullyCount++; + else partiallyCount++; + + if (added.length > 0) { + addedCount++; + addedItems.push({ id: item.id, added }); + } + }); + + document.getElementById('summary').innerHTML = ` +
+ ${total} + Всего замечаний +
+
+ ${fullyCount} + Полностью учтено +
+
+ ${partiallyCount} + Частично учтено +
+
+ ${addedCount} + С дополнениями +
+ `; + + const summaryDetails = document.getElementById('summary-details'); + summaryDetails.innerHTML = ` +
+

📊 Общая статистика

+
    +
  • Всего замечаний проанализировано: ${total}
  • +
  • Полностью учтены в Приложении 1_СФ: ${fullyCount} (${((fullyCount/total)*100).toFixed(1)}%)
  • +
  • Частично учтены / изменены: ${partiallyCount} (${((partiallyCount/total)*100).toFixed(1)}%)
  • +
  • Замечаний с новыми дополнениями: ${addedCount}
  • +
+
+ +
+

✨ Что добавлено в Приложении 1_СФ

+ ${addedItems.length > 0 ? ` +
    + ${addedItems.map(item => ` +
  • + Замечание ${item.id}: +
      + ${item.added.map(a => `
    • ${a.trim()}.
    • `).join('')} +
    +
  • + `).join('')} +
+ ` : '
  • Новых положений не выявлено
  • '} +
    + +
    +

    📋 Ключевые дополнения в Приложении 1_СФ по сравнению с ПКМ замечаниями

    +
    + ${addedItems.length > 0 ? addedItems.map(item => ` +
    + Замечание ${item.id} +
      + ${item.added.map(a => `
    • ${a.trim()}.
    • `).join('')} +
    +
    + `).join('') : '

    Все решения полностью соответствуют исходным замечаниям

    '} +
    +
    + `; +} + +document.querySelectorAll('.filter-btn').forEach(btn => { + btn.addEventListener('click', () => { + document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active')); + btn.classList.add('active'); + currentFilter = btn.dataset.filter; + renderTable(currentFilter); + }); +}); + +document.addEventListener('DOMContentLoaded', loadData); diff --git a/style.css b/style.css new file mode 100644 index 0000000..23644db --- /dev/null +++ b/style.css @@ -0,0 +1,346 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + min-height: 100vh; + padding: 20px; + color: #333; +} + +.container { + max-width: 1600px; + margin: 0 auto; + background: white; + border-radius: 16px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); + overflow: hidden; +} + +.header { + background: linear-gradient(135deg, #2c3e50 0%, #3498db 100%); + color: white; + padding: 40px; + text-align: center; +} + +.header h1 { + font-size: 32px; + margin-bottom: 12px; + font-weight: 700; +} + +.subtitle { + font-size: 16px; + opacity: 0.9; + margin-bottom: 24px; +} + +.summary { + display: flex; + justify-content: center; + gap: 30px; + flex-wrap: wrap; +} + +.summary-item { + background: rgba(255, 255, 255, 0.15); + padding: 12px 24px; + border-radius: 8px; + backdrop-filter: blur(10px); +} + +.summary-item strong { + display: block; + font-size: 24px; + margin-bottom: 4px; +} + +.summary-item span { + font-size: 13px; + opacity: 0.9; +} + +.filters { + display: flex; + gap: 12px; + padding: 24px 40px; + background: #f8f9fa; + border-bottom: 2px solid #e9ecef; + flex-wrap: wrap; +} + +.filter-btn { + padding: 10px 20px; + border: 2px solid #dee2e6; + background: white; + border-radius: 8px; + cursor: pointer; + font-size: 14px; + font-weight: 500; + transition: all 0.3s ease; + color: #495057; +} + +.filter-btn:hover { + border-color: #3498db; + color: #3498db; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(52, 152, 219, 0.2); +} + +.filter-btn.active { + background: #3498db; + border-color: #3498db; + color: white; +} + +.table-wrapper { + overflow-x: auto; + max-height: 70vh; + overflow-y: auto; +} + +.comparison-table { + width: 100%; + border-collapse: collapse; + font-size: 13px; +} + +.comparison-table thead { + position: sticky; + top: 0; + z-index: 10; + background: #2c3e50; + color: white; +} + +.comparison-table th { + padding: 16px 12px; + text-align: left; + font-weight: 600; + border-right: 1px solid rgba(255, 255, 255, 0.2); + white-space: nowrap; +} + +.comparison-table th:last-child { + border-right: none; +} + +.comparison-table td { + padding: 14px 12px; + border-bottom: 1px solid #e9ecef; + vertical-align: top; + line-height: 1.5; +} + +.comparison-table tbody tr { + transition: all 0.2s ease; +} + +.comparison-table tbody tr:hover { + background: #f8f9fa; + transform: scale(1.005); +} + +.col-id { + width: 50px; + text-align: center; + font-weight: 700; + color: #2c3e50; +} + +.col-problem { + width: 20%; + min-width: 250px; +} + +.col-recommendation { + width: 20%; + min-width: 250px; +} + +.col-decision-zam { + width: 18%; + min-width: 220px; + background: #fff3cd; +} + +.col-decision-sf { + width: 18%; + min-width: 220px; + background: #d4edda; +} + +.col-status { + width: 120px; + text-align: center; +} + +.status-badge { + display: inline-block; + padding: 6px 12px; + border-radius: 20px; + font-size: 12px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.status-fully { + background: #d4edda; + color: #155724; +} + +.status-partially { + background: #fff3cd; + color: #856404; +} + +.status-added { + background: #cce5ff; + color: #004085; +} + +.summary-block { + padding: 40px; + background: #f8f9fa; + border-top: 2px solid #e9ecef; +} + +.summary-block h2 { + font-size: 24px; + margin-bottom: 24px; + color: #2c3e50; +} + +#summary-details { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 20px; +} + +.summary-card { + background: white; + padding: 24px; + border-radius: 12px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + border-left: 4px solid #3498db; +} + +.summary-card h3 { + font-size: 16px; + margin-bottom: 12px; + color: #2c3e50; +} + +.summary-card ul { + list-style: none; + padding-left: 0; +} + +.summary-card li { + padding: 8px 0; + border-bottom: 1px solid #f1f3f5; + font-size: 13px; + display: flex; + align-items: flex-start; + gap: 10px; +} + +.summary-card li:last-child { + border-bottom: none; +} + +.summary-card li::before { + content: "✓"; + color: #27ae60; + font-weight: 700; + flex-shrink: 0; +} + +.changes-highlight { + background: #e8f5e9; + padding: 12px; + border-radius: 6px; + margin-top: 8px; + font-size: 12px; + border-left: 3px solid #27ae60; +} + +.changes-highlight strong { + color: #27ae60; + display: block; + margin-bottom: 6px; +} + +.changes-highlight ul { + list-style: disc; + padding-left: 20px; + margin: 0; +} + +.changes-highlight li { + padding: 4px 0; + border: none; +} + +@media (max-width: 1200px) { + .comparison-table { + font-size: 12px; + } + + .col-problem, + .col-recommendation { + min-width: 200px; + } +} + +@media (max-width: 768px) { + body { + padding: 10px; + } + + .header { + padding: 24px 20px; + } + + .header h1 { + font-size: 24px; + } + + .filters { + padding: 16px 20px; + } + + .table-wrapper { + max-height: 60vh; + } + + .comparison-table th, + .comparison-table td { + padding: 10px 8px; + } +} + +::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +::-webkit-scrollbar-track { + background: #f1f1f1; +} + +::-webkit-scrollbar-thumb { + background: #c1c1c1; + border-radius: 5px; +} + +::-webkit-scrollbar-thumb:hover { + background: #a8a8a8; +} diff --git a/ПКМ_замечания.xlsx b/ПКМ_замечания.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b025fafc65f25c06bf4643c0e38e1de95516cd31 GIT binary patch literal 29850 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 J(CQyg{{?h?b0Po$ literal 0 HcmV?d00001