205 lines
17 KiB
HTML
205 lines
17 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{--ink:#0d1117;--bg:#0a0e14;--panel:#11161f;--panel2:#161d29;--line:#232c3b;--mut:#8b96a8;--acc:#4d8dff;--acc2:#22c55e;--warn:#f59e0b;--bad:#ef4444;--vio:#a78bfa}
|
||
*{box-sizing:border-box}
|
||
body{margin:0;font-family:'SF Mono','Cascadia Code',Consolas,monospace;background:var(--bg);color:#dbe2ee;font-size:14.5px;line-height:1.6}
|
||
.wrap{max-width:1060px;margin:0 auto;padding:28px 18px 90px}
|
||
header{border:1px solid var(--line);border-radius:14px;padding:22px 26px;margin-bottom:22px;background:linear-gradient(135deg,#101726,#0d1420)}
|
||
.kicker{font-size:11px;letter-spacing:.22em;text-transform:uppercase;color:var(--acc);font-weight:700}
|
||
h1{margin:8px 0 6px;font-size:26px;line-height:1.25}
|
||
.sub{color:var(--mut);font-size:13px}
|
||
.cols{display:grid;grid-template-columns:300px 1fr;gap:18px}
|
||
@media(max-width:860px){.cols{grid-template-columns:1fr}}
|
||
.panel{background:var(--panel);border:1px solid var(--line);border-radius:12px;overflow:hidden}
|
||
.panel h3{margin:0;padding:12px 16px;font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--mut);border-bottom:1px solid var(--line);background:var(--panel2)}
|
||
.pbody{padding:14px 16px}
|
||
.member{display:flex;align-items:center;gap:10px;padding:9px 10px;border:1px solid var(--line);border-radius:10px;margin:8px 0;background:var(--panel2);cursor:pointer;transition:border-color .15s}
|
||
.member:hover{border-color:var(--acc)}
|
||
.member.sel{border-color:var(--acc);box-shadow:0 0 0 1px var(--acc) inset}
|
||
.avatar{width:30px;height:30px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;color:#fff}
|
||
.mname{font-weight:700;font-size:13.5px}
|
||
.mrole{font-size:11px;color:var(--mut)}
|
||
.voteweight{margin-left:auto;font-size:11px;color:var(--vio)}
|
||
.ledger{background:#080b10;border-radius:10px;border:1px solid var(--line);padding:12px;max-height:340px;overflow-y:auto;font-size:12px}
|
||
.tx{border-left:2px solid var(--acc2);padding:6px 10px;margin:7px 0;background:#0c121b;border-radius:0 8px 8px 0}
|
||
.tx.gov{border-left-color:var(--vio)}
|
||
.tx.peg{border-left-color:var(--acc)}
|
||
.tx.err{border-left-color:var(--bad)}
|
||
.txhead{display:flex;justify-content:space-between;gap:8px;font-weight:700;color:#e8eefb;font-size:11.5px}
|
||
.txbody{color:var(--mut);margin-top:3px;white-space:pre-wrap}
|
||
.ok{color:var(--acc2);font-weight:700}.warn{color:var(--warn);font-weight:700}.err{color:var(--bad);font-weight:700}.vio{color:var(--vio)}
|
||
.btnrow{display:flex;flex-wrap:wrap;gap:10px;margin:14px 0}
|
||
button{font-family:inherit;font-size:12.5px;font-weight:700;padding:10px 14px;border-radius:10px;border:1px solid var(--acc);background:#15243f;color:#bcd6ff;cursor:pointer;transition:.15s}
|
||
button:hover{background:#1b3157}
|
||
button:disabled{opacity:.35;cursor:not-allowed}
|
||
button.ghost{border-color:var(--line);background:var(--panel2);color:var(--mut)}
|
||
.kv{display:grid;grid-template-columns:auto 1fr;gap:4px 12px;font-size:12.5px}
|
||
.kv b{color:var(--mut);font-weight:400}
|
||
.bar{height:10px;background:#0b1119;border:1px solid var(--line);border-radius:99px;overflow:hidden;display:flex}
|
||
.seg{height:100%}
|
||
.legend{display:flex;flex-wrap:wrap;gap:12px;font-size:11px;color:var(--mut);margin-top:8px}
|
||
.dot{display:inline-block;width:9px;height:9px;border-radius:3px;margin-right:5px;vertical-align:-1px}
|
||
.note{background:#101726;border:1px solid var(--line);border-radius:10px;padding:12px 14px;font-size:12px;color:var(--mut);margin-top:12px}
|
||
.note b{color:#c8d4e6}
|
||
.sec2{margin-top:22px}
|
||
.timeline{display:grid;gap:10px}
|
||
.step{display:grid;grid-template-columns:34px 1fr;gap:12px;align-items:start}
|
||
.n{width:30px;height:30px;border-radius:9px;background:#15243f;border:1px solid var(--acc);color:#bcd6ff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:13px}
|
||
.step .t{font-weight:700;font-size:13.5px}
|
||
.step .d{color:var(--mut);font-size:12.5px}
|
||
footer{margin-top:34px;border-top:1px solid var(--line);padding-top:14px;font-size:11.5px;color:var(--mut)}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="wrap">
|
||
|
||
<header>
|
||
<div class="kicker">Кооператив 42 · Интерактивное демо для ПВТ</div>
|
||
<h1>Конституция кооператива на блокчейне</h1>
|
||
<div class="sub">Как устав и законы кооператива исполняются on-chain: голосование → решение → юридическое действие. Смарт-контракт — исполнительный механизм, устав — источник власти (ГК РБ + Декрет №8). Основа контента: док законов t-261014120323.</div>
|
||
</header>
|
||
|
||
<div class="cols">
|
||
<div>
|
||
<div class="panel">
|
||
<h3>Реестр членов</h3>
|
||
<div class="pbody">
|
||
<div class="kv" style="margin-bottom:10px"><b>Всего членов:</b><span id="mcount">—</span></div>
|
||
<div id="members"></div>
|
||
<div class="note" style="margin-top:10px">Каждый член — адрес в реестре. <b>1 член = 1 голос</b> (§111 WY / устав). Кликните — проголосовать от имени члена.</div>
|
||
</div>
|
||
</div>
|
||
<div class="panel" style="margin-top:16px">
|
||
<h3>Смарт-контракт</h3>
|
||
<div class="pbody">
|
||
<div class="kv">
|
||
<b>Адрес:</b><span>0x42…C0NF (в уставе)</span>
|
||
<b>Версия:</b><span id="cver">v1.0</span>
|
||
<b>Кворум:</b><span id="cq">—</span>
|
||
<b>Порог:</b><span>50%+1 от голосовавших</span>
|
||
<b>Upgradable:</b><span class="ok">да, dual-confirm</span>
|
||
</div>
|
||
<div class="note">Публичный адрес контракта фиксируется в уставе (аналог §109 WY: неактуальный идентификатор блокирует on-chain операции).</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="panel">
|
||
<h3>Активное предложение (on-chain governance)</h3>
|
||
<div class="pbody">
|
||
<div id="proposal" class="tx gov"><div class="txhead"><span>PROPOSAL-1 · governance</span><span id="pstate">открыто</span></div><div class="txbody">Принять Конституцию кооператива v1: цифровой режим управления, учёт паёв в токенах, решения органов оформляются on-chain.</div></div>
|
||
<div style="margin:12px 0 6px;font-size:12px;color:var(--mut)">Явка / кворум ⅔</div>
|
||
<div class="bar" id="bar"></div>
|
||
<div class="legend">
|
||
<span><span class="dot" style="background:#22c55e"></span>За</span>
|
||
<span><span class="dot" style="background:#ef4444"></span>Против</span>
|
||
<span><span class="dot" style="background:#232c3b"></span>Не голосовали</span>
|
||
<span id="tally" style="margin-left:auto"></span>
|
||
</div>
|
||
<div class="btnrow">
|
||
<button id="btnVote" onclick="castVote()">Проголосовать (за)</button>
|
||
<button class="ghost" onclick="castVote(true)">Против</button>
|
||
<button id="btnExec" onclick="executeProposal()" disabled>Исполнить решение</button>
|
||
<button class="ghost" onclick="location.reload()">Сброс демо</button>
|
||
</div>
|
||
<div id="verdict" class="note">Выберите члена слева и проголосуйте. Когда явка достигнет кворума и большинство — «за», кнопка «Исполнить решение» активируется: смарт-контракт оформит решение собрания on-chain.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="panel" style="margin-top:16px">
|
||
<h3>Журнал реестра (ledger)</h3>
|
||
<div class="ledger" id="ledger">
|
||
<div class="tx peg"><div class="txhead"><span>GENESIS · peg</span><span>#0</span></div><div class="txbody">Реестр привязан к уставу кооператива (РБ): состав органов, паи, правила — из юрдокумента. Токен = учёт пая, не ценная бумага (Декрет №8).</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="panel sec2">
|
||
<h3>Как решение становится юридическим фактом (5 шагов)</h3>
|
||
<div class="pbody timeline">
|
||
<div class="step"><div class="n">1</div><div><div class="t">Предложение (proposal)</div><div class="d">Правление вносит предложение on-chain. В уставе закреплено: повестка собрания = активные предложения реестра.</div></div></div>
|
||
<div class="step"><div class="n">2</div><div><div class="t">Голосование членов (1 член = 1 голос)</div><div class="d">Члены голосуют подписью со своего адреса. Тайна личности — псевдонимизация, вес — по уставу, не по капиталу.</div></div></div>
|
||
<div class="step"><div class="n">3</div><div><div class="t">Кворум + порог</div><div class="d">Смарт-контракт считает явку и голоса по уставным параметрам (здесь: кворум ⅔, порог 50%+1). Невозможность «накрутки» — математика реестра.</div></div></div>
|
||
<div class="step"><div class="n">4</div><div><div class="t">Исполнение (execute)</div><div class="d">Контракт оформляет решение операцией в реестре; для решений, требующих юрдействия (реестр юрлиц, договоры), формируется пакет для подписи председателем — принцип «контракт исполняет, устав властвует».</div></div></div>
|
||
<div class="step"><div class="n">5</div><div><div class="t">Прозрачность (audit)</div><div class="d">Любой партнёр (ПВТ, аудит, член) проверяет историю голосований и решений в открытом реестре — без запроса отчётности (§112 WY).</div></div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="panel sec2">
|
||
<h3>Привязка к праву РБ (для юристов ПВТ)</h3>
|
||
<div class="pbody" style="font-size:13px">
|
||
<ul style="margin:0;padding-left:18px;color:#c3cddd">
|
||
<li><b>Юрлицо:</b> производственный кооператив (ГК РБ, ст. 104–113) — устав обязателен, собрание — высший орган.</li>
|
||
<li><b>Цифровой слой:</b> Декрет №8 «О развитии цифровой экономики» — токены (учёт пая), смарт-контракты (оформление сделок/решений), резидентство ПВТ.</li>
|
||
<li><b>Иерархия:</b> устав выше контракта — реестр признаётся доказательством состояний, контракт — исполнительный механизм; коллизии решает собрание.</li>
|
||
<li><b>Защита членов:</b> выход — с выплатой пая (обязательна); контрактом это автоматизируется, но не отменяется.</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<footer>Демо-симуляция работы Конституции кооператива on-chain · Кооператив 42 · артефакт t-261014121824-a70757 · контент по док законов РБ (t-261014120323) · не юрзаключение, для показа продукта партнёрам ПВТ.</footer>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
const MEMBERS=[
|
||
{n:'Алекс',r:'председатель / продукт',c:'#4d8dff'},
|
||
{n:'Юра',r:'правление / операции',c:'#22c55e'},
|
||
{n:'Марина',r:'финансы и договоры',c:'#f59e0b'},
|
||
{n:'Дима',r:'инженерия',c:'#a78bfa'},
|
||
{n:'Стас',r:'партнёрства',c:'#ef4444'},
|
||
{n:'Наталья',r:'юрист-консультант',c:'#14b8a6'}
|
||
];
|
||
let sel=null, votes={}, done=false, ntx=0;
|
||
const QUORUM=Math.ceil(MEMBERS.length*2/3); // ⅔
|
||
function $(id){return document.getElementById(id)}
|
||
function log(kind,head,body){ntx++;const d=document.createElement('div');d.className='tx '+kind;d.innerHTML='<div class="txhead"><span>'+head+'</span><span>#'+ntx+'</span></div><div class="txbody">'+body+'</div>';$('ledger').prepend(d)}
|
||
function renderMembers(){
|
||
$('mcount').textContent=MEMBERS.length+' (3 физлица минимум по ГК — норма соблюдена)';
|
||
$('members').innerHTML=MEMBERS.map((m,i)=>'<div class="member'+(sel===i?' sel':'')+'" onclick="pick('+i+')"><div class="avatar" style="background:'+m.c+'">'+m.n[0]+'</div><div><div class="mname">'+m.n+'</div><div class="mrole">'+m.r+'</div></div><div class="voteweight">1 голос</div></div>').join('');
|
||
}
|
||
function pick(i){sel=i;renderMembers();log('peg','SELECT_SIGNER','подписант: '+MEMBERS[i].n+' ('+MEMBERS[i].r+') — голос будет подписан адресом члена')}
|
||
function renderVotes(){
|
||
const v=MEMBERS.map((m,i)=>votes[i]);
|
||
const yes=v.filter(x=>x===true).length,no=v.filter(x=>x===false).length,abst=MEMBERS.length-yes-no;
|
||
$('bar').innerHTML='<div class="seg" style="width:'+(yes/MEMBERS.length*100)+'%;background:#22c55e"></div><div class="seg" style="width:'+(no/MEMBERS.length*100)+'%;background:#ef4444"></div>';
|
||
$('tally').innerHTML='<span class="ok">'+yes+' за</span> · <span class="err">'+no+' против</span> · '+abst+' молчат';
|
||
const turnout=yes+no;
|
||
$('cq').textContent=turnout+'/'+MEMBERS.length+' (нужно '+QUORUM+')';
|
||
const q=turnout>=QUORUM, pass=q&&yes>no;
|
||
if(!done){
|
||
$('btnExec').disabled=!pass;
|
||
$('pstate').innerHTML=pass?'<span class="ok">кворум есть · большинство ЗА</span>':'<span class="warn">ждёт голосов</span>';
|
||
if(pass)$('verdict').innerHTML='<b>Кворум достигнут, большинство — за.</b> Нажмите «Исполнить решение»: смарт-контракт оформит решение собрания операцией в реестре (шаг 4).';
|
||
else $('verdict').innerHTML='Явка '+(turnout)+' из '+MEMBERS.length+', кворум '+QUORUM+'. Голосуйте от имени разных членов (клик слева → кнопка).';
|
||
}
|
||
}
|
||
function castVote(against){
|
||
if(done){log('err','ERROR','предложение уже исполнено — реестр неизменяем');return}
|
||
if(sel===null){log('err','ERROR','выберите члена в реестре слева');return}
|
||
if(votes[sel]!==undefined){log('err','REJECT','двойной голос отклонён: адрес '+MEMBERS[sel].n+' уже голосовал (анти-манипуляция реестра)');return}
|
||
votes[sel]=!against;
|
||
log('gov','VOTE',''+MEMBERS[sel].n+' → '+(against?'ПРОТИВ':'ЗА')+' · подпись адреса принята');
|
||
renderVotes();
|
||
}
|
||
function executeProposal(){
|
||
const yes=Object.values(votes).filter(x=>x).length;
|
||
if($('btnExec').disabled){log('err','EXECUTE_REJECT','условия устава не выполнены (кворум/порог)');return}
|
||
done=true;
|
||
$('pstate').innerHTML='<span class="ok">ИСПОЛНЕНО</span>';
|
||
log('gov','EXECUTE','решение собрания оформлено: Конституция v1 принята ('+yes+' за, кворум '+QUORUM+') · запись реестра = протокол собрания');
|
||
log('peg','LEGAL_BRIDGE','сформирован пакет юрдействий: протокол для подписи председателем, ссылка на запись реестра — устав выше контракта, контракт его исполняет');
|
||
$('verdict').innerHTML='<b>Готово.</b> Решение зафиксировано в реестре (неизменяемо), юрпакет передан на подпись. Дальше по дорожной карте: юристы ПВТ → резидентство → устав с «цифровым режимом» → dual-running пилот.';
|
||
$('btnVote').disabled=true;$('btnExec').disabled=true;
|
||
}
|
||
renderMembers();renderVotes();
|
||
</script>
|
||
</body>
|
||
</html>
|