301 lines
21 KiB
HTML
301 lines
21 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Архитектура — блок-схемы</title>
|
||
<style>
|
||
:root {
|
||
--bg: #0d1117; --fg: #c9d1d9; --muted: #8b949e;
|
||
--accent: #58a6ff; --green: #3fb950; --border: #30363d;
|
||
}
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
body { font: 15px/1.5 -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: var(--bg); color: var(--fg); max-width: 960px; margin: 0 auto; padding: 32px 20px 80px; }
|
||
h1 { font-size: 26px; margin-bottom: 8px; }
|
||
h2 { font-size: 18px; margin-top: 48px; margin-bottom: 16px; color: var(--accent); }
|
||
.nav { margin-bottom: 24px; }
|
||
.nav a { color: var(--accent); text-decoration: none; }
|
||
.nav a:hover { text-decoration: underline; }
|
||
svg { display: block; max-width: 100%; height: auto; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="nav"><a href="/docs/architect">← Архитектура (текст)</a></div>
|
||
|
||
<h1>🏗️ Архитектура — блок-схемы</h1>
|
||
|
||
<h2>1. Система — компоненты и связи</h2>
|
||
|
||
<svg viewBox="0 0 920 340" xmlns="http://www.w3.org/2000/svg">
|
||
<defs>
|
||
<marker id="a1" markerWidth="7" markerHeight="5" refX="7" refY="2.5" orient="auto"><path d="M0,0 L7,2.5 L0,5 Z" fill="#58a6ff"/></marker>
|
||
<marker id="a2" markerWidth="7" markerHeight="5" refX="7" refY="2.5" orient="auto"><path d="M0,0 L7,2.5 L0,5 Z" fill="#3fb950"/></marker>
|
||
<filter id="sh"><feDropShadow dx="0" dy="2" stdDeviation="3" flood-opacity="0.25"/></filter>
|
||
<linearGradient id="gradFlask" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#1a2a3a"/><stop offset="100%" stop-color="#0d1a28"/></linearGradient>
|
||
<linearGradient id="gradVM" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#1a2a1a"/><stop offset="100%" stop-color="#0d1a0d"/></linearGradient>
|
||
<linearGradient id="gradDB" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#2a1a2a"/><stop offset="100%" stop-color="#1a0d1a"/></linearGradient>
|
||
<linearGradient id="gradLLM" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#3a2a1a"/><stop offset="100%" stop-color="#281a0d"/></linearGradient>
|
||
<linearGradient id="gradUser" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#2a1a1a"/><stop offset="100%" stop-color="#1a0d0d"/></linearGradient>
|
||
</defs>
|
||
|
||
<!-- User -->
|
||
<rect x="30" y="100" width="140" height="90" rx="10" fill="url(#gradUser)" stroke="#f85149" stroke-width="1.5" filter="url(#sh)"/>
|
||
<text x="100" y="135" text-anchor="middle" fill="#f85149" font-size="15" font-weight="bold">👤 Пользователь</text>
|
||
<text x="100" y="155" text-anchor="middle" fill="#8b949e" font-size="11">Браузер</text>
|
||
<text x="100" y="172" text-anchor="middle" fill="#8b949e" font-size="11">Загрузка файлов</text>
|
||
|
||
<!-- Arrow User → Flask -->
|
||
<line x1="172" y1="130" x2="230" y2="80" stroke="#f85149" stroke-width="1.5" marker-end="url(#a1)"/>
|
||
<text x="205" y="95" fill="#8b949e" font-size="9">HTTPS</text>
|
||
|
||
<line x1="172" y1="150" x2="230" y2="150" stroke="#58a6ff" stroke-width="1.5" marker-end="url(#a1)"/>
|
||
<text x="205" y="143" fill="#8b949e" font-size="9">SSE</text>
|
||
|
||
<!-- Flask -->
|
||
<rect x="235" y="50" width="160" height="120" rx="10" fill="url(#gradFlask)" stroke="#58a6ff" stroke-width="1.5" filter="url(#sh)"/>
|
||
<text x="315" y="80" text-anchor="middle" fill="#58a6ff" font-size="14" font-weight="bold">⚡ Flask-фронтенд</text>
|
||
<text x="315" y="100" text-anchor="middle" fill="#8b949e" font-size="10">Managed Python (Nubes)</text>
|
||
<text x="315" y="118" text-anchor="middle" fill="#8b949e" font-size="10">Jinja2-шаблоны</text>
|
||
<text x="315" y="136" text-anchor="middle" fill="#8b949e" font-size="10">Промпт-редактор</text>
|
||
<text x="315" y="154" text-anchor="middle" fill="#8b949e" font-size="10">Чат с LLM</text>
|
||
|
||
<!-- Arrow Flask → VM -->
|
||
<line x1="397" y1="110" x2="455" y2="110" stroke="#58a6ff" stroke-width="1.5" marker-end="url(#a1)"/>
|
||
<text x="430" y="103" fill="#8b949e" font-size="9">REST API</text>
|
||
|
||
<!-- VM box -->
|
||
<rect x="460" y="15" width="230" height="210" rx="10" fill="none" stroke="#30363d" stroke-width="1" stroke-dasharray="6,4"/>
|
||
<text x="575" y="35" text-anchor="middle" fill="#8b949e" font-size="11">Выделенная VM</text>
|
||
|
||
<!-- Parsing -->
|
||
<rect x="480" y="50" width="190" height="50" rx="8" fill="url(#gradVM)" stroke="#3fb950" stroke-width="1" filter="url(#sh)"/>
|
||
<text x="575" y="72" text-anchor="middle" fill="#3fb950" font-size="12" font-weight="bold">📄 Парсинг документов</text>
|
||
<text x="575" y="90" text-anchor="middle" fill="#8b949e" font-size="10">pdfplumber · python-docx</text>
|
||
|
||
<!-- Classification -->
|
||
<rect x="480" y="110" width="190" height="50" rx="8" fill="url(#gradVM)" stroke="#bc8cff" stroke-width="1" filter="url(#sh)"/>
|
||
<text x="575" y="132" text-anchor="middle" fill="#bc8cff" font-size="12" font-weight="bold">🏷️ Классификация</text>
|
||
<text x="575" y="150" text-anchor="middle" fill="#8b949e" font-size="10">3-этапный фильтр мусора</text>
|
||
|
||
<!-- Comparison -->
|
||
<rect x="480" y="170" width="190" height="45" rx="8" fill="url(#gradVM)" stroke="#d2991d" stroke-width="1" filter="url(#sh)"/>
|
||
<text x="575" y="190" text-anchor="middle" fill="#d2991d" font-size="12" font-weight="bold">🤖 LLM-сравнение</text>
|
||
<text x="575" y="207" text-anchor="middle" fill="#8b949e" font-size="10">extract + diff · группировка</text>
|
||
|
||
<!-- Internal arrows -->
|
||
<line x1="575" y1="100" x2="575" y2="108" stroke="#58a6ff" stroke-width="1" marker-end="url(#a1)"/>
|
||
<line x1="575" y1="160" x2="575" y2="168" stroke="#58a6ff" stroke-width="1" marker-end="url(#a1)"/>
|
||
|
||
<!-- Arrow VM → LLM -->
|
||
<line x1="692" y1="140" x2="750" y2="90" stroke="#d2991d" stroke-width="1.5" marker-end="url(#a1)"/>
|
||
<text x="725" y="108" fill="#8b949e" font-size="9">HTTP/2</text>
|
||
|
||
<!-- LLM -->
|
||
<rect x="755" y="60" width="140" height="80" rx="10" fill="url(#gradLLM)" stroke="#d2991d" stroke-width="1.5" filter="url(#sh)"/>
|
||
<text x="825" y="90" text-anchor="middle" fill="#d2991d" font-size="13" font-weight="bold">🧠 LLM</text>
|
||
<text x="825" y="110" text-anchor="middle" fill="#8b949e" font-size="10">api.aillm.ru</text>
|
||
<text x="825" y="128" text-anchor="middle" fill="#8b949e" font-size="10">gpt-oss-120b</text>
|
||
|
||
<!-- Arrow VM ↔ DB -->
|
||
<line x1="575" y1="228" x2="575" y2="260" stroke="#bc8cff" stroke-width="1.5" marker-end="url(#a1)"/>
|
||
|
||
<!-- DB -->
|
||
<rect x="470" y="265" width="210" height="55" rx="10" fill="url(#gradDB)" stroke="#bc8cff" stroke-width="1.5" filter="url(#sh)"/>
|
||
<text x="575" y="290" text-anchor="middle" fill="#bc8cff" font-size="13" font-weight="bold">🗄️ PostgreSQL 15</text>
|
||
<text x="575" y="310" text-anchor="middle" fill="#8b949e" font-size="10">JSONB · Event Sourcing · spec_events</text>
|
||
</svg>
|
||
|
||
<h2>2. Пайплайн обработки одного файла</h2>
|
||
|
||
<svg viewBox="0 0 920 280" xmlns="http://www.w3.org/2000/svg">
|
||
<defs>
|
||
<marker id="b1" markerWidth="6" markerHeight="4" refX="6" refY="2" orient="auto"><path d="M0,0 L6,2 L0,4 Z" fill="#58a6ff"/></marker>
|
||
<marker id="b2" markerWidth="6" markerHeight="4" refX="6" refY="2" orient="auto"><path d="M0,0 L6,2 L0,4 Z" fill="#f85149"/></marker>
|
||
<filter id="sh2"><feDropShadow dx="0" dy="1" stdDeviation="2" flood-opacity="0.2"/></filter>
|
||
</defs>
|
||
|
||
<!-- Stage 1 -->
|
||
<rect x="10" y="30" width="135" height="90" rx="8" fill="#1a2a1a" stroke="#3fb950" stroke-width="1.5" filter="url(#sh2)"/>
|
||
<text x="77" y="55" text-anchor="middle" fill="#3fb950" font-size="12" font-weight="bold">📤 Загрузка</text>
|
||
<text x="77" y="73" text-anchor="middle" fill="#8b949e" font-size="9">Multipart-парсинг</text>
|
||
<text x="77" y="88" text-anchor="middle" fill="#8b949e" font-size="9">SHA-256 хеш</text>
|
||
<text x="77" y="103" text-anchor="middle" fill="#8b949e" font-size="9">Формат: pdf/docx/zip</text>
|
||
|
||
<line x1="147" y1="75" x2="172" y2="75" stroke="#58a6ff" stroke-width="1.5" marker-end="url(#b1)"/>
|
||
|
||
<!-- Stage 2 -->
|
||
<rect x="177" y="30" width="135" height="90" rx="8" fill="#1a2a3a" stroke="#58a6ff" stroke-width="1.5" filter="url(#sh2)"/>
|
||
<text x="244" y="55" text-anchor="middle" fill="#58a6ff" font-size="12" font-weight="bold">🔍 Парсинг</text>
|
||
<text x="244" y="73" text-anchor="middle" fill="#8b949e" font-size="9">Извлечение текста</text>
|
||
<text x="244" y="88" text-anchor="middle" fill="#8b949e" font-size="9">Извлечение таблиц</text>
|
||
<text x="244" y="103" text-anchor="middle" fill="#8b949e" font-size="9">→ elements_json</text>
|
||
|
||
<line x1="314" y1="75" x2="339" y2="75" stroke="#58a6ff" stroke-width="1.5" marker-end="url(#b1)"/>
|
||
|
||
<!-- Stage 3a -->
|
||
<rect x="344" y="30" width="145" height="90" rx="8" fill="#2a1a3a" stroke="#bc8cff" stroke-width="1.5" filter="url(#sh2)"/>
|
||
<text x="416" y="52" text-anchor="middle" fill="#bc8cff" font-size="12" font-weight="bold">🏷️ Фильтр #1-#2</text>
|
||
<text x="416" y="68" text-anchor="middle" fill="#8b949e" font-size="9">Имя файла → мусор?</text>
|
||
<text x="416" y="83" text-anchor="middle" fill="#8b949e" font-size="9">Заголовки → мусор?</text>
|
||
<text x="416" y="98" text-anchor="middle" fill="#8b949e" font-size="9">0 токенов LLM</text>
|
||
<text x="416" y="113" text-anchor="middle" fill="#f85149" font-size="8">мусор → стоп</text>
|
||
|
||
<line x1="491" y1="75" x2="516" y2="75" stroke="#58a6ff" stroke-width="1.5" marker-end="url(#b1)"/>
|
||
|
||
<!-- Stage 3b -->
|
||
<rect x="521" y="30" width="145" height="90" rx="8" fill="#2a2a1a" stroke="#d2991d" stroke-width="1.5" filter="url(#sh2)"/>
|
||
<text x="593" y="52" text-anchor="middle" fill="#d2991d" font-size="12" font-weight="bold">🤖 Фильтр #3 — LLM</text>
|
||
<text x="593" y="68" text-anchor="middle" fill="#8b949e" font-size="9">Тип: договор/допник/</text>
|
||
<text x="593" y="83" text-anchor="middle" fill="#8b949e" font-size="9">спецификация/мусор</text>
|
||
<text x="593" y="98" text-anchor="middle" fill="#8b949e" font-size="9">Номер, дата, контрагент</text>
|
||
<text x="593" y="113" text-anchor="middle" fill="#f85149" font-size="8">мусор → стоп</text>
|
||
|
||
<line x1="668" y1="75" x2="693" y2="75" stroke="#58a6ff" stroke-width="1.5" marker-end="url(#b1)"/>
|
||
|
||
<!-- Stage 4 -->
|
||
<rect x="698" y="30" width="100" height="90" rx="8" fill="#3a2a1a" stroke="#d2991d" stroke-width="1.5" filter="url(#sh2)"/>
|
||
<text x="748" y="60" text-anchor="middle" fill="#d2991d" font-size="12" font-weight="bold">📋 Группи-</text>
|
||
<text x="748" y="78" text-anchor="middle" fill="#d2991d" font-size="12" font-weight="bold">ровка</text>
|
||
<text x="748" y="96" text-anchor="middle" fill="#8b949e" font-size="9">По номерам</text>
|
||
<text x="748" y="111" text-anchor="middle" fill="#8b949e" font-size="9">договоров</text>
|
||
|
||
<line x1="800" y1="75" x2="825" y2="75" stroke="#58a6ff" stroke-width="1.5" marker-end="url(#b1)"/>
|
||
|
||
<!-- Stage 5 -->
|
||
<rect x="830" y="30" width="80" height="90" rx="8" fill="#1a3a2a" stroke="#3fb950" stroke-width="1.5" filter="url(#sh2)"/>
|
||
<text x="870" y="60" text-anchor="middle" fill="#3fb950" font-size="12" font-weight="bold">Срав-</text>
|
||
<text x="870" y="78" text-anchor="middle" fill="#3fb950" font-size="12" font-weight="bold">нение</text>
|
||
<text x="870" y="100" text-anchor="middle" fill="#8b949e" font-size="9">ADD</text>
|
||
<text x="870" y="114" text-anchor="middle" fill="#8b949e" font-size="9">UPDATE</text>
|
||
|
||
<!-- Protection Bar -->
|
||
<rect x="10" y="145" width="900" height="40" rx="6" fill="#1a0a0a" stroke="#f85149" stroke-width="1" stroke-dasharray="3,2"/>
|
||
<text x="460" y="170" text-anchor="middle" fill="#f85149" font-size="11" font-weight="bold">🛡️ Защита: ZIP-бомба (500/500/100×) · Path traversal · Whitelist форматов · content_hash · UNRESOLVED · нормализация чисел/дат · price×qty=sum</text>
|
||
|
||
<!-- Output Bar -->
|
||
<rect x="10" y="210" width="900" height="50" rx="6" fill="#161b22" stroke="#3fb950" stroke-width="1.5" filter="url(#sh2)"/>
|
||
<text x="460" y="233" text-anchor="middle" fill="#3fb950" font-size="12" font-weight="bold">📊 База: documents (метаданные + elements_json) · classify_results · spec_events (аудит) · spec_current (спецификация) · prompts (версионирование)</text>
|
||
<text x="460" y="250" text-anchor="middle" fill="#8b949e" font-size="9">Бинарные файлы удаляются после парсинга. Промежуточные данные — требуется автоочистка.</text>
|
||
</svg>
|
||
|
||
<h2>3. Event Sourcing — как работает сравнение</h2>
|
||
|
||
<svg viewBox="0 0 920 380" xmlns="http://www.w3.org/2000/svg">
|
||
<defs>
|
||
<marker id="c1" markerWidth="6" markerHeight="4" refX="6" refY="2" orient="auto"><path d="M0,0 L6,2 L0,4 Z" fill="#58a6ff"/></marker>
|
||
<filter id="sh3"><feDropShadow dx="0" dy="1" stdDeviation="2" flood-opacity="0.2"/></filter>
|
||
</defs>
|
||
|
||
<!-- Documents row -->
|
||
<text x="460" y="24" text-anchor="middle" fill="#8b949e" font-size="12">Документы группы (отсортированы по doc_date)</text>
|
||
|
||
<rect x="10" y="38" width="100" height="55" rx="6" fill="#1a2a3a" stroke="#58a6ff" stroke-width="1" filter="url(#sh3)"/>
|
||
<text x="60" y="60" text-anchor="middle" fill="#58a6ff" font-size="10" font-weight="bold">📄 Договор</text>
|
||
<text x="60" y="78" text-anchor="middle" fill="#8b949e" font-size="9">базовый</text>
|
||
|
||
<rect x="130" y="38" width="80" height="55" rx="6" fill="#1a2a3a" stroke="#58a6ff" stroke-width="1" filter="url(#sh3)"/>
|
||
<text x="170" y="60" text-anchor="middle" fill="#58a6ff" font-size="10" font-weight="bold">📄 Допник</text>
|
||
<text x="170" y="78" text-anchor="middle" fill="#8b949e" font-size="9">#1</text>
|
||
|
||
<rect x="230" y="38" width="80" height="55" rx="6" fill="#1a2a3a" stroke="#58a6ff" stroke-width="1" filter="url(#sh3)"/>
|
||
<text x="270" y="60" text-anchor="middle" fill="#58a6ff" font-size="10" font-weight="bold">📄 Допник</text>
|
||
<text x="270" y="78" text-anchor="middle" fill="#8b949e" font-size="9">#2</text>
|
||
|
||
<text x="350" y="70" fill="#8b949e" font-size="20">...</text>
|
||
|
||
<!-- Arrow to Extract -->
|
||
<line x1="60" y1="95" x2="60" y2="130" stroke="#58a6ff" stroke-width="1.5" marker-end="url(#c1)"/>
|
||
|
||
<!-- Extract box -->
|
||
<rect x="10" y="135" width="200" height="70" rx="8" fill="#1a2a3a" stroke="#d2991d" stroke-width="1.5" filter="url(#sh3)"/>
|
||
<text x="110" y="158" text-anchor="middle" fill="#d2991d" font-size="12" font-weight="bold">🤖 LLM: промпт extract</text>
|
||
<text x="110" y="176" text-anchor="middle" fill="#8b949e" font-size="10">Извлечение всех услуг</text>
|
||
<text x="110" y="194" text-anchor="middle" fill="#8b949e" font-size="10">→ массив ADD-операций</text>
|
||
|
||
<line x1="212" y1="170" x2="242" y2="170" stroke="#58a6ff" stroke-width="1.5" marker-end="url(#c1)"/>
|
||
|
||
<!-- Events box -->
|
||
<rect x="247" y="130" width="200" height="80" rx="8" fill="#2a1a2a" stroke="#bc8cff" stroke-width="1.5" filter="url(#sh3)"/>
|
||
<text x="347" y="153" text-anchor="middle" fill="#bc8cff" font-size="12" font-weight="bold">🗄️ spec_events</text>
|
||
<text x="347" y="171" text-anchor="middle" fill="#8b949e" font-size="10">ADD услуга X</text>
|
||
<text x="347" y="187" text-anchor="middle" fill="#8b949e" font-size="10">ADD услуга Y</text>
|
||
<text x="347" y="203" text-anchor="middle" fill="#8b949e" font-size="10">(неизменяемый лог)</text>
|
||
|
||
<line x1="347" y1="212" x2="347" y2="242" stroke="#58a6ff" stroke-width="1.5" marker-end="url(#c1)"/>
|
||
|
||
<!-- Current spec -->
|
||
<rect x="247" y="247" width="200" height="70" rx="8" fill="#1a2a1a" stroke="#3fb950" stroke-width="1.5" filter="url(#sh3)"/>
|
||
<text x="347" y="272" text-anchor="middle" fill="#3fb950" font-size="12" font-weight="bold">📊 spec_current</text>
|
||
<text x="347" y="292" text-anchor="middle" fill="#8b949e" font-size="10">Услуга X | 100₽ | 10 шт</text>
|
||
<text x="347" y="308" text-anchor="middle" fill="#8b949e" font-size="10">Услуга Y | 200₽ | 5 шт</text>
|
||
|
||
<!-- Arrow back to LLM for diff -->
|
||
<line x1="449" y1="282" x2="500" y2="282" stroke="#3fb950" stroke-width="1.5" marker-end="url(#c1)"/>
|
||
|
||
<!-- Diff box -->
|
||
<rect x="505" y="135" width="200" height="70" rx="8" fill="#3a2a1a" stroke="#d2991d" stroke-width="1.5" filter="url(#sh3)"/>
|
||
<text x="605" y="158" text-anchor="middle" fill="#d2991d" font-size="12" font-weight="bold">🤖 LLM: промпт diff</text>
|
||
<text x="605" y="176" text-anchor="middle" fill="#8b949e" font-size="10">(допник #1) vs spec_current</text>
|
||
<text x="605" y="194" text-anchor="middle" fill="#8b949e" font-size="10">→ ADD / UPDATE / DELETE</text>
|
||
|
||
<line x1="707" y1="170" x2="737" y2="170" stroke="#58a6ff" stroke-width="1.5" marker-end="url(#c1)"/>
|
||
|
||
<!-- Events 2 -->
|
||
<rect x="742" y="130" width="168" height="80" rx="8" fill="#2a1a2a" stroke="#bc8cff" stroke-width="1.5" filter="url(#sh3)"/>
|
||
<text x="826" y="153" text-anchor="middle" fill="#bc8cff" font-size="12" font-weight="bold">🗄️ spec_events</text>
|
||
<text x="826" y="171" text-anchor="middle" fill="#8b949e" font-size="10">UPDATE услуга X</text>
|
||
<text x="826" y="187" text-anchor="middle" fill="#8b949e" font-size="10">DELETE услуга Y</text>
|
||
<text x="826" y="203" text-anchor="middle" fill="#8b949e" font-size="10">ADD услуга Z</text>
|
||
|
||
<line x1="826" y1="212" x2="826" y2="242" stroke="#58a6ff" stroke-width="1.5" marker-end="url(#c1)"/>
|
||
|
||
<!-- Updated spec -->
|
||
<rect x="726" y="247" width="184" height="70" rx="8" fill="#1a2a1a" stroke="#3fb950" stroke-width="1.5" filter="url(#sh3)"/>
|
||
<text x="818" y="272" text-anchor="middle" fill="#3fb950" font-size="12" font-weight="bold">📊 spec_current (обн.)</text>
|
||
<text x="818" y="292" text-anchor="middle" fill="#8b949e" font-size="10">Услуга X | 150₽ | 10 шт</text>
|
||
<text x="818" y="308" text-anchor="middle" fill="#8b949e" font-size="10">Услуга Z | 300₽ | 2 шт</text>
|
||
|
||
<!-- Arrows between events -->
|
||
<line x1="473" y1="170" x2="505" y2="150" stroke="#d2991d" stroke-width="1" stroke-dasharray="3,2"/>
|
||
<text x="492" y="148" fill="#8b949e" font-size="8">цикл по допникам</text>
|
||
|
||
<!-- Legend -->
|
||
<rect x="10" y="340" width="900" height="30" rx="4" fill="#161b22" stroke="#30363d" stroke-width="0.5"/>
|
||
<text x="460" y="360" text-anchor="middle" fill="#8b949e" font-size="10">Каждый допник сравнивается с актуальной spec_current → операции накапливаются в spec_events → spec_current пересчитывается</text>
|
||
</svg>
|
||
|
||
<h2>4. Защита — эшелоны</h2>
|
||
|
||
<svg viewBox="0 0 920 220" xmlns="http://www.w3.org/2000/svg">
|
||
<defs>
|
||
<marker id="d1" markerWidth="5" markerHeight="3" refX="5" refY="1.5" orient="auto"><path d="M0,0 L5,1.5 L0,3 Z" fill="#f85149"/></marker>
|
||
<filter id="sh4"><feDropShadow dx="0" dy="1" stdDeviation="2" flood-opacity="0.2"/></filter>
|
||
</defs>
|
||
|
||
<!-- Layer 1: Upload -->
|
||
<rect x="10" y="10" width="900" height="40" rx="6" fill="#1a0a0a" stroke="#f85149" stroke-width="1" filter="url(#sh4)"/>
|
||
<text x="460" y="35" text-anchor="middle" fill="#f85149" font-size="12" font-weight="bold">🔴 Уровень 1 — Загрузка: ZIP-бомба (500 файлов / 500MB / ratio 100×) · Path traversal · Whitelist .pdf .docx .doc .zip</text>
|
||
|
||
<line x1="460" y1="50" x2="460" y2="58" stroke="#f85149" stroke-width="1" marker-end="url(#d1)"/>
|
||
|
||
<!-- Layer 2: Parse -->
|
||
<rect x="30" y="62" width="860" height="40" rx="6" fill="#2a1a0a" stroke="#d2991d" stroke-width="1" filter="url(#sh4)"/>
|
||
<text x="460" y="87" text-anchor="middle" fill="#d2991d" font-size="12" font-weight="bold">🟠 Уровень 2 — Парсинг: cp437→utf8 для битых имён · content_hash (SHA-256) · дедупликация · try/except → logging.warning</text>
|
||
|
||
<line x1="460" y1="102" x2="460" y2="110" stroke="#f85149" stroke-width="1" marker-end="url(#d1)"/>
|
||
|
||
<!-- Layer 3: Classify -->
|
||
<rect x="50" y="114" width="820" height="40" rx="6" fill="#2a2a0a" stroke="#e3b341" stroke-width="1" filter="url(#sh4)"/>
|
||
<text x="460" y="139" text-anchor="middle" fill="#e3b341" font-size="12" font-weight="bold">🟡 Уровень 3 — Классификация: фильтр по имени файла · фильтр по заголовкам (2000 симв.) · LLM-фильтр · мусор → garbage</text>
|
||
|
||
<line x1="460" y1="154" x2="460" y2="162" stroke="#f85149" stroke-width="1" marker-end="url(#d1)"/>
|
||
|
||
<!-- Layer 4: Compare -->
|
||
<rect x="70" y="166" width="780" height="40" rx="6" fill="#1a2a0a" stroke="#3fb950" stroke-width="1" filter="url(#sh4)"/>
|
||
<text x="460" y="191" text-anchor="middle" fill="#3fb950" font-size="12" font-weight="bold">🟢 Уровень 4 — Сравнение: ADD без имени → UNRESOLVED · UPDATE/DELETE без цели → UNRESOLVED · нормализация 1 000,50→1000.50 · дат · price×qty=sum</text>
|
||
</svg>
|
||
|
||
</body>
|
||
</html>
|