Beeline
Монорепозиторий проекта: бекенд-API и фронтенд-приложения в одном репозитории под управлением pnpm workspaces.
Для жюри / быстрый запуск в Docker:
docs/jury.md.
Для AI-агентов: канонический подробный документ по проекту —
CLAUDE.md(стек, слои, команды, конвенции, «гочи»). Агентские скиллы/команды/субагенты — в.claude/(см..claude/SUMMARY.md).
Стек
- Пакетный менеджер: pnpm (workspaces), Node >= 24
-
Бекенд (
apps/api): Hono + @hono/zod-openapi, аутентификация — better-auth, логирование — pino, Scalar-доки -
БД (
packages/db): PostgreSQL + Drizzle ORM (+ drizzle-kit для миграций) -
Фронтенд (
apps/admin): Vite + React 19 + TypeScript, TailwindCSS v4, Zustand (клиентское состояние), TanStack Query (серверное),react-router-domv7, клиент better-auth. Архитектура — Feature-Sliced Design -
Дизайн-система (
packages/ui): React-компоненты на семантических токенах; токены/тема —packages/shared/theme.css(Tailwind v4, тёмная тема по классу.dark, шрифт Onest) -
Общий код (
packages/shared): типизированный Hono-клиент (hc), конфиг better-auth, типы ресурсов,theme.css
Структура
.
├── apps/
│ ├── api/ # Бекенд на Hono (реализован частично: cities + auth)
│ └── admin/ # Админка (Vite + React SPA), структура по FSD:
│ # app / pages / features / entities / shared
├── packages/
│ ├── db/ # Слой БД: схемы Drizzle, миграции, подключение к Postgres
│ ├── shared/ # @beeline/shared — hc-клиент, конфиг auth, типы, theme.css
│ ├── ui/ # @beeline/ui — React-компоненты дизайн-системы
│ └── onboarding/ # @beeline/onboarding — движок туров driver.js (router-агностичный)
├── docker-compose.yml # Локальный PostgreSQL
├── .env.example # Шаблон общего окружения для api + db
├── CLAUDE.md # Подробный док проекта для AI-агентов
└── pnpm-workspace.yaml
Фронтенд задуман как два независимых приложения:
apps/admin(админ-панель) и будущее клиентское. Сейчас реализуется толькоadmin;packages/uiиpackages/shared— переиспользуемый кросс-аппный слой.
Требования
- Node.js >= 24 (см.
devEnginesвpackage.json) - pnpm >= 11
- Docker (для локального PostgreSQL) — либо свой инстанс Postgres
Быстрый старт
pnpm install # 1. зависимости всех воркспейсов
cp .env.example .env # 2. общий .env для apps/api + packages/db
cp apps/admin/.env.example apps/admin/.env # 3. .env админки (VITE_API_URL)
docker compose up -d # 4. локальный PostgreSQL
pnpm db:migrate # 5. миграции (db:generate — создать новую)
pnpm dev:api # 6. API на http://localhost:3030 (tsx watch)
pnpm dev:admin # 7. админка на http://localhost:5173 (Vite)
API-доки (Swagger/Scalar) — http://localhost:3030/reference (нужен запущенный
pnpm dev:api).
-
.env— общий файл дляapps/apiиpackages/db(оба резолвят его из корня). Секрет:BETTER_AUTH_SECRET(>= 16 символов), напримерopenssl rand -base64 32. - Порт Postgres берётся из
POSTGRES_PORTв.env(на этой машине5432занят другим проектом — используется5433; проверяйтеdocker psперед поднятием ещё одной БД). - Для админки есть свой
apps/admin/.env(толькоVITE_API_URL); шаблон —apps/admin/.env.example. - Origin админки (
http://localhost:5173) уже прописан вALLOWED_ORIGINS.
Памятка по .env и портам
Два разных .env (оба в .gitignore, из шаблонов — копировать один раз после клона):
| Файл | Кто читает | Ключевые переменные | Шаблон |
|---|---|---|---|
.env (корень) |
apps/api, packages/db
|
DATABASE_URL, POSTGRES_PORT, BETTER_AUTH_SECRET, BETTER_AUTH_URL, ALLOWED_ORIGINS, ADMIN_EMAIL/ADMIN_PASSWORD
|
.env.example |
apps/admin/.env |
apps/admin (Vite) |
VITE_API_URL |
apps/admin/.env.example |
cp .env.example .env # корневой (api + db)
cp apps/admin/.env.example apps/admin/.env # админка (VITE_API_URL)
Порты по умолчанию: API — 3030, админка (Vite) — 5173, Postgres — 5433 (не 5432).
Частые проблемы
-
EADDRINUSE ... port: 3030приpnpm dev:api— порт занят, обычно второй экземпляр API (tsx watchне умер после закрытого терминала). Найти и прибить процесс:Get-NetTCPConnection -LocalPort 3030 -State Listen | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force }Затем снова
pnpm dev:api. -
Запрос авторизации уходит на
5173вместо3030(http://localhost:5173/auth/get-session) — нетapps/admin/.envили в нём пустойVITE_API_URL. Без переменной better-auth берёт origin страницы (5173). Лечитсяcp apps/admin/.env.example apps/admin/.env+ перезапуск Vite (import.meta.env.VITE_*вшивается на старте, на лету не подхватывается). -
CORS-ошибки на все запросы к API — Vite молча уехал с занятого 5173 на 5174/5175 (смотрите порт в баннере Vite). Новый origin не в
ALLOWED_ORIGINS. Освободите 5173 либо добавьте порт вALLOWED_ORIGINS(через запятую) в корневом.envи перезапустите API (tsx watchне перечитывает.env). -
Сменили порт API — синхронно поправьте
VITE_API_URL(apps/admin/.env),BETTER_AUTH_URLиALLOWED_ORIGINS(корневой.env), иначе фронт/CORS отвалятся.
Как проверить
Бекенд:
-
API-доки (Swagger/Scalar):
http://localhost:3030/reference— интерактивный UI по всем эндпоинтам, «попробовать», + отдельный источник по auth. Требуется поднятый API (pnpm dev:api). -
http://localhost:3030/doc— сырой OpenAPI-спек (JSON), из него рисуется/reference -
http://localhost:3030/— корневой эндпоинт →{ "status": "ok", "data": { "message": "Test API" } }
curl http://localhost:3030/cities
curl -X POST http://localhost:3030/cities -H "Content-Type: application/json" -d '{"name":"Москва"}'
Админка: http://localhost:5173 — план дня, календарь, заявки, инженеры, рабочий график, справочники (/catalogs → типы работ, навыки, оборудование, типы графиков, города — везде поиск/фильтры, создание и правка) и /ui-kit (витрина дизайн-системы, переключатель светлой/тёмной темы). Это сквозная проверка связки фронт { status, data, meta }).
Полезные скрипты (из корня)
| Команда | Что делает |
|---|---|
pnpm dev:api |
Запуск API в dev-режиме |
pnpm dev:admin |
Запуск админки в dev-режиме |
pnpm db:migrate |
Применить миграции к БД |
pnpm db:generate |
Сгенерировать миграцию из схем Drizzle |
pnpm build |
Собрать все пакеты (pnpm -r build) |
pnpm format |
Прогнать Prettier по репозиторию |
Фронтенд-архитектура (FSD)
apps/admin следует Feature-Sliced Design. Слои сверху вниз: app → pages → widgets → features → entities → shared. Импорты — только вниз; слайсы одного слоя изолированы; публичный API слайса — через index.ts.
apps/admin/src/
app/ шелл, провайдеры, роутинг (react-router-dom), стили
pages/ cities, ui-kit — цели маршрутов
features/ create-city, delete-city, theme-toggle — по одному действию
entities/ city — чтение (useCities) + ключи кэша + типы
shared/ api (client+auth), config (query-client), model (ui-store)
Роутинг живёт только в app (app/routing.tsx + app/root-layout.tsx). Sidebar из @beeline/ui остаётся router-агностичным. Подробности и правила — в CLAUDE.md.
Дизайн-система (@beeline/ui + theme.css)
- Токены —
packages/shared/theme.css(Tailwind v4@theme), тёмная тема по классу.dark, шрифт Onest. Приложение импортит@import '@beeline/shared/theme.css'и добавляет@sourceдляpackages/ui/src+packages/shared/src. - Компоненты —
packages/ui(@beeline/ui). В разметке только семантические утилиты (bg-canvas/bg-surface/text-fg/border-border/bg-brand), без примитивов и произвольных значений. Иконки — в одном месте (packages/ui/src/icons/).
Общий код: @beeline/shared
Source-only TS-пакет (приложения импортируют исходники напрямую):
-
Типизированный RPC-клиент Hono (
hc) —createApiClient(baseUrl); типы путей/query/тела/ответов выведены из исходников бэкенда:Тип роутера отдаётся черезimport { createApiClient, unwrap } from '@beeline/shared'; const api = createApiClient(import.meta.env.VITE_API_URL); const { data, meta } = await unwrap(await api.cities.$get({ query: { limit: '10' } }));apps/api→api/hc.unwrap()разворачивает конверт{ status, data, meta? }, сужает до успешной ветки и бросаетApiErrorна не-2xx. -
Типы ресурсов (
City,CitiesQuery) выводятся из клиента — руками не дублируются. -
better-auth —
authClientConfig(baseURL)даёт базовый конфиг; плагины добавляет каждое приложение.
⚠ ️ Типыhcберутся из собранных декларацийapps/api(api/dist/hc.d.ts):
- перед
pnpm --filter admin build/typecheckсоберите API:pnpm --filter api build(вpnpm buildучтено — топологический порядок);import typeстирается, поэтомуpnpm dev:adminработает без сборки API;- после изменения роутов — пересоберите типы:
pnpm --filter api build.
Документация для агентов
-
CLAUDE.md— единый подробный док проекта (стек, слои, команды, конвенции, гочи). Держится в актуальном состоянии и обновляется в том же коммите, что и изменение структуры/команд/контрактов (см. правило вCLAUDE.md; pre-commit-хук напоминает). -
.claude/— субагенты (agents/), скиллы (skills/), slash-команды (commands/); индекс —.claude/SUMMARY.md.
Деплой
CI/CD в .gitlab-ci.yml (ветка main): rsync кода, pnpm install, сборка @beeline/db и api, миграции, перезапуск через PM2. Продакшен-.env — из переменной $PRODUCTION_ENV GitLab. SPA-фронт при статик-хостинге требует history-fallback на index.html.