Remove the Go reference server; keep only Rust
CI / Rust (fmt / clippy / test / build) (push) Successful in 1m41s
CI / HTTP/JSON reference + SQLite persistence (push) Successful in 1m16s
CI / Rust (fmt / clippy / test / build) (pull_request) Successful in 47s
CI / HTTP/JSON reference + SQLite persistence (pull_request) Successful in 1m34s

The Go implementation is preserved in the v1.0.0 tag. Its observable
behaviour stays the API reference: responses recorded from the Go server
live in tools/compatibility_expected.txt, and tools/compatibility.py now
compares the Rust server against them (--update re-records after an
intentional change). The Go SQLite schema is frozen in
tests/fixtures/go_schema_v1.sql for the existing-database test.

Move the web client from internal/httpapi/web to web/, drop the Go CI job
and Go version pin, and update README, AGENTS.md and docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
wtandClaude Opus 5.5 committed 2026-10-30 16:27:33 +07:00
1 parent 16dd2a3b3c
commit 10272f3851
33 files changed
+890 -1438

No files matched your search

+106
View File
@@ -0,0 +1,106 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="theme-color" content="#5b5bd6">
<meta name="description" content="Balance — личные финансы на вашем сервере">
<title>Balance</title>
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="manifest" href="/manifest.webmanifest">
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<div id="toast-region" class="toast-region" aria-live="polite" aria-atomic="true"></div>
<main id="auth-view" class="auth-layout">
<section class="auth-card" aria-labelledby="auth-title">
<div class="brand brand-auth">
<img src="/icon.svg" alt="" width="58" height="58">
<div>
<span class="brand-name">Balance</span>
<span class="brand-caption">Ваши финансы. Ваш сервер.</span>
</div>
</div>
<div class="auth-copy">
<p class="eyebrow">SELF-HOSTED</p>
<h1 id="auth-title">Финансы под вашим контролем</h1>
<p>Войдите в аккаунт этого сервера. Операции синхронизируются с iPhone, Apple Watch, Mac и Android.</p>
</div>
<div class="segmented auth-switch" role="tablist" aria-label="Вход или регистрация">
<button type="button" class="is-active" data-auth-mode="login" role="tab">Войти</button>
<button type="button" data-auth-mode="register" role="tab">Регистрация</button>
</div>
<form id="auth-form" class="stack" autocomplete="on">
<label class="field">
<span>Email</span>
<input id="auth-email" name="email" type="email" inputmode="email" autocomplete="email" required maxlength="254" placeholder="name@example.com">
</label>
<label class="field">
<span>Пароль</span>
<input id="auth-password" name="password" type="password" autocomplete="current-password" required minlength="8" maxlength="1024" placeholder="Минимум 8 символов">
</label>
<p id="auth-error" class="form-error" role="alert" hidden></p>
<button id="auth-submit" class="button button-primary button-large" type="submit">Войти</button>
</form>
<p class="security-note"><span aria-hidden="true">🔒</span> Сессия хранится в защищённых HttpOnly-cookie и недоступна JavaScript.</p>
</section>
</main>
<div id="app-view" class="app-shell" hidden>
<aside class="sidebar">
<div class="brand sidebar-brand">
<img src="/icon.svg" alt="" width="42" height="42">
<div>
<span class="brand-name">Balance</span>
<span class="brand-caption">Личные финансы</span>
</div>
</div>
<nav class="side-nav" aria-label="Основная навигация">
<button type="button" data-route="dashboard"><span>⌂</span> Обзор</button>
<button type="button" data-route="transactions"><span>↕</span> Операции</button>
<button type="button" data-route="analytics"><span>◫</span> Аналитика</button>
<button type="button" data-route="budgets"><span>◎</span> Бюджеты</button>
<button type="button" data-route="categories"><span>◆</span> Категории</button>
<button type="button" data-route="settings"><span>⚙</span> Настройки</button>
</nav>
<div class="sidebar-footer">
<div id="sync-pill" class="sync-pill"><span></span><span>Синхронизировано</span></div>
<div class="account-mini">
<div class="avatar" id="account-avatar">Б</div>
<div>
<strong id="account-email">—</strong>
<span>Личный аккаунт</span>
</div>
</div>
</div>
</aside>
<main class="workspace">
<header class="mobile-header">
<div class="brand">
<img src="/icon.svg" alt="" width="36" height="36">
<span class="brand-name">Balance</span>
</div>
<button type="button" class="icon-button" data-action="sync" aria-label="Синхронизировать">↻</button>
</header>
<div id="content" class="content" tabindex="-1"></div>
</main>
<nav class="bottom-nav" aria-label="Мобильная навигация">
<button type="button" data-route="dashboard"><span>⌂</span><small>Обзор</small></button>
<button type="button" data-route="transactions"><span>↕</span><small>Операции</small></button>
<button type="button" data-route="analytics"><span>◫</span><small>Аналитика</small></button>
<button type="button" data-route="budgets"><span>◎</span><small>Бюджеты</small></button>
<button type="button" data-route="settings"><span>⚙</span><small>Ещё</small></button>
</nav>
</div>
<dialog id="editor-dialog" class="modal">
<div id="dialog-content"></div>
</dialog>
<noscript>Для работы Balance необходимо включить JavaScript.</noscript>
<script src="/app.js" defer></script>
</body>
</html>