4 Commits

Author SHA1 Message Date
admin e768d30fb6 feat: import DOCX/PDF/scanned templates via DeepSeek recognition
Backend pipeline:
- POST /api/templates/import (multipart, max 25 MB)
- extract.ts: DOCX→mammoth, PDF→pdf-parse, fallback to OCR via tesseract+poppler-utils
  (pdftoppm renders pages to PNG, tesseract reads with rus+eng)
- deepseek.ts: chat completions client with strict JSON response_format
- recognize.ts: structured prompt that produces simplified DocBody (string text),
  postprocessor wraps text in TipTap-compatible JSON, validates with zod schema
- prompt enforces placeholder substitution: {{customer.*}}, {{executor.*}},
  {{contract.number}}, {{contract.date}}, {{today}}
- error codes: NO_OCR / NO_DEEPSEEK_KEY / UNSUPPORTED_MIME / INVALID_DOC_BODY

Dockerfile: apk add tesseract-ocr (+rus +eng data), poppler-utils, imagemagick

Frontend:
- Templates page: ⤴ Загрузить документ → file picker (.docx,.pdf,.png,.jpg)
- doc type selector (contract/invoice/act/upd)
- import-banner with spinner shows uploading→analyzing stages
- on success navigates to /templates/:id (TemplateEdit) for review

Reuses DEEPSEEK_API_KEY pattern from Hall-planer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 11:40:28 +03:00
admin 624d378bb5 feat: DaData ИНН lookup for clients and companies
- New API endpoint GET /api/lookup/party?inn=... — proxies to DaData API,
  returns parsed party (name, kpp, ogrn, address, signatory, status)
- Env DADATA_API_KEY (optional) — without it endpoint returns 503/no_dadata_key
- Web: InnLookupButton component shown next to ИНН field in Clients form
  and Company requisites; on click fetches DaData and fills all matching
  fields. Warns if status is not ACTIVE (liquidated, etc.)

Free DaData tier: 10000 requests/day. Get key at
https://dadata.ru/api/find-party/ — paste into DADATA_API_KEY in
docker/.env on queoserver.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 11:16:20 +03:00
admin 4965fdd60f fix: auth login URL is /login on Auth_server, not /auth/login
GET /auth/login → 404. Auth_server's user-facing login form lives at
GET https://auth.queo.ru/login (rendered by views/login.html), while
POST /auth/login is the JSON API. Web was redirecting to wrong path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 21:41:41 +03:00
admin 4553f63deb init: M1 scaffolding + M2 organization/clients/services CRUD
- monorepo (npm workspaces): apps/api (Fastify+Prisma+TS), apps/web (Vite+React+TS), packages/shared (zod schemas)
- SSO via auth.queo.ru: jose+JWKS plugin, requireDocPermission(viewer|user|admin)
- DEV_BYPASS_AUTH for local development (hard-checked off in production)
- M2: organization upsert, clients CRUD with search, services catalog with soft-delete
- BigInt -> Number serializer for Prisma money columns
- Embedded Postgres + npm run dev:demo for one-command local boot
- Docker compose for queoserver: postgres + api + web (nginx as ingress proxying /api -> api:3030)
- First migration 0_init committed (prisma migrate diff)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 21:24:26 +03:00