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
+38
View File
@@ -55,6 +55,12 @@ enum PaymentKind {
outgoing
}
enum ProjectStatus {
active
completed
cancelled
}
model Organization {
id String @id @default(uuid()) @db.Uuid
name String
@@ -82,6 +88,31 @@ model Organization {
tochkaCredentials TochkaCredential[]
auditLog AuditLog[]
bankAccounts BankAccount[]
projects Project[]
}
model Project {
id String @id @default(uuid()) @db.Uuid
organizationId String @db.Uuid
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
name String
status ProjectStatus @default(active)
// Дефолты — подставляются при создании документов внутри проекта
defaultClientId String? @db.Uuid
defaultClient Client? @relation(fields: [defaultClientId], references: [id])
defaultTemplateId String? @db.Uuid
defaultTemplate DocumentTemplate? @relation(fields: [defaultTemplateId], references: [id])
defaultBankAccountId String? @db.Uuid
defaultBankAccount BankAccount? @relation(fields: [defaultBankAccountId], references: [id])
notes String?
archivedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
documents Document[]
@@index([organizationId, archivedAt])
@@index([organizationId, status])
}
model BankAccount {
@@ -100,6 +131,7 @@ model BankAccount {
updatedAt DateTime @updatedAt
tochkaCredentials TochkaCredential[]
defaultForProjects Project[]
@@index([organizationId])
}
@@ -121,6 +153,7 @@ model Client {
updatedAt DateTime @updatedAt
documents Document[]
defaultForProjects Project[]
@@index([organizationId])
@@index([organizationId, name])
@@ -155,6 +188,8 @@ model DocumentTemplate {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
defaultForProjects Project[]
@@index([organizationId, docType])
}
@@ -162,6 +197,8 @@ model Document {
id String @id @default(uuid()) @db.Uuid
organizationId String @db.Uuid
organization Organization @relation(fields: [organizationId], references: [id])
projectId String? @db.Uuid
project Project? @relation(fields: [projectId], references: [id])
docType DocType
number String
issuedAt DateTime?
@@ -188,6 +225,7 @@ model Document {
@@unique([organizationId, docType, number])
@@index([organizationId, clientId, issuedAt(sort: Desc)])
@@index([organizationId, status])
@@index([organizationId, projectId])
@@index([tochkaDocumentId])
}