wasrusgen1-crm/Mokap/presentation_architecture.html
wasrusgen ffa56b1d18 add: Mokap mockups, CLAUDE.md, project structure
- 15 HTML mockups (admin, assembler, manager, owner и др.)
- CLAUDE.md с политикой работы с файлами
- .claude/launch.json

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 13:39:30 +03:00

619 lines
38 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Архитектура платформы @wasrusgen1 CRM</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<style>
:root{
--bg:#0F0F1A;
--accent:#3B82F6;
--accent2:#60A5FA;
--success:#10B981;
--warn:#F59E0B;
--text:#F8FAFC;
--card:#1A1A2E;
--muted:#94A3B8;
--border:rgba(148,163,184,.16);
--mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
}
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%}
body{
font-family:'Inter',system-ui,sans-serif;
background:var(--bg);
color:var(--text);
overflow:hidden;
}
/* ===== DECK ===== */
.deck{position:fixed;inset:0}
.slide{
position:absolute;inset:0;
display:flex;flex-direction:column;
padding:64px 88px 90px;
opacity:0;visibility:hidden;
transform:translateY(14px);
transition:opacity .5s ease,transform .5s ease,visibility .5s;
overflow:hidden;
}
.slide.active{opacity:1;visibility:visible;transform:none;z-index:2}
/* aspect frame to keep 16:9 readable on any screen */
.stage{
position:relative;width:100%;height:100%;
max-width:1920px;max-height:1080px;margin:auto;
}
/* background glows */
.slide::before{
content:"";position:absolute;width:760px;height:760px;border-radius:50%;
background:radial-gradient(circle,rgba(59,130,246,.16),transparent 62%);
top:-300px;right:-200px;pointer-events:none;
}
.slide::after{
content:"";position:absolute;width:620px;height:620px;border-radius:50%;
background:radial-gradient(circle,rgba(16,185,129,.08),transparent 65%);
bottom:-280px;left:-160px;pointer-events:none;
}
/* ===== TYPO ===== */
.kicker{
font-family:var(--mono);font-size:14px;letter-spacing:.28em;text-transform:uppercase;
color:var(--accent2);margin-bottom:18px;display:flex;align-items:center;gap:12px;
}
.kicker::before{content:"";width:30px;height:2px;background:var(--accent);display:inline-block}
h1{font-size:64px;font-weight:900;line-height:1.04;letter-spacing:-.02em}
h2{font-size:44px;font-weight:800;line-height:1.08;letter-spacing:-.015em;margin-bottom:10px}
.sub{color:var(--muted);font-size:20px;font-weight:400;line-height:1.5;max-width:980px}
.slide-body{flex:1;min-height:0;margin-top:34px;display:flex;flex-direction:column}
/* ===== TITLE SLIDE ===== */
.title-slide{justify-content:center}
.title-slide h1{font-size:84px;max-width:1300px}
.title-slide .lede{font-size:30px;color:var(--accent2);font-weight:600;margin-top:26px}
.brandtag{
display:inline-flex;align-items:center;gap:14px;
font-family:var(--mono);font-size:16px;color:var(--muted);
border:1px solid var(--border);border-radius:100px;padding:12px 22px;margin-bottom:40px;
background:rgba(26,26,46,.6);width:max-content;
}
.dot{width:10px;height:10px;border-radius:50%;background:var(--success);box-shadow:0 0 14px var(--success)}
.title-meta{
margin-top:64px;display:flex;gap:64px;flex-wrap:wrap;
}
.title-meta div span{display:block;font-family:var(--mono);font-size:13px;color:var(--muted);letter-spacing:.1em;text-transform:uppercase;margin-bottom:6px}
.title-meta div strong{font-size:24px;font-weight:700}
/* ===== CARDS / GRID ===== */
.grid{display:grid;gap:22px}
.g2{grid-template-columns:repeat(2,1fr)}
.g3{grid-template-columns:repeat(3,1fr)}
.g4{grid-template-columns:repeat(4,1fr)}
.card{
background:linear-gradient(160deg,var(--card),rgba(26,26,46,.55));
border:1px solid var(--border);border-radius:18px;padding:28px 26px;
position:relative;overflow:hidden;
}
.card .ic{
width:46px;height:46px;border-radius:12px;display:flex;align-items:center;justify-content:center;
font-size:22px;margin-bottom:16px;background:rgba(59,130,246,.14);border:1px solid rgba(59,130,246,.3);
}
.card h3{font-size:21px;font-weight:700;margin-bottom:8px}
.card p{color:var(--muted);font-size:16px;line-height:1.55}
.card.accent{border-color:rgba(59,130,246,.45)}
.card.success .ic{background:rgba(16,185,129,.14);border-color:rgba(16,185,129,.35)}
.card.warn .ic{background:rgba(245,158,11,.14);border-color:rgba(245,158,11,.35)}
.tag{font-family:var(--mono);font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--accent2);font-weight:600}
.pill{display:inline-block;font-family:var(--mono);font-size:13px;padding:4px 12px;border-radius:100px;border:1px solid var(--border);color:var(--muted)}
.pill.rec{color:var(--success);border-color:rgba(16,185,129,.4);background:rgba(16,185,129,.08)}
/* ===== CODE / DIAGRAM BLOCK ===== */
.codeblock{
font-family:var(--mono);background:#0A0A12;border:1px solid var(--border);
border-radius:16px;padding:30px 34px;font-size:18px;line-height:1.85;color:#CBD5E1;
box-shadow:inset 0 0 0 1px rgba(59,130,246,.05);position:relative;
}
.codeblock .winbar{position:absolute;top:14px;left:18px;display:flex;gap:7px}
.codeblock .winbar i{width:11px;height:11px;border-radius:50%;display:inline-block}
.codeblock pre{margin-top:14px;white-space:pre;overflow:auto}
.c-key{color:var(--accent2)} .c-ok{color:var(--success)} .c-warn{color:var(--warn)}
.c-mut{color:var(--muted)} .c-acc{color:var(--accent);font-weight:700}
/* ===== ARCH MAP ===== */
.archmap{display:flex;flex-direction:column;align-items:center;gap:0;font-family:var(--mono)}
.node{
border:1px solid var(--border);border-radius:14px;padding:16px 28px;background:var(--card);
text-align:center;min-width:300px;
}
.node strong{display:block;font-size:20px;font-family:'Inter';font-weight:700}
.node span{font-size:13px;color:var(--muted)}
.node.master{border-color:var(--accent);box-shadow:0 0 32px rgba(59,130,246,.25);background:rgba(59,130,246,.08)}
.node.git{border-color:rgba(96,165,250,.4)}
.node.vps{border-color:rgba(16,185,129,.4);background:rgba(16,185,129,.05)}
.arrow{color:var(--accent2);font-size:22px;padding:8px 0;font-family:var(--mono)}
.arrow small{display:block;font-size:11px;color:var(--muted);letter-spacing:.1em}
.tenants{display:flex;gap:18px;margin-top:6px}
.tenant{
border:1px dashed rgba(16,185,129,.4);border-radius:12px;padding:14px 20px;
font-family:var(--mono);font-size:14px;text-align:center;background:rgba(16,185,129,.04);
}
.tenant b{color:var(--success)} .tenant span{display:block;color:var(--muted);font-size:12px;margin-top:4px}
/* ===== TABLE ===== */
table{width:100%;border-collapse:collapse;font-size:18px}
th,td{text-align:left;padding:18px 22px;border-bottom:1px solid var(--border)}
th{font-family:var(--mono);font-size:13px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);font-weight:600}
td{color:#E2E8F0}
tr:last-child td{border-bottom:none}
td .mono{font-family:var(--mono)}
.num{font-family:var(--mono);font-weight:700;color:var(--accent2);text-align:right}
.num.ok{color:var(--success)}
tbody tr:hover{background:rgba(59,130,246,.05)}
/* ===== CHECKLIST ===== */
.checklist{display:grid;grid-template-columns:1fr 1fr;gap:16px 38px;align-self:stretch}
.check{
display:flex;align-items:center;gap:18px;cursor:pointer;user-select:none;
background:var(--card);border:1px solid var(--border);border-radius:14px;padding:20px 24px;
transition:.25s;
}
.check:hover{border-color:rgba(59,130,246,.4);transform:translateX(3px)}
.box{
width:30px;height:30px;border-radius:8px;border:2px solid var(--muted);flex:0 0 auto;
display:flex;align-items:center;justify-content:center;transition:.2s;font-weight:900;color:transparent;
}
.check.done .box{background:var(--success);border-color:var(--success);color:#06281c}
.check.done .box::after{content:"✓"}
.check .label{font-size:19px;font-weight:500;transition:.2s}
.check.done .label{color:var(--muted);text-decoration:line-through}
.check .mono{font-family:var(--mono);color:var(--accent2);font-size:16px}
/* ===== TIMELINE / ROADMAP ===== */
.timeline{display:flex;align-items:stretch;gap:0;margin-top:30px}
.phase{flex:1;position:relative;padding:0 14px}
.phase .ring{
width:26px;height:26px;border-radius:50%;border:3px solid var(--accent);
background:var(--bg);margin:0 auto 22px;position:relative;z-index:2;
}
.phase.now .ring{background:var(--accent);box-shadow:0 0 22px var(--accent)}
.phase::before{
content:"";position:absolute;top:11px;left:-50%;width:100%;height:3px;
background:var(--border);z-index:1;
}
.phase:first-child::before{display:none}
.phase.now::before,.phase.now ~ .phase::before{background:var(--border)}
.phase-card{
background:var(--card);border:1px solid var(--border);border-radius:16px;padding:24px 22px;text-align:center;height:100%;
}
.phase.now .phase-card{border-color:var(--accent);background:rgba(59,130,246,.08)}
.phase .ph-tag{font-family:var(--mono);font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--accent2);margin-bottom:8px}
.phase h3{font-size:22px;font-weight:700;margin-bottom:10px}
.phase p{font-size:15px;color:var(--muted);line-height:1.5}
/* ===== ER DIAGRAM ===== */
.er .codeblock{font-size:16px;line-height:1.75}
/* generic list */
.blist{list-style:none;display:flex;flex-direction:column;gap:14px}
.blist li{display:flex;gap:14px;font-size:19px;line-height:1.5;align-items:flex-start}
.blist li::before{content:"▸";color:var(--accent);font-weight:900;margin-top:2px}
.blist li b{color:var(--text)}
.blist li span{color:var(--muted)}
/* steps for lifecycle */
.steps{display:flex;flex-direction:column;gap:14px}
.step{display:flex;gap:22px;align-items:center;background:var(--card);border:1px solid var(--border);border-radius:14px;padding:20px 26px}
.step .no{font-family:var(--mono);font-size:26px;font-weight:700;color:var(--accent);width:46px;flex:0 0 auto}
.step .txt{flex:1}
.step .txt b{font-size:20px;font-weight:700;display:block}
.step .txt span{color:var(--muted);font-size:16px}
.step .time{font-family:var(--mono);font-size:15px;color:var(--success);background:rgba(16,185,129,.1);border:1px solid rgba(16,185,129,.3);border-radius:100px;padding:7px 16px;white-space:nowrap}
/* P&L econ */
.pl{display:grid;grid-template-columns:1fr 1fr;gap:26px}
.pl .block{background:var(--card);border:1px solid var(--border);border-radius:16px;padding:30px}
.pl .block.rev{border-color:rgba(16,185,129,.35)}
.pl .block.cost{border-color:rgba(245,158,11,.35)}
.pl .row{display:flex;justify-content:space-between;padding:12px 0;border-bottom:1px dashed var(--border);font-size:18px}
.pl .row:last-child{border:none}
.pl .row b{font-family:var(--mono)}
.be{margin-top:24px;display:flex;gap:24px}
.be .stat{flex:1;background:linear-gradient(160deg,rgba(59,130,246,.12),rgba(26,26,46,.6));border:1px solid rgba(59,130,246,.35);border-radius:16px;padding:24px 28px}
.be .stat span{font-family:var(--mono);font-size:13px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.be .stat strong{display:block;font-size:38px;font-weight:800;color:var(--accent2);margin-top:6px}
/* ===== NAV ===== */
.nav{position:fixed;bottom:26px;left:50%;transform:translateX(-50%);display:flex;align-items:center;gap:18px;z-index:50}
.nav button{
width:46px;height:46px;border-radius:12px;border:1px solid var(--border);background:rgba(26,26,46,.85);
color:var(--text);font-size:20px;cursor:pointer;transition:.2s;backdrop-filter:blur(8px);
}
.nav button:hover{border-color:var(--accent);color:var(--accent2)}
.nav .counter{font-family:var(--mono);font-size:15px;color:var(--muted);min-width:64px;text-align:center}
.nav .counter b{color:var(--text)}
.progress{position:fixed;top:0;left:0;height:3px;background:linear-gradient(90deg,var(--accent),var(--success));z-index:60;transition:width .5s ease;box-shadow:0 0 10px var(--accent)}
.brandmark{position:fixed;bottom:30px;left:40px;font-family:var(--mono);font-size:13px;color:var(--muted);z-index:50;letter-spacing:.1em}
.pagenum{position:fixed;bottom:30px;right:40px;font-family:var(--mono);font-size:13px;color:var(--muted);z-index:50}
.twocol{display:grid;grid-template-columns:1fr 1fr;gap:48px;align-items:center;height:100%}
.footnote{margin-top:auto;padding-top:22px;color:var(--muted);font-size:15px;font-family:var(--mono)}
@media(max-width:1100px){
.slide{padding:40px 44px 90px}
h1{font-size:48px}.title-slide h1{font-size:56px}h2{font-size:34px}
.g4{grid-template-columns:repeat(2,1fr)}.g3{grid-template-columns:repeat(2,1fr)}
.checklist{grid-template-columns:1fr}.timeline{flex-direction:column;gap:14px}
.phase::before{display:none}.twocol{grid-template-columns:1fr;gap:24px}
}
</style>
</head>
<body>
<div class="progress" id="progress"></div>
<div class="deck" id="deck">
<!-- 1 TITLE -->
<section class="slide title-slide active">
<div class="stage" style="display:flex;flex-direction:column;justify-content:center">
<div class="brandtag"><span class="dot"></span> @wasrusgen1 CRM · PLATFORM ARCHITECTURE</div>
<h1>Архитектура платформы<br><span style="color:var(--accent2)">@wasrusgen1 CRM</span></h1>
<p class="lede">Один продукт — много клиентов. Полный контроль.</p>
<div class="title-meta">
<div><span>Документ для</span><strong>Собственника системы</strong></div>
<div><span>Тема</span><strong>Ввод проекта в работу</strong></div>
<div><span>Дата</span><strong>2026</strong></div>
</div>
</div>
</section>
<!-- 2 SYSTEM MAP -->
<section class="slide">
<div class="stage">
<div class="kicker">Слайд 02 · Big picture</div>
<h2>Карта системы</h2>
<p class="sub">Единый код в GitHub разворачивается на VPS. Каждый клиент — отдельный поддомен и отдельная база.</p>
<div class="slide-body" style="justify-content:center">
<div class="archmap">
<div class="node master"><strong>Руслан · Мастер-панель</strong><span>управление всеми проектами</span></div>
<div class="arrow"></div>
<div class="node git"><strong>GitHub</strong><span>единый исходный код</span></div>
<div class="arrow"><small>авто-деплой CI/CD</small></div>
<div class="node vps"><strong>VPS сервер · Nginx + Docker</strong><span>роутинг по поддоменам</span></div>
<div class="arrow"></div>
<div class="tenants">
<div class="tenant"><b>salon1.crm.ru</b><span>→ PostgreSQL DB_1</span></div>
<div class="tenant"><b>salon2.crm.ru</b><span>→ PostgreSQL DB_2</span></div>
<div class="tenant"><b>salonN.crm.ru</b><span>→ PostgreSQL DB_N</span></div>
</div>
</div>
</div>
</div>
</section>
<!-- 3 THREE MODELS -->
<section class="slide">
<div class="stage">
<div class="kicker">Слайд 03 · Стратегия</div>
<h2>Три модели управления</h2>
<p class="sub">Как обслуживать множество клиентов на одной кодовой базе.</p>
<div class="slide-body">
<div class="grid g3" style="flex:1;align-content:center">
<div class="card">
<div class="ic">A</div>
<h3>Мультитенант</h3>
<p>Один деплой, одна БД, разделение по <span class="mono" style="color:var(--accent2)">tenant_id</span>. Дёшево в масштабе, но слабая изоляция и риск общего сбоя.</p>
<div style="margin-top:14px"><span class="pill">сложно стартовать</span></div>
</div>
<div class="card success">
<div class="ic">B</div>
<h3>Мультидеплой</h3>
<p>Отдельный контейнер + отдельная БД на клиента. Полная изоляция, простой старт, легко считать расходы по клиенту.</p>
<div style="margin-top:14px"><span class="pill rec">★ старт здесь</span></div>
</div>
<div class="card accent">
<div class="ic">C</div>
<h3>Гибрид</h3>
<p>Общий код и инфра-слой, изолированные БД, общий мониторинг и единое обновление. Баланс цены и изоляции на росте.</p>
<div style="margin-top:14px"><span class="pill rec">★ цель</span></div>
</div>
</div>
<div class="footnote">Рекомендация: начать с модели <b style="color:var(--success)">B (мультидеплой)</b> → перейти на <b style="color:var(--accent2)">C (гибрид)</b> при 5+ клиентах.</div>
</div>
</div>
</section>
<!-- 4 LIFECYCLE -->
<section class="slide">
<div class="stage">
<div class="kicker">Слайд 04 · Процесс</div>
<h2>Жизненный цикл нового проекта</h2>
<p class="sub">От подписи договора до запуска — около 3 рабочих дней.</p>
<div class="slide-body">
<div class="steps" style="margin:auto 0">
<div class="step"><div class="no">01</div><div class="txt"><b>Договор с клиентом</b><span>согласование условий, тариф, доступы</span></div><div class="time">1 день</div></div>
<div class="step"><div class="no">02</div><div class="txt"><b>Настройка инстанса</b><span>создание БД, конфиг, поддомен, деплой</span></div><div class="time">24 ч</div></div>
<div class="step"><div class="no">03</div><div class="txt"><b>Загрузка данных</b><span>салоны, пользователи, справочники</span></div><div class="time">12 ч</div></div>
<div class="step"><div class="no">04</div><div class="txt"><b>Обучение команды</b><span>КД, администраторы, мастера</span></div><div class="time">12 дня</div></div>
<div class="step"><div class="no">05</div><div class="txt"><b>Старт → техподдержка</b><span>пилот, мониторинг, SLA</span></div><div class="time">запуск</div></div>
</div>
</div>
</div>
</section>
<!-- 5 STACK -->
<section class="slide">
<div class="stage">
<div class="kicker">Слайд 05 · Технологии</div>
<h2>Стек технологий</h2>
<p class="sub">Проверенные инструменты, без экзотики — быстрый найм и поддержка.</p>
<div class="slide-body">
<div class="grid g4" style="flex:1;align-content:center">
<div class="card"><div class="ic">🖥️</div><h3>Frontend</h3><p>HTML/JS (текущий прототип) → <b style="color:var(--accent2)">React</b> в v2</p></div>
<div class="card"><div class="ic">⚙️</div><h3>Backend</h3><p>Node.js + Express — REST API, авторизация</p></div>
<div class="card success"><div class="ic">🗄️</div><h3>База данных</h3><p>PostgreSQL — <b style="color:var(--success)">одна БД на клиента</b></p></div>
<div class="card"><div class="ic"></div><h3>Кеш / сессии</h3><p>Redis — сессии, очереди, кеш</p></div>
<div class="card"><div class="ic">📦</div><h3>Файлы</h3><p>S3 / MinIO — фото, документы, экспорты</p></div>
<div class="card accent"><div class="ic">🚀</div><h3>Деплой</h3><p>Docker Compose + GitHub Actions CI/CD</p></div>
<div class="card"><div class="ic">☁️</div><h3>Хостинг</h3><p>VPS: Hetzner / Timeweb / Selectel</p></div>
<div class="card"><div class="ic">🔒</div><h3>Сеть</h3><p>Nginx reverse-proxy + Let's Encrypt HTTPS</p></div>
</div>
</div>
</div>
</section>
<!-- 6 ER DIAGRAM -->
<section class="slide er">
<div class="stage">
<div class="kicker">Слайд 06 · Данные</div>
<h2>Схема базы данных</h2>
<p class="sub">8 ключевых сущностей. Каждый клиент получает изолированную копию этой схемы.</p>
<div class="slide-body" style="justify-content:center">
<div class="codeblock">
<div class="winbar"><i style="background:#ff5f57"></i><i style="background:#febc2e"></i><i style="background:#28c840"></i></div>
<pre><span class="c-mut"># SCHEMA.md — ER-диаграмма (одна БД на клиента)</span>
<span class="c-acc">┌────────────┐</span <span class="c-acc">┌────────────┐</span <span class="c-acc">┌────────────┐</span
<span class="c-acc">│ salons │</span<span class="c-key">──1:N──</span<span class="c-acc">│ users │</span<span class="c-key">──1:N──</span<span class="c-acc">│shiftRequest│</span
<span class="c-acc">└─────┬──────┘</span <span class="c-acc">└─────┬──────┘</span <span class="c-acc">└────────────┘</span
<span class="c-key">│ 1:N</span <span class="c-key">│ 1:N</span
<span class="c-acc">┌─────┴──────┐</span <span class="c-acc">┌─────┴──────┐</span <span class="c-acc">┌────────────┐</span
<span class="c-acc">│ clients │</span<span class="c-key">──1:N──</span<span class="c-acc">│ orders │</span<span class="c-key">──1:N──</span<span class="c-acc">│ ratings │</span
<span class="c-acc">└─────┬──────┘</span <span class="c-acc">└─────┬──────┘</span <span class="c-acc">└────────────┘</span
<span class="c-key">│ 1:N</span <span class="c-key">│ 1:N</span
<span class="c-acc">┌─────┴──────┐</span <span class="c-acc">┌─────┴──────┐</span
<span class="c-acc">│appointments│</span<span class="c-key">───────│</span <span class="c-acc">│ requests │</span
<span class="c-acc">└────────────┘</span <span class="c-acc">└────────────┘</span
<span class="c-ok">salons</span> → сеть салонов клиента
<span class="c-ok">users</span> → сотрудники (КД / админ / мастер)
<span class="c-ok">clients</span> → клиентская база салона
<span class="c-ok">orders</span> → сделки / заказы
<span class="c-ok">appointments</span>→ записи на услуги
<span class="c-ok">requests</span> → заявки / лиды
<span class="c-ok">shiftRequests</span>→ заявки на смены сотрудников
<span class="c-ok">ratings</span> → оценки и обратная связь</pre>
</div>
</div>
</div>
</section>
<!-- 7 MASTER PANEL -->
<section class="slide">
<div class="stage">
<div class="kicker">Слайд 07 · Инструмент владельца</div>
<h2>Мастер-панель Руслана</h2>
<p class="sub">Что нужно разработать для управления всем парком проектов из одного места.</p>
<div class="slide-body">
<div class="grid g2" style="flex:1;align-content:center">
<div class="card accent"><div class="ic">📋</div><h3>Список проектов</h3><p>Все клиентские инстансы: статус, last activity, число пользователей, тариф.</p></div>
<div class="card success"><div class="ic"></div><h3>Создать новый проект</h3><p>Кнопка «Новый проект» → деплой инстанса в 1 клик (или скриптом).</p></div>
<div class="card"><div class="ic">📡</div><h3>Мониторинг</h3><p>Uptime, ошибки, нагрузка CPU/RAM, статус БД по каждому клиенту.</p></div>
<div class="card"><div class="ic">🔄</div><h3>Массовое обновление</h3><p>Выкатить новую версию на все проекты одновременно одной командой.</p></div>
</div>
</div>
</div>
</section>
<!-- 8 CHECKLIST -->
<section class="slide">
<div class="stage">
<div class="kicker">Слайд 08 · Onboarding</div>
<h2>Как подключить нового клиента</h2>
<p class="sub">Интерактивный чеклист — кликните по пунктам. <span style="color:var(--accent2)">Прогресс сохраняется в сессии.</span></p>
<div class="slide-body" style="justify-content:center">
<div class="checklist" id="checklist">
<div class="check"><div class="box"></div><div class="label">Подписан договор</div></div>
<div class="check"><div class="box"></div><div class="label">Получены данные: сеть, салоны, сотрудники</div></div>
<div class="check"><div class="box"></div><div class="label">Создан поддомен <span class="mono">client-name.wasrusgen1.ru</span></div></div>
<div class="check"><div class="box"></div><div class="label">Развёрнута БД и заполнены справочники</div></div>
<div class="check"><div class="box"></div><div class="label">Созданы учётные записи (КД, Администраторы)</div></div>
<div class="check"><div class="box"></div><div class="label">Проведено обучение команды</div></div>
<div class="check"><div class="box"></div><div class="label">Запущен пилот</div></div>
</div>
</div>
</div>
</section>
<!-- 9 INFRA COST -->
<section class="slide">
<div class="stage">
<div class="kicker">Слайд 09 · Инфраструктура</div>
<h2>Инфраструктура и стоимость</h2>
<p class="sub">Расходы растут вместе с числом клиентов — на старте почти нулевые.</p>
<div class="slide-body" style="justify-content:center">
<div class="card" style="padding:8px 16px">
<table>
<thead><tr><th>Этап</th><th>Конфигурация</th><th style="text-align:right">$/мес</th></tr></thead>
<tbody>
<tr><td><b>Прототип</b> <span style="color:var(--muted)">(сейчас)</span></td><td class="mono">GitHub Pages</td><td class="num ok">$0</td></tr>
<tr><td><b>Пилот</b> <span style="color:var(--muted)">(13 клиента)</span></td><td class="mono">VPS 2CPU / 4GB + Postgres</td><td class="num">~$2535</td></tr>
<tr><td><b>Рост</b> <span style="color:var(--muted)">(410 клиентов)</span></td><td class="mono">VPS 4CPU / 8GB + backup</td><td class="num">~$5080</td></tr>
<tr><td><b>Масштаб</b> <span style="color:var(--muted)">(10+ клиентов)</span></td><td class="mono">2 VPS + балансировщик</td><td class="num">~$120200</td></tr>
</tbody>
</table>
</div>
<div class="footnote">При 8 000 ₽/мес с клиента стоимость инфраструктуры — менее <b style="color:var(--success)">3 %</b> от выручки даже на масштабе.</div>
</div>
</div>
</section>
<!-- 10 ECONOMICS -->
<section class="slide">
<div class="stage">
<div class="kicker">Слайд 10 · Экономика</div>
<h2>Экономика продукта · P&L</h2>
<p class="sub">Точка безубыточности — первый же клиент. Маржа растёт с каждым следующим.</p>
<div class="slide-body" style="justify-content:center">
<div class="pl">
<div class="block cost">
<div class="tag" style="color:var(--warn)">— РАСХОДЫ / мес</div>
<div class="row"><span>Сервер (VPS + Postgres)</span><b>~$35</b></div>
<div class="row"><span>Поддержка (N часов)</span><b>переменные</b></div>
<div class="row"><span>Прочее (домены, бэкап)</span><b>~$5</b></div>
<div class="row" style="color:var(--warn)"><span><b>Итого база</b></span><b>~$40</b></div>
</div>
<div class="block rev">
<div class="tag" style="color:var(--success)">+ ДОХОДЫ / мес</div>
<div class="row"><span>Тариф на клиента</span><b>8 000 ₽</b></div>
<div class="row"><span>5 клиентов</span><b>40 000 ₽</b></div>
<div class="row"><span>10 клиентов</span><b>80 000 ₽</b></div>
<div class="row" style="color:var(--success)"><span><b>Модель X × 8 000 ₽</b></span><b>растёт линейно</b></div>
</div>
</div>
<div class="be">
<div class="stat"><span>Break-even</span><strong>1 клиент</strong></div>
<div class="stat"><span>Целевая маржа</span><strong>85 %+</strong></div>
<div class="stat"><span>При</span><strong>5+ клиентах</strong></div>
</div>
</div>
</div>
</section>
<!-- 11 ROADMAP -->
<section class="slide">
<div class="stage">
<div class="kicker">Слайд 11 · Roadmap</div>
<h2>Roadmap продукта</h2>
<p class="sub">Четыре фазы — от прототипа до AI-функций.</p>
<div class="slide-body" style="justify-content:center">
<div class="timeline">
<div class="phase now">
<div class="ring"></div>
<div class="phase-card"><div class="ph-tag">Фаза 1 · сейчас</div><h3>Прототип</h3><p>Готовый интерфейс → первый пилотный клиент.</p></div>
</div>
<div class="phase">
<div class="ring"></div>
<div class="phase-card"><div class="ph-tag">Фаза 2</div><h3>Бэкенд</h3><p>Node.js + PostgreSQL + авторизация (JWT).</p></div>
</div>
<div class="phase">
<div class="ring"></div>
<div class="phase-card"><div class="ph-tag">Фаза 3</div><h3>Мобильное (PWA)</h3><p>Установка на телефон, офлайн, push-уведомления.</p></div>
</div>
<div class="phase">
<div class="ring"></div>
<div class="phase-card"><div class="ph-tag">Фаза 4</div><h3>AI-функции</h3><p>Прогноз сделок, автоматизация рутины, аналитика.</p></div>
</div>
</div>
</div>
</div>
</section>
<!-- 12 SECURITY -->
<section class="slide">
<div class="stage">
<div class="kicker">Слайд 12 · Безопасность</div>
<h2>Безопасность и изоляция данных</h2>
<p class="sub">Данные каждого клиента физически отделены — утечка одного не затрагивает других.</p>
<div class="slide-body">
<div class="grid g3" style="flex:1;align-content:center">
<div class="card success"><div class="ic">🧱</div><h3>Физическая изоляция</h3><p>Каждый клиент — отдельная БД. Данные не пересекаются на уровне хранилища.</p></div>
<div class="card"><div class="ic">🔑</div><h3>JWT авторизация</h3><p>Токены доступа, роли и права на уровне API.</p></div>
<div class="card"><div class="ic">🔐</div><h3>HTTPS везде</h3><p>Let's Encrypt, авто-обновление сертификатов на всех поддоменах.</p></div>
<div class="card"><div class="ic">💾</div><h3>Бэкапы ежедневно</h3><p>Автоматический бэкап каждой БД, хранение и восстановление.</p></div>
<div class="card accent"><div class="ic">📤</div><h3>Экспорт данных</h3><p>Клиент может запросить выгрузку своих данных в любой момент.</p></div>
<div class="card"><div class="ic">📜</div><h3>Соответствие ПДн</h3><p>Хранение в РФ, разграничение доступа, журналирование.</p></div>
</div>
</div>
</div>
</section>
<!-- 13 SLA -->
<section class="slide">
<div class="stage">
<div class="kicker">Слайд 13 · Обязательства</div>
<h2>SLA и поддержка</h2>
<p class="sub">Понятные обязательства перед клиентом — основа доверия и удержания.</p>
<div class="slide-body">
<div class="grid g4" style="flex:1;align-content:center">
<div class="card success"><div class="ic">⏱️</div><h3>Uptime</h3><p style="font-size:34px;font-weight:800;color:var(--success);font-family:var(--mono)">99.5 %</p></div>
<div class="card"><div class="ic">📞</div><h3>Реакция</h3><p style="font-size:34px;font-weight:800;color:var(--accent2);font-family:var(--mono)">4 ч</p><p>в рабочее время</p></div>
<div class="card"><div class="ic">🔁</div><h3>Обновления</h3><p style="font-size:34px;font-weight:800;color:var(--accent2);font-family:var(--mono)">2 нед</p><p>регулярный цикл</p></div>
<div class="card accent"><div class="ic">🚀</div><h3>Onboarding</h3><p style="font-size:34px;font-weight:800;color:var(--accent);font-family:var(--mono)">3 дня</p><p>до запуска</p></div>
</div>
</div>
</div>
</section>
<!-- 14 NEXT STEPS -->
<section class="slide">
<div class="stage">
<div class="kicker">Слайд 14 · План действий</div>
<h2>Следующие шаги</h2>
<p class="sub">Конкретный план на 4 недели — от выбора клиента до запуска пилота.</p>
<div class="slide-body">
<div class="steps" style="margin:auto 0">
<div class="step"><div class="no">W1</div><div class="txt"><b>Выбрать первого пилотного клиента</b><span>сеть салонов, готовая дать данные и команду</span></div><div class="time">Неделя 1</div></div>
<div class="step"><div class="no">W2</div><div class="txt"><b>Развернуть бэкенд на VPS</b><span>Node.js + PostgreSQL + Docker + CI/CD</span></div><div class="time">Неделя 2</div></div>
<div class="step"><div class="no">W3</div><div class="txt"><b>Перевести прототип на реальные данные</b><span>подключить API, загрузить салоны и пользователей</span></div><div class="time">Неделя 3</div></div>
<div class="step"><div class="no">W4</div><div class="txt"><b>Запуск пилота с командой клиента</b><span>обучение, мониторинг, сбор обратной связи</span></div><div class="time">Неделя 4</div></div>
</div>
<div class="footnote">Готов начать с недели 1 — нужен выбор пилотного клиента.</div>
</div>
</div>
</section>
</div>
<div class="brandmark">@wasrusgen1 · CRM PLATFORM</div>
<div class="pagenum" id="pagenum">01 / 14</div>
<nav class="nav">
<button id="prev" aria-label="Назад"></button>
<div class="counter"><b id="cur">1</b> / 14</div>
<button id="next" aria-label="Вперёд"></button>
</nav>
<script>
(function(){
const slides=[...document.querySelectorAll('.slide')];
let i=0;const total=slides.length;
const progress=document.getElementById('progress');
const cur=document.getElementById('cur');
const pagenum=document.getElementById('pagenum');
function pad(n){return String(n).padStart(2,'0');}
function show(n){
i=Math.max(0,Math.min(total-1,n));
slides.forEach((s,k)=>s.classList.toggle('active',k===i));
progress.style.width=((i+1)/total*100)+'%';
cur.textContent=i+1;
pagenum.textContent=pad(i+1)+' / '+pad(total);
}
document.getElementById('next').onclick=()=>show(i+1);
document.getElementById('prev').onclick=()=>show(i-1);
document.addEventListener('keydown',e=>{
if(['ArrowRight','PageDown',' '].includes(e.key)){e.preventDefault();show(i+1);}
else if(['ArrowLeft','PageUp'].includes(e.key)){e.preventDefault();show(i-1);}
else if(e.key==='Home')show(0);
else if(e.key==='End')show(total-1);
});
// interactive checklist
document.querySelectorAll('#checklist .check').forEach(c=>{
c.addEventListener('click',()=>c.classList.toggle('done'));
});
show(0);
})();
</script>
</body>
</html>