feat: Projects + stronger LLM placeholder substitution

Backend:
- Project model with defaults: defaultClient, defaultTemplate, defaultBankAccount
- Document gets optional projectId (FK + index)
- Migration 2_projects: enum ProjectStatus + Project table + Document.projectId
- API: /api/projects CRUD, GET /api/projects/:id/documents
- documents/routes filter by projectId

LLM prompt:
- Concrete preamble example: «ООО «...», в лице директора ... , ИП ..., ОГРНИП ...»
  → {{customer.name}}, {{customer.signatoryPosition}} {{customer.signatoryName}},
    {{executor.name}}, {{executor.ogrn}}
- Expanded placeholder list (signatoryName/Position для customer, ogrn etc)
- Side-role detection: «Заказчик» vs «Исполнитель» map to customer/executor

Frontend:
- /projects (list) and /projects/:id (defaults form + documents list under project)
- Nav: «Проекты» first
- DocumentEdit reads projectId from URL, presets default client from project,
  saves projectId with the document

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
admin
2026-05-01 13:17:07 +03:00
parent 973d85c1dd
commit b2c221e643
11 changed files with 661 additions and 17 deletions
@@ -0,0 +1,37 @@
-- CreateEnum
CREATE TYPE "ProjectStatus" AS ENUM ('active', 'completed', 'cancelled');
-- CreateTable
CREATE TABLE "Project" (
"id" UUID NOT NULL,
"organizationId" UUID NOT NULL,
"name" TEXT NOT NULL,
"status" "ProjectStatus" NOT NULL DEFAULT 'active',
"defaultClientId" UUID,
"defaultTemplateId" UUID,
"defaultBankAccountId" UUID,
"notes" TEXT,
"archivedAt" TIMESTAMP(3),
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Project_pkey" PRIMARY KEY ("id")
);
CREATE INDEX "Project_organizationId_archivedAt_idx" ON "Project"("organizationId", "archivedAt");
CREATE INDEX "Project_organizationId_status_idx" ON "Project"("organizationId", "status");
ALTER TABLE "Project" ADD CONSTRAINT "Project_organizationId_fkey"
FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "Project" ADD CONSTRAINT "Project_defaultClientId_fkey"
FOREIGN KEY ("defaultClientId") REFERENCES "Client"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "Project" ADD CONSTRAINT "Project_defaultTemplateId_fkey"
FOREIGN KEY ("defaultTemplateId") REFERENCES "DocumentTemplate"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "Project" ADD CONSTRAINT "Project_defaultBankAccountId_fkey"
FOREIGN KEY ("defaultBankAccountId") REFERENCES "BankAccount"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AlterTable: добавить projectId на Document
ALTER TABLE "Document" ADD COLUMN "projectId" UUID;
CREATE INDEX "Document_organizationId_projectId_idx" ON "Document"("organizationId", "projectId");
ALTER TABLE "Document" ADD CONSTRAINT "Document_projectId_fkey"
FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE SET NULL ON UPDATE CASCADE;