ไฟล์ร่าง (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>
92 lines
4.2 KiB
C#
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);
|