9.7 KiB
Heritage
Назначение
Веб-приложение «Родословное дерево семьи» (Family Tree) — построение, визуализация и ведение генеалогического дерева. Хранит персон (ФИО, пол, даты, фото, биография, контакты) и связи (родитель→ребёнок, брак/союз, приёмные). Даёт дерево с pan/zoom, поиск, карточки персон, роли (admin/editor/viewer), импорт/экспорт JSON/CSV/GEDCOM, светлую/тёмную тему.
Стек: Frontend — React + TypeScript + Vite + Tailwind + React Flow;
Backend — Node.js + Express + PostgreSQL (JWT-авторизация, bcrypt).
Развёртывание через docker-compose (db 5432 / backend 4000 / frontend 3000→80).
Дополнительно: автономные статичные HTML (landing/, preview/) для демонстрации
без сборки и сервера, плюс папка design/ с исходным макетом.
- Основной язык: TypeScript + JavaScript (React / Node).
- Суммарный LOC (отслеживаемый код backend/src + frontend/src + db + landing + preview): ~2208
(React/Express-код ~815; статичные HTML/SQL ~1400). Папка
design/(~92 КБ JS-макета) не входит в сборку.
Архитектура
graph TD
subgraph Frontend[frontend/ React+Vite+Tailwind]
MAIN[main.tsx] --> APP[App.tsx]
APP --> TREE[FamilyTree.tsx<br/>React Flow]
APP --> MODAL[PersonModal.tsx]
TREE --> NODE[PersonNode.tsx]
TREE --> LAYOUT[lib/layout.ts]
APP --> CLIENT[api/client.ts]
APP --> TYPES[types.ts]
end
subgraph Backend[backend/ Express]
INDEX[index.js<br/>app + /api/health] --> RAUTH[routes/auth.js]
INDEX --> RPERS[routes/persons.js]
INDEX --> RREL[routes/relations.js]
INDEX --> RIO[routes/io.js]
RAUTH --> MW[middleware/auth.js<br/>authRequired/requireRole]
RPERS --> MW
RREL --> MW
RIO --> MW
RAUTH --> POOL[db/pool.js]
RPERS --> POOL
RREL --> POOL
RIO --> POOL
MIGRATE[db/migrate.js] --> POOL
end
subgraph Data[PostgreSQL]
SCHEMA[db/schema.sql]
SEED[db/seed.sql]
end
subgraph Static[Автономные артефакты]
LAND[landing/index.html]
PREV[preview/index.html]
DESIGN[design/*.js .dc.html]
end
CLIENT -->|fetch /api| INDEX
POOL --> Data
LAND -.открыть дерево.-> PREV
Entry-points / маршруты
Backend Express, монтирование в backend/src/index.js
(/api/auth, /api/persons, /api/relations, /api/io).
| Метод | Путь | Доступ | Файл | Назначение |
|---|---|---|---|---|
| GET | /api/health |
все | index.js:15 | Проверка живости |
| POST | /api/auth/register |
все | routes/auth.js:9 | Регистрация |
| POST | /api/auth/login |
все | routes/auth.js:27 | Вход, JWT |
| GET | /api/auth/me |
авторизован | routes/auth.js:37 | Текущий юзер |
| GET | /api/persons/tree |
авторизован | routes/persons.js:16 | Всё дерево |
| GET | /api/persons/search?q= |
авторизован | routes/persons.js:22 | Поиск |
| GET | /api/persons/:id |
авторизован | routes/persons.js:33 | Карточка + родня |
| POST | /api/persons |
admin, editor | routes/persons.js:47 | Создать |
| PUT | /api/persons/:id |
admin, editor | routes/persons.js:59 | Изменить |
| DELETE | /api/persons/:id |
admin | routes/persons.js:72 | Удалить |
| POST | /api/relations/parent-child |
admin, editor | routes/relations.js:9 | Связь родитель→ребёнок |
| DELETE | /api/relations/parent-child/:id |
admin, editor | routes/relations.js:18 | Удалить связь |
| POST | /api/relations/union |
admin, editor | routes/relations.js:24 | Брак/союз |
| DELETE | /api/relations/union/:id |
admin, editor | routes/relations.js:34 | Удалить союз |
| GET | /api/relations/history |
авторизован | routes/relations.js:40 | История изменений |
| GET | /api/io/export/json |
авторизован | routes/io.js:15 | Экспорт JSON |
| GET | /api/io/export/csv |
авторизован | routes/io.js:19 | Экспорт CSV |
| GET | /api/io/export/gedcom |
авторизован | routes/io.js:29 | Экспорт GEDCOM |
| POST | /api/io/import/json |
admin, editor | routes/io.js:53 | Импорт JSON |
Frontend не имеет своих HTTP-роутов — SPA; клиент API в frontend/src/api/client.ts
(BASE = VITE_API_URL || '/api'). Nginx (frontend/nginx.conf) отдаёт статику.
Ключевые цепочки вызовов
- Вход:
App.tsxформа →api.login()(client.ts) →POST /api/auth/login→routes/auth.jsbcrypt.compare + JWT → токен вsetToken()→ загрузка дерева. - Отрисовка дерева:
App.tsx→api.tree()→GET /api/persons/tree(SQL join) →FamilyTree.tsx→lib/layout.ts(раскладка узлов) →PersonNode.tsx(React Flow). - Карточка персоны: клик по узлу →
App.selected→PersonModal.tsx→api.person(id)→GET /api/persons/:id(персона + родня + медиа);onNavigateвнутри модалки переключает на родственника. - Редактирование:
PersonModal/App→api.create/update/remove→POST/PUT/DELETE /api/personsсrequireRole(admin,editor)→db/pool.js→ Postgres. - Экспорт/импорт: UI →
api.exportJson()/importJson()→routes/io.js(сериализация JSON/CSV/GEDCOM либо запись импорта под ролью editor+).
Cross-service links
Прямых runtime-вызовов к другим нашим сервисам нет. Единственная внешняя ссылка —
исходный git-репозиторий в README: git1.servaki.online/german/Heritage.git
(поддомен *.servaki.online, git-хостинг инфраструктуры). Коммит-история упоминает
деплой-хост vm-mts1 (сервер публикации фронта). Внешних API-интеграций
(finik/gate/ru*/de и т.п.) не обнаружено.
Тех-долг
Все пункты — предположение (эвристика grep / отсутствие входящих ссылок); точность — через codebase-memory-mcp.
design/(image-slot.js ~32 КБ, support.js ~60 КБ, Heritage Landing.dc.html) — исходный макет конструктораx-dc; не импортируется ни фронтом, ни сборкой → кандидат в мёртвый код (артефакт дизайна). предположение.Heritage проекта дизайн.zip(137 КБ) в корне — бинарный артефакт в репозитории, не используется кодом. предположение — кандидат на вынос из git.backend/src/db/migrate.js— есть npm-скриптmigrate, но docker применяетdb/schema.sql+seed.sqlнапрямую через initdb; в рантайме миграция не вызывается → возможный дубль пути инициализации БД. предположение.- Дубль статики landing/preview vs React-приложение —
landing/index.htmlиpreview/index.htmlреализуют функционал автономно (дерево, темы, импорт/экспорт) параллельно с полноценным React-фронтом → потенциальное расхождение/дублирование логики. предположение. design/screens/01..04-landing.png— 4 png одинакового размера (21670 б), вероятно дубликаты-заглушки. предположение.- JWT_SECRET / пароли по умолчанию в docker-compose (
please_change_this_secret, demopassword) — не тех-долг архитектуры, но отметка для безопасности.
TODO для Лилии (codebase-memory-mcp)
- Построить точный call-graph frontend↔backend: сопоставить методы
api.*(client.ts) с конкретными обработчиками роутов и SQL вdb/pool.js. - Подтвердить/опровергнуть dead-code: реально ли
design/*,.zip,db/migrate.jsбез входящих ссылок; проверить импорты вpreview/landing. - Уточнить cross-service: подтвердить, что нет сетевых вызовов к другим сервисам
инфраструктуры; зафиксировать деплой-таргет
vm-mts1иgit1.servaki.online. - Разобрать дубль логики React-приложение vs
preview/index.html— единый источник истины. - Снять снапшот graph.db.zst по финальному дереву модулей и связей для инкрементальных обновлений.
- Зафиксировать схему БД (
db/schema.sql, 118 строк) как узлы данных в графе памяти.