Work-log: Document workflow — Phase 1 fixes + 4 new features
Date: 2026-05-20
Duration: ~4 hours
Engineer: Claude Code
Что сделано
Fixes по обратной связи Руслана (Phase 1 pilot)
-
“Body exceeded 1 MB limit” — все загрузки файлов через веб падали с этой ошибкой.
Корень: Next.js Server Actions имеет дефолтный лимит 1MB.
Исправление:experimental.serverActions.bodySizeLimit: "25mb"вnext.config.ts. -
Суммы с запятыми/копейками — поле
type="number"не принимает русскую запятую.
Исправление:type="text" inputMode="decimal"+.replace(",", ".")вparseFloatна бэке (app/lib/actions/contracts.ts). -
История поступлений и договоров с удалением — добавлены
deleteRevenueEventиdeleteContractserver actions, в UI проекта — кнопки удаления сDeleteFormкомпонентом. -
Secure cookie на HTTP — на rigabase без HTTPS кука не устанавливалась.
Исправление:secure: process.env.APP_URL?.startsWith("https") ?? falseвместоNODE_ENV === "production"вapp/lib/auth/lucia.ts. -
docker-compose порт — изменён
127.0.0.1:3010:3000на0.0.0.0:3010:3000для доступа через IP.
Новые фичи (design spec: docs/superpowers/specs/2026-05-20-document-workflow-design.md)
1. Multi-file upload (веб)
- Новый компонент
app/components/documents/MultiUpload.tsx— клиентский, последовательный upload с прогрессом “Загружаю N из M: filename”. - API route
app/app/api/documents/upload/route.ts— POST, аутентификация + проверка ownership проекта. - Shared logic
app/lib/upload/uploadSingle.ts— валидация MIME/размера (20MB), S3 upload, DB insert с rollback (DeleteObjectCommand при ошибке DB).
2. Telegram bot: выбор объекта перед сохранением
tg-bot/src/state.ts— in-memory Map с TTL 5 минут.tg-bot/src/handlers/projectSelect.ts— callback_query handler, читает pending из Map, сохраняет в БД с выбранным projectId (или null).tg-bot/src/handlers/file.ts— полный рерайт: загрузка → MinIO → inline keyboard с активными проектами организации + ”📂 Без объекта”.- Фоновый sweep каждые 60с: просроченные pending сохраняются с
projectId = NULL.
3. Каталог поставщиков (фильтр без объекта)
- Фильтр-табы в
/documents:Все | По объектам | Без объектачерез?filter=all|bound|unboundURL-параметр. - Серверная условная query в
app/app/(app)/documents/page.tsx.
4. Статусы согласования документов
- Миграция БД:
approval_statusenum (pending_review | approved | rejected | paid), колонка вdocument. StatusButtons.tsx— клиентский компонент сuseActionState, badge + контекстные кнопки по состоянию.updateDocumentStatusserver action — проверка ownership + state machine переходов.
Файлы затронутые
Новые:
app/lib/upload/uploadSingle.tsapp/app/api/documents/upload/route.tsapp/components/documents/MultiUpload.tsxapp/components/documents/StatusButtons.tsxapp/components/ui/DeleteForm.tsxapp/drizzle/0001_lowly_hellion.sqltg-bot/src/state.tstg-bot/src/handlers/projectSelect.ts
Изменены:
app/next.config.tsapp/lib/db/schema.tsapp/lib/actions/documents.tsapp/lib/actions/contracts.tsapp/lib/auth/lucia.tsapp/app/(app)/documents/page.tsxapp/app/(app)/projects/[id]/page.tsxtg-bot/src/handlers/file.tstg-bot/src/index.tsdocker-compose.yml
Что не сделано / отложено
- Детальная страница документа со статусом (Phase 2)
- История переходов статусов (Phase 2)
- Webhook вместо long-polling для бота (Phase 2)
- Голосовые сообщения в боте (Phase 2)
- Telegram bot: кнопки должны автоматически исчезать после выбора (UX-улучшение)
Технические решения
- In-memory Map для bot state — намеренно, без внешнего Redis, достаточно для Phase 1 с одним пользователем. Принятие: риск потери state при рестарте контейнера приемлем (TTL 5 минут, auto-sweep).
- Sequential upload — Server Actions не поддерживают промежуточные события прогресса, поэтому клиентский sequential fetch loop.
- Supplier catalog без нового раздела — фильтр-табы в существующем
/documents, минимально достаточно.
Статус деплоя
Все изменения задеплоены на rigabase:
bablo-app: Up (healthy), пересобран после всех коммитовbablo-tg-bot: Up (healthy), пересобран после3d862d1- Стройплощадка: передеплоена на Vercel (
vercel deploy --prod)