Migrate web app from Python/FastAPI to Node.js/TypeScript

Replace the entire Python/FastAPI backend with a Node.js/TypeScript stack:
- Framework: Hono + @hono/node-server
- Templates: Nunjucks (.njk) replacing Jinja2 (.html)
- ORM: Drizzle ORM with mysql2 (same MariaDB schema, no migrations needed)
- Sessions: hono-sessions with CookieStore
- CSS: Pico CSS v2 replacing Bootstrap 5 (Bootstrap Icons CDN kept)
- Dev: tsx watch; Prod: tsc + node dist/index.js

Original Python app preserved in web-python/ as backup.
Updated Dockerfile.web and docker-compose.yml for Node.js deployment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
mguschin
2026-03-17 19:33:32 +03:00
parent db0c1cbed3
commit 854c912a88
100 changed files with 5770 additions and 39 deletions

View File

@@ -0,0 +1,47 @@
{% extends "base.html" %}
{% block title %}Подключение ВКонтакте — ЭВОСИНК{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-sm-10 col-md-7 col-lg-6">
<div class="card shadow-sm mt-4 text-center">
<div class="card-body py-5">
<div id="state-loading">
<div class="spinner-border text-primary mb-3" role="status"></div>
<p class="text-muted mb-0">Подключение ВКонтакте…</p>
</div>
<div id="state-error" class="d-none">
<i class="bi bi-exclamation-triangle-fill text-danger fs-1 mb-3 d-block"></i>
<p class="text-muted mb-3" id="error-message">Не удалось получить токен от ВКонтакте.</p>
<a href="/vk" class="btn btn-outline-secondary">Попробовать снова</a>
</div>
</div>
</div>
</div>
</div>
<form id="token-form" method="post" action="/vk/token" class="d-none">
<input type="hidden" name="token" id="token-input">
</form>
<script>
(function () {
var hash = window.location.hash.slice(1);
var params = {};
hash.split("&").forEach(function (part) {
var kv = part.split("=");
params[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1] || "");
});
if (params.access_token) {
document.getElementById("token-input").value = params.access_token;
document.getElementById("token-form").submit();
} else {
var msg = params.error_description || params.error || "Авторизация отклонена.";
document.getElementById("error-message").textContent = msg;
document.getElementById("state-loading").classList.add("d-none");
document.getElementById("state-error").classList.remove("d-none");
}
})();
</script>
{% endblock %}