eCourt-Doc-Edit/backend/WordVersioning.Api/Models/VersionDtos.cs
Suphonchai Phoonsawat b3c1c667f7 Phase 12: draft generation (FR-16)
ไฟล์ร่าง (draft) — generate docx จาก template แบบ stateless ไม่สร้าง
Document/version; stamp เฉพาะ custom property TemplateId เพื่อให้ add-in
เห็นเป็น untracked; Start Versioning ส่ง form field templateId ให้ backend
ผูก template ตอน auto-create — เอกสารเริ่มที่ v1 (ไม่มี v0) + field sync เต็มระบบ

- Backend: POST /api/templates/{id}/generate-draft (200 คืนไฟล์) +
  DocxGenerationService.GenerateDraft + แยก TemplateFieldValidation ใช้ร่วมกับ
  generate + UploadVersion รับ templateId (non-GUID/unknown → 400,
  deactivated → ผูกได้, document เดิม → เฉย) + CORS expose Content-Disposition
- Add-in: readTrackedProperties อ่าน TemplateId + ส่ง templateId เฉพาะ
  startVersioning + hint ไฟล์ร่างใน task pane
- Web: ปุ่ม "สร้างไฟล์ร่าง" บนฟอร์มเดิม + downloadFile รับ init (POST → blob)
- Docs: spec v8 (FR-16, AC-19) + Phase 12 + CONTEXT.md + ADR 0002 +
  acceptance-review AC-19
- Tests: backend 82 / add-in 66 / web 59 + build ครบ; QA reviewer PASS
  (2 rounds); ค้าง manual บน Word จริง

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-10 10:51:13 +07:00

92 lines
4.2 KiB
C#

using System.ComponentModel.DataAnnotations;
using System.Text.Json;
namespace WordVersioning.Api.Models;
/// <summary>body ของ POST /api/documents/{documentId}/versions (multipart/form-data)</summary>
public class UploadVersionRequest
{
[Required]
public IFormFile File { get; set; } = null!;
public IFormFile? Pdf { get; set; }
/// <summary>GUID ที่ client generate ต่อ version — ใช้เป็นส่วนหนึ่งของ object key</summary>
[Required]
public string ClientVersionId { get; set; } = string.Empty;
/// <summary>JSON object map tag→text จาก content controls (FR-11)</summary>
public string? Fields { get; set; }
/// <summary>คำอธิบาย version แบบ commit message (FR-13) — optional</summary>
public string? Message { get; set; }
/// <summary>GUID ของ template ต้นทาง (FR-16 ไฟล์ร่าง) — ใช้เฉพาะตอน auto-create Document;
/// ไม่ส่ง = เอกสาร track เอง · ส่งมาตอน document มีอยู่แล้ว = เฉย (validate ทุกครั้งที่ส่ง)</summary>
public string? TemplateId { get; set; }
}
public record UploadVersionResponse(Guid VersionId, int VersionNumber, bool HasPdf);
/// <summary>body ของ POST /api/documents/generate (FR-10)</summary>
public class GenerateDocumentRequest
{
[Required]
public Guid TemplateId { get; set; }
/// <summary>map fieldKey → value (ค่า scalar ทั้งหมด)</summary>
public JsonElement Values { get; set; }
/// <summary>คำอธิบาย version แบบ commit message (FR-13) — optional</summary>
public string? Message { get; set; }
}
public record GenerateDocumentResponse(Guid DocumentId, Guid VersionId, int VersionNumber, string DownloadUrl);
/// <summary>item ของ version history — fields คือ snapshot ที่ parse แล้ว (ถ้ามี), message คือคำอธิบายของผู้ใช้ (FR-13)</summary>
public record VersionListItem(
Guid VersionId,
int VersionNumber,
DateTimeOffset CreatedAt,
string CreatedByUserId,
string ContentHash,
object? Fields,
string? Message,
bool HasPdf);
/// <summary>response ของ GET .../download-link — presigned URL อายุสั้นให้เปิดในเบราว์เซอร์ของผู้ใช้</summary>
public record VersionDownloadLinkResponse(string Url, DateTimeOffset ExpiresAt);
/// <summary>item ของ GET /api/templates/{templateId}/documents — รายการเอกสารของ template หนึ่งตัว (FR-12)</summary>
public record TemplateDocumentListItem(
Guid DocumentId,
string FileName,
DateTimeOffset CreatedAt,
int VersionCount,
int LatestVersionNumber,
DateTimeOffset? LatestVersionAt);
/// <summary>field หนึ่งตัวของ document (FR-12) — นิยามจาก TemplateField + ค่าล่าสุดจาก DocumentFieldValue
/// Label/Type/IsRequired เป็น null เมื่อมีค่าเก็บไว้แต่ key ไม่มีในนิยาม template ปัจจุบัน
/// (เช่น replace ไฟล์แล้ว tag หาย) — SourceVersionId/UpdatedByUserId/UpdatedAt เป็น null เมื่อ
/// field เพิ่มเข้า template หลังเอกสารนี้ถูกสร้าง (ยังไม่เคยมีค่า)</summary>
public record DocumentFieldItem(
string Key,
string? Label,
string? Type,
bool? IsRequired,
string Value,
Guid? SourceVersionId,
string? UpdatedByUserId,
DateTimeOffset? UpdatedAt);
/// <summary>response ของ GET /api/documents/{documentId} (FR-12) —
/// TemplateId null คือเอกสาร track เองจาก add-in (ไม่มีนิยาม field, Fields ว่าง)</summary>
public record DocumentDetail(
Guid Id,
string FileName,
DateTimeOffset CreatedAt,
Guid? TemplateId,
string? TemplateName,
bool TemplateIsActive,
IReadOnlyList<DocumentFieldItem> Fields);