Contract là gì trong ngữ cảnh này

Definition

Trong ngữ cảnh này, contract là một lớp mô tả có cấu trúc cho domain và hành vi của hệ thống. Nó có thể định nghĩa thực thể nghiệp vụ, hành động hợp lệ, các rule, workflow, API mapping và những flow quan trọng cần giữ đúng.

Contract không phải prompt tự do. Nó cũng không phải snapshot tạm của code hiện tại. Khi làm theo hướng contract-first, contract được xem là nguồn sự thật cho behavior, còn code là thứ được sinh ra, kiểm tra và áp dụng từ lớp mô tả đó.

Điểm cần giữ cho đúng ngay từ đầu:
  • contract phải đủ chặt để validate
  • contract vẫn phải gần với intent nghiệp vụ hơn implementation
  • review thay đổi nên diễn ra trước ở contract, không chỉ ở diff code cuối
  • code là output được dẫn ra từ contract, không phải nguồn sự thật chính

Từ tự định nghĩa contract đến Midi Coder pipeline

Model

Nếu tự làm, người dùng có thể bắt đầu rất trực tiếp: tự định nghĩa contract bằng bất kỳ ngôn ngữ mô tả nào mà team thấy phù hợp, miễn là nó đủ rõ để biểu diễn domain, hành vi và các ràng buộc của hệ thống. Ngôn ngữ đó có thể là YAML, JSON, DSL riêng, hoặc một format có cấu trúc khác. Một điểm bắt đầu tối thiểu vẫn thường là định nghĩa thực thể chính, lỗi nghiệp vụ cơ bản, các command và mapping HTTP route. Ở mức này, contract đã đủ để mô tả một flow CRUD hoặc application service đơn giản mà không phải viết một file mô tả dài, lẫn lộn giữa domain, rule và endpoint.

Midi Coder đi tiếp từ ý tưởng đó và đưa ra một quyết định triển khai cụ thể: dùng YAML làm dạng biểu diễn cho DSL contracts của mình. Từ lựa chọn đó, Midi Coder định nghĩa luôn schema, validator, cross-file checking, IR trung gian, code plan và cơ chế generate/apply patch. Điều này biến contract thành input chính cho code generation chứ không chỉ là tài liệu tham khảo.

Nói ngắn gọn, người dùng có thể tự định nghĩa contract. Midi Coder là lớp chuẩn hóa và pipeline hóa cách làm đó để nó vận hành được một cách nhất quán hơn trong thực tế.

Nếu team tự làm

  • tự chọn ngôn ngữ mô tả phù hợp với domain và behavior
  • bắt đầu tối thiểu từ entity, error, command và HTTP route mapping
  • contract đã đủ để mô tả flow CRUD hoặc application service đơn giản

Khi Midi Coder triển khai

  • chọn YAML làm dạng biểu diễn cho DSL contracts
  • chuẩn hóa thêm schema, validator, cross-file checking, IR và code plan
  • đưa contract thành input chính cho code generation và patch pipeline

Pipeline tổng quát

Flow

Từ section này trở đi, nội dung mặc định mô tả cách Midi Coder triển khai contract coding. Ở mức tổng quát, flow của Midi Coder có thể nhìn như sau:

  1. 01

    Xác định yêu cầu

    Xác định hoặc cập nhật yêu cầu cần thay đổi.

  2. 02

    Chuyển thành contract

    Chuyển yêu cầu đó thành contract.

  3. 03

    Validate

    Validate contract ở mức schema và mức quan hệ giữa các file.

  4. 04

    Compile thành IR

    Compile contract hợp lệ thành IR.

  5. 05

    Tạo code plan

    Tạo code plan từ IR theo stack đích.

  6. 06

    Generate patch

    Generate patch tương ứng.

  7. 07

    Apply và review

    Apply patch vào codebase và review kết quả.

Trong Midi Coder, phần đầu của flow thường bắt đầu từ master-brief.md, project context và schema summary để sinh draft contracts. Nếu người dùng tự author contract thì có thể bỏ qua bước sinh từ brief, nhưng các bước validate, compile, review và truy vết vẫn là phần cốt lõi của flow.

Điểm cần giữ là code không đi thẳng từ prompt vào file. Nó đi qua contract, qua check, qua lớp trung gian, rồi mới trở thành patch có thể review.

Cấu trúc bộ contract

Structure

Trong cách Midi Coder tổ chức contracts, contract không được xem là một file duy nhất mà là một bộ nhiều file. Các file này nằm trong một cấu trúc thư mục rõ ràng, nơi mỗi nhóm file giữ một loại thông tin khác nhau.

Cấu trúc thư mục điển hình, theo ví dụ gợi ý trong contracts-spec, gồm:

Không phải lúc nào cũng cần đủ toàn bộ ngay từ đầu. Một team có thể bắt đầu từ bộ tối thiểu như:

Khi nghiệp vụ rõ hơn hoặc flow phức tạp hơn, bộ contract có thể mở rộng thêm events, queries, projections, workflows, policy và scenarios. Nếu dùng công cụ của Midi Coder, đây không nhất thiết là phần người dùng phải tự viết tay từng file từ đầu. Trong flow của Midi Coder, bộ contracts có thể được sinh ra như một bộ đầy đủ hoặc gần đầy đủ từ brief, context và schema, sau đó mới được review, chỉnh sửa và validate tiếp. Cách tách này giúp file ngắn hơn, review dễ hơn và validation cũng mạnh hơn so với việc nhét tất cả vào một mô tả dài.

Vai trò của từng lớp contract

Layers

Trong DSL của Midi Coder, mỗi lớp contract trả lời một câu hỏi khác nhau.

Lớp Vai trò
EntityMô tả thực thể nghiệp vụ cốt lõi của hệ thống. Ở đây team định nghĩa field, khóa chính, index, constraint và tenant scope nếu có.
CommandMô tả những hành động ghi hoặc thay đổi trạng thái mà hệ thống cho phép. Đây là nơi câu hỏi “hệ thống có thể làm gì” được formalize thành input, guard, effect, error và output.
Query / ProjectionMô tả phần đọc. Chúng giúp tách rõ logic ghi và logic đọc, đồng thời cho phép biểu diễn read model một cách rõ ràng hơn.
Rule / PolicyMô tả các điều kiện, ràng buộc và quyền truy cập. Thay vì nhúng mọi điều kiện trực tiếp vào command, phần rule/policy tách riêng để dễ đọc, dễ thay đổi và dễ review.
WorkflowMô tả vòng đời của một entity theo thời gian. Đây là nơi trạng thái và transition được nói rõ thay vì để logic state rải rác trong code.
EffectMô tả tác động hệ thống, ví dụ ghi dữ liệu, emit event, gọi integration hoặc gửi email. Nó là cách contract nói “sau khi hành động xảy ra thì hệ thống làm gì”.
APILà lớp mapping hành vi ra HTTP hoặc GraphQL. Nó không tạo thêm nghiệp vụ mới, mà chỉ nối thế giới bên ngoài với application layer.
ScenarioMô tả các flow end-to-end quan trọng để kiểm chứng rằng toàn bộ chuỗi hành vi vẫn hợp lý khi nhìn từ đầu đến cuối.
ValidationLà lớp kiểm tra tính hợp lệ của toàn bộ bộ contract. Một phần là schema validation cho từng file. Phần còn lại là cross-file checking để bảo đảm id, ref, command, route, event, workflow và effect khớp nhau.

Một điểm cần nói rõ là bộ tài liệu nguồn hiện không định nghĩa một lớp UI contract riêng. Nếu cần giải thích phần giao diện bên ngoài, nên nói ở mức API hoặc external interface, không nên suy diễn thành một DSL frontend riêng khi tài liệu chưa hỗ trợ điều đó.

Vì sao flow này có tính kiểm soát hơn

Control

Trong cách Midi Coder triển khai, điểm khác biệt lớn nhất là thay đổi được kiểm soát ở nhiều lớp, không chỉ ở diff code cuối cùng.

Thứ nhất, contract là source of truth cho behavior. Điều này buộc team phải nói rõ hệ thống định làm gì trước khi sinh code.

Thứ hai, schema validation và cross-file checking loại bỏ nhiều lỗi ngay từ đầu. Nếu command tham chiếu một entity không tồn tại, một route map sai command, hoặc một effect dùng event chưa định nghĩa, flow có thể dừng trước khi chạm đến code generation.

Thứ ba, IR và code plan tạo ra lớp trung gian giữa intent và implementation. Điều này giúp cách sinh code có thể kiểm tra được và lặp lại được, thay vì mỗi lần lại phụ thuộc vào prompt tự do.

Thứ tư, code được apply dưới dạng patch thay vì sửa file một cách tùy ý. Team vì vậy có thể review thay đổi ở cả mức contract và mức patch.

Thứ năm, contract diff cho phép review thay đổi ở mức ý định nghiệp vụ. Team không chỉ thấy “file nào đổi”, mà còn thấy “behavior nào vừa bị đổi”.

Cuối cùng, vì output luôn gắn với một version contract cụ thể, có thể lần ngược từ code về contract đã sinh ra nó. Đây là nền cho audit, traceability và khả năng lặp lại khi contract và pipeline không đổi.

Ví dụ end-to-end

Example

Ví dụ dưới đây vẫn theo flow mà Midi Coder triển khai. Trường hợp được chọn là chức năng upload hồ sơ nhân sự lên Amazon S3 trong một hệ thống quản lý chấm công, bảng lương và hồ sơ nhân sự.

Ở mức yêu cầu nghiệp vụ, bài toán có vài điểm chính: HR có thể upload hồ sơ nhân sự, hệ thống lưu file lên S3, metadata được lưu vào database, và người dùng phù hợp có thể lấy lại file URL hoặc download URL an toàn. Đây là một ví dụ tốt vì nó không chỉ có entity và command, mà còn kéo theo rule, permission, workflow, event và API route.

Nếu chuyển brief này thành contracts, thay đổi hoặc định nghĩa sẽ trải ra trên nhiều file. Ở domain/ sẽ có Employee, HRDocument, các enum như DocumentType, các error như DocumentNotFound, FileUploadFailed, S3StorageError, và event như EmployeeDocumentUploaded. Ở app/ sẽ có command như UploadEmployeeDocumentCommand, DeleteEmployeeDocumentCommand và query như GetEmployeeDocuments, GetDocumentDownloadURL. Ở rules/ hoặc policy/ sẽ có các ràng buộc như giới hạn kích thước file, pre-signed S3 URL và RBAC cho HR hoặc Admin. Ở workflows/ có thể có vòng đời của HRDocument, và ở api/ là các route upload, list, download.

Ở mức validation, Midi Coder sẽ kiểm tra các tham chiếu này có khớp nhau không. Command upload có dùng đúng entity và error đã định nghĩa không. Event emit ra có tồn tại không. Route HTTP có map đúng command hoặc query không. Policy và permission có bám đúng operation dự kiến không. Nếu một phần không khớp, flow có thể dừng ở bước contract check trước khi chạm đến code generation.

Khi contracts hợp lệ, pipeline build IR rồi tạo code plan cho stack đích. Với brief này, code plan thường sẽ dẫn tới các phần như HTTP endpoint cho upload và download, application service xử lý upload, integration với S3, persistence cho metadata và các phần kiểm tra quyền truy cập. Từ đó, patch được sinh ra và apply vào repo theo đúng plan.

Điểm quan trọng của ví dụ này là nó phản ánh đúng một brief có nhiều lớp thông tin. Người đọc vì vậy sẽ dễ hiểu hơn vì sao Section 9 không nên chỉ hiển thị một file contract đơn lẻ, mà cần hiển thị cả một bộ nhiều file cùng tham gia vào cùng một flow nghiệp vụ.

Bộ contract mẫu thực tế

Reference

Thay vì chỉ nhìn vài snippet rời, phần này mở nguyên bộ contract mẫu để người đọc thấy cách các lớp domain, app, policy, workflow và API cùng nằm trong một workspace. Mục tiêu ở đây là giúp việc review hình dung đúng cảm giác đọc một contract set thực tế trong IDE, chứ không lặp lại phần giải thích khái niệm.

contracts/api/http.yaml contracts/app/commands.yaml contracts/app/queries.yaml contracts/domain/entities.yaml contracts/domain/errors.yaml contracts/domain/events.yaml contracts/domain/value_objects.yaml contracts/glossary.yaml contracts/integrations/integrations.yaml contracts/meta/info.yaml contracts/persistence/model.yaml contracts/policy/policies.yaml contracts/policy/rbac.yaml contracts/rules/rules.yaml contracts/scenarios/scenarios.yaml contracts/workflows/workflows.yaml Khám phá bộ contracts
api
app
domain
integrations
meta
persistence
policy
rules
scenarios
workflows
routes:
  - method: POST
    path: /api/v1/employees/{employee_id}/documents
    command: UploadEmployeeDocument
    description: Upload HR document to S3 and store metadata
    auth: required
    request_schema:
      - name: file
        type: string
        required: true
        description: Binary file data
      - name: document_type
        type: string
        required: true
        description: Type of document (cv, contract, identity_card, 
          tax_document, other)
    response_schema:
      - name: document_id
        type: uuid
        required: true
      - name: file_url
        type: string
        required: true
      - name: uploaded_at
        type: datetime
        required: true
    tags:
      - documents
  - method: GET
    path: /api/v1/employees/{employee_id}/documents
    query: GetEmployeeDocuments
    description: Retrieve all documents for an employee
    auth: required
    request_schema:
      - name: document_type
        type: string
        required: false
        description: Filter by document type
    response_schema:
      - name: documents
        type: list<string>
        required: true
        description: Array of document objects
    tags:
      - documents
  - method: GET
    path: /api/v1/documents/{document_id}/download
    query: GetDocumentDownloadURL
    description: Generate pre-signed S3 URL for secure download
    auth: required
    request_schema:
      - name: expiration
        type: int
        required: false
        description: URL expiration in seconds (default 3600)
    response_schema:
      - name: download_url
        type: string
        required: true
      - name: expires_at
        type: datetime
        required: true
    tags:
      - documents
  - method: DELETE
    path: /api/v1/documents/{document_id}
    command: DeleteEmployeeDocument
    description: Delete document from S3 and remove metadata
    auth: required
    response_schema:
      - name: success
        type: bool
        required: true
    tags:
      - documents
  - method: POST
    path: /api/v1/payroll/{payroll_id}/send
    command: SendPayslipEmail
    description: Send payroll email to employee
    auth: required
    response_schema:
      - name: payslip_id
        type: uuid
        required: true
      - name: email_status
        type: string
        required: true
    tags:
      - payroll
  - method: GET
    path: /api/v1/employees/{employee_id}/payslips
    query: GetEmployeePayslips
    description: Retrieve payslips for an employee
    auth: required
    request_schema:
      - name: period_start
        type: date
        required: false
      - name: period_end
        type: date
        required: false
    response_schema:
      - name: payslips
        type: list<string>
        required: true
        description: Array of payslip objects
    tags:
      - payroll
  - method: POST
    path: /api/v1/attendance/check-in
    command: CheckIn
    description: Record employee check-in with weather info
    auth: required
    request_schema:
      - name: location
        type: string
        required: false
    response_schema:
      - name: attendance_id
        type: uuid
        required: true
      - name: check_in_time
        type: datetime
        required: true
      - name: weather_info
        type: json
        required: true
    tags:
      - attendance
commands:
  - id: UploadEmployeeDocument
    description: Upload HR document to S3 and store metadata
    input:
      - name: employee_id
        type: uuid
        required: true
      - name: document_type
        type: string
        required: true
      - name: file
        type: string
        required: true
        description: Binary file data
      - name: uploaded_by
        type: uuid
        required: true
    guards:
      - id: auth.role
        params:
          roles:
            - HR
            - Admin
    effects:
      - id: db.insert
        params:
          table: hr_documents
          entity: HRDocument
      - id: call.integration
        params:
          target: aws_s3_hr_documents
          operation_id: get_current_weather
          payload:
            employee_id: '{{employee_id}}'
            document_type: '{{document_type}}'
            file: '{{file}}'
      - id: emit.event
        params:
          event: EmployeeDocumentUploaded
    returns:
      - name: document_id
        type: uuid
        required: true
      - name: file_url
        type: string
        required: true
    errors:
      - EmployeeNotFound
      - FileUploadFailed
      - S3StorageError
      - FileSizeExceeded
      - Unauthorized
    emits:
      - EmployeeDocumentUploaded
    category: crud.create
    transaction: true
  - id: DeleteEmployeeDocument
    description: Delete document from S3 and remove metadata
    input:
      - name: document_id
        type: uuid
        required: true
      - name: deleted_by
        type: uuid
        required: true
    guards:
      - id: auth.role
        params:
          roles:
            - HR
            - Admin
    effects:
      - id: call.integration
        params:
          target: aws_s3_hr_documents
          operation_id: get_current_weather
          payload:
            document_id: '{{document_id}}'
      - id: db.delete
        params:
          table: hr_documents
          entity: HRDocument
      - id: emit.event
        params:
          event: EmployeeDocumentDeleted
    returns:
      - name: success
        type: bool
        required: true
    errors:
      - DocumentNotFound
      - S3StorageError
      - Unauthorized
    emits:
      - EmployeeDocumentDeleted
    category: crud.delete
    transaction: true
  - id: SendPayslipEmail
    description: Send payroll email to employee
    input:
      - name: payroll_id
        type: uuid
        required: true
      - name: employee_id
        type: uuid
        required: true
    guards:
      - id: auth.role
        params:
          roles:
            - HR
            - Admin
    effects:
      - id: send.email
        params:
          template: payslip
      - id: db.insert
        params:
          table: payslips
          entity: Payslip
      - id: db.update
        params:
          table: payslips
          entity: Payslip
      - id: emit.event
        params:
          event: PayslipSent
    returns:
      - name: payslip_id
        type: uuid
        required: true
      - name: email_status
        type: string
        required: true
    errors:
      - PayrollNotFound
      - EmployeeNotFound
      - EmailDeliveryFailed
    emits:
      - PayslipSent
    category: notification.send
    transaction: true
  - id: CheckIn
    description: Record employee check-in with weather info
    input:
      - name: employee_id
        type: uuid
        required: true
      - name: check_in_time
        type: datetime
        required: true
      - name: location
        type: string
        required: false
    guards:
      - id: auth.role
        params:
          roles:
            - Employee
            - HR
            - Admin
    effects:
      - id: call.integration
        params:
          service: weather_api
          operation: get_weather
      - id: db.insert
        params:
          table: attendance_records
          entity: AttendanceRecord
      - id: emit.event
        params:
          event: EmployeeCheckedIn
    returns:
      - name: attendance_id
        type: uuid
        required: true
      - name: weather_info
        type: json
        required: true
    errors:
      - EmployeeNotFound
      - Unauthorized
    emits:
      - EmployeeCheckedIn
    category: crud.create
    transaction: true
queries:
  - id: GetEmployeeDocuments
    description: Retrieve all documents for an employee
    input:
      - name: employee_id
        type: uuid
        required: true
      - name: document_type
        type: string
        required: false
    returns:
      - name: documents
        type: list<json>
        required: true
    reads_from:
      - hr_documents
    required_roles:
      - HR
      - Admin
      - Employee
    category: list
  - id: GetDocumentDownloadURL
    description: Generate pre-signed S3 URL for secure download
    input:
      - name: document_id
        type: uuid
        required: true
      - name: expiration
        type: int
        required: false
        default: 3600
    returns:
      - name: download_url
        type: string
        required: true
      - name: expires_at
        type: datetime
        required: true
    reads_from:
      - hr_documents
    required_roles:
      - HR
      - Admin
      - Employee
    category: detail
  - id: GetEmployeePayslips
    description: Retrieve payslips for an employee
    input:
      - name: employee_id
        type: uuid
        required: true
      - name: period_start
        type: date
        required: false
      - name: period_end
        type: date
        required: false
    returns:
      - name: payslips
        type: list<json>
        required: true
    reads_from:
      - payslips
      - payrolls
    required_roles:
      - HR
      - Admin
      - Employee
    category: list
entities:
  - id: Employee
    description: Employee entity for HR management
    fields:
      - name: id
        type: uuid
        required: true
      - name: employee_code
        type: string
        required: true
      - name: name
        type: string
        required: true
      - name: email
        type: string
        required: true
      - name: department
        type: string
        required: true
      - name: position
        type: string
        required: true
      - name: status
        type: string
        required: true
      - name: created_at
        type: datetime
        required: true
    primary_key: id
    constraints:
      - type: unique
        fields:
          - employee_code
      - type: unique
        fields:
          - email
  - id: AttendanceRecord
    description: Employee attendance check-in record with weather information
    fields:
      - name: id
        type: uuid
        required: true
      - name: employee_id
        type: uuid
        required: true
      - name: date
        type: date
        required: true
      - name: check_in_time
        type: datetime
        required: true
      - name: check_out_time
        type: datetime
        required: false
      - name: status
        type: string
        required: true
      - name: total_work_hours
        type: decimal
        required: false
      - name: weather_description
        type: string
        required: false
      - name: temperature
        type: decimal
        required: false
    primary_key: id
    constraints:
      - type: foreign_key
        fields:
          - employee_id
        ref: Employee.id
  - id: Payroll
    description: Employee payroll information
    fields:
      - name: id
        type: uuid
        required: true
      - name: employee_id
        type: uuid
        required: true
      - name: period_start
        type: date
        required: true
      - name: period_end
        type: date
        required: true
      - name: net_salary_amount
        type: decimal
        required: true
      - name: net_salary_currency
        type: string
        required: true
        default: VND
      - name: status
        type: string
        required: true
      - name: created_at
        type: datetime
        required: true
    primary_key: id
    constraints:
      - type: foreign_key
        fields:
          - employee_id
        ref: Employee.id
  - id: Payslip
    description: Payroll email delivery record
    fields:
      - name: id
        type: uuid
        required: true
      - name: payroll_id
        type: uuid
        required: true
      - name: employee_id
        type: uuid
        required: true
      - name: file_url
        type: string
        required: true
      - name: sent_at
        type: datetime
        required: true
      - name: email_status
        type: string
        required: true
    primary_key: id
    constraints:
      - type: foreign_key
        fields:
          - payroll_id
        ref: Payroll.id
      - type: foreign_key
        fields:
          - employee_id
        ref: Employee.id
  - id: HRDocument
    description: HR document stored on Amazon S3
    fields:
      - name: id
        type: uuid
        required: true
      - name: employee_id
        type: uuid
        required: true
      - name: document_type
        type: string
        required: true
      - name: file_name
        type: string
        required: true
      - name: file_url
        type: string
        required: true
      - name: s3_bucket
        type: string
        required: true
      - name: s3_key
        type: string
        required: true
      - name: uploaded_by
        type: uuid
        required: true
      - name: uploaded_at
        type: datetime
        required: true
    primary_key: id
    constraints:
      - type: foreign_key
        fields:
          - employee_id
        ref: Employee.id
errors:
  - id: EmployeeNotFound
    code: EMPLOYEE_NOT_FOUND
    description: Employee not found
    http_status: 404
    category: business
  - id: AttendanceNotFound
    code: ATTENDANCE_NOT_FOUND
    description: Attendance record not found
    http_status: 404
    category: business
  - id: PayrollNotFound
    code: PAYROLL_NOT_FOUND
    description: Payroll not found
    http_status: 404
    category: business
  - id: DocumentNotFound
    code: DOCUMENT_NOT_FOUND
    description: HR document not found
    http_status: 404
    category: business
  - id: FileUploadFailed
    code: FILE_UPLOAD_FAILED
    description: Failed to upload file
    http_status: 500
    category: system
  - id: S3StorageError
    code: S3_STORAGE_ERROR
    description: S3 storage operation failed
    http_status: 500
    category: integration
  - id: EmailDeliveryFailed
    code: EMAIL_DELIVERY_FAILED
    description: Failed to send email
    http_status: 500
    category: integration
  - id: Unauthorized
    code: UNAUTHORIZED
    description: Unauthorized access
    http_status: 401
    category: security
  - id: FileSizeExceeded
    code: FILE_SIZE_EXCEEDED
    description: File size exceeds 20MB limit
    http_status: 400
    category: validation
events:
  - id: EmployeeCheckedIn
    description: Employee checked in with attendance record
    kind: domain
    payload:
      - name: employee_id
        type: uuid
        required: true
      - name: attendance_id
        type: uuid
        required: true
      - name: check_in_time
        type: datetime
        required: true
      - name: weather_condition
        type: string
        required: false
      - name: weather_description
        type: string
        required: false
      - name: temperature
        type: decimal
        required: false
      - name: weather_retrieved_at
        type: datetime
        required: false
  - id: PayrollGenerated
    description: Payroll generated for employee
    kind: domain
    payload:
      - name: payroll_id
        type: uuid
        required: true
      - name: employee_id
        type: uuid
        required: true
      - name: period_start
        type: date
        required: true
      - name: period_end
        type: date
        required: true
  - id: PayslipSent
    description: Payslip email sent to employee
    kind: domain
    payload:
      - name: payslip_id
        type: uuid
        required: true
      - name: payroll_id
        type: uuid
        required: true
      - name: employee_id
        type: uuid
        required: true
      - name: sent_at
        type: datetime
        required: true
  - id: EmployeeDocumentUploaded
    description: HR document uploaded to S3
    kind: domain
    payload:
      - name: document_id
        type: uuid
        required: true
      - name: employee_id
        type: uuid
        required: true
      - name: document_type
        type: string
        required: true
      - name: file_url
        type: string
        required: true
      - name: uploaded_by
        type: uuid
        required: true
  - id: EmployeeDocumentDeleted
    description: HR document deleted from S3
    kind: domain
    payload:
      - name: document_id
        type: uuid
        required: true
      - name: employee_id
        type: uuid
        required: true
      - name: deleted_by
        type: uuid
        required: true
  - id: PayslipFailed
    description: Payslip email delivery failed
    kind: domain
    payload:
      - name: payslip_id
        type: uuid
        required: true
      - name: payroll_id
        type: uuid
        required: true
      - name: employee_id
        type: uuid
        required: true
      - name: error_message
        type: string
        required: false
value_objects:
  - id: WeatherInfo
    description: Weather information retrieved during check-in
    fields:
      - name: condition
        type: string
        required: true
        description: Weather condition
      - name: description
        type: string
        required: true
        description: Weather description
      - name: temperature
        type: decimal
        required: true
        description: Temperature value
      - name: retrieved_at
        type: datetime
        required: true
        description: Timestamp when weather data was retrieved
    category:
    tags: []
    source: master-brief
  - id: Money
    description: Monetary value with currency
    fields:
      - name: amount
        type: decimal
        required: true
        description: Monetary amount
      - name: currency
        type: string
        required: true
        default: VND
        description: Currency code
    category: money
    tags: []
    source: master-brief
  - id: DocumentMetadata
    description: Metadata for uploaded documents
    fields:
      - name: file_size
        type: int
        required: true
        description: File size in bytes
      - name: mime_type
        type: string
        required: true
        description: MIME type of the file
      - name: upload_time
        type: datetime
        required: true
        description: Timestamp of upload
    category:
    tags: []
    source: master-brief
glossary:
  terms:
    - id: payroll
      term: Payroll
      definition: bảng lương
      category: business
    - id: payslip
      term: Payslip
      definition: file bảng lương
      category: business
    - id: hr_document
      term: HR Document
      definition: tài liệu nhân sự
      category: business
    - id: s3_object
      term: S3 Object
      definition: file lưu trên S3
      category: technical
    - id: employee
      term: Employee
      definition: nhân viên trong hệ thống
      category: domain
    - id: hr
      term: HR
      definition: nhân viên phòng nhân sự
      category: domain
    - id: admin
      term: Admin
      definition: quản trị viên hệ thống
      category: domain
    - id: attendance
      term: Attendance
      definition: chấm công nhân viên
      category: business
    - id: check_in
      term: Check-in
      definition: ghi nhận thời gian vào làm của nhân viên
      category: process
integrations:
  - id: weather_api
    type: rest_api
    base_url: https://api.weatherapi.com/v1
    auth:
      type: api_key
      key_name: key
    timeouts:
      total_ms: 5000
    tags:
      - weather
      - external
  - id: aws_s3_hr_documents
    type: aws_s3
    provider: aws
    service: s3
    auth:
      type: aws_sigv4
    tags:
      - storage
      - hr
  - id: email_service
    type: smtp
    tags:
      - email
      - payroll
operations:
  - id: get_current_weather
    integration_id: weather_api
    method: GET
    path: /current.json
    request_schema:
      - name: q
        type: string
        required: true
        description: Location query
    response_schema:
      - name: condition
        type: string
        required: true
      - name: temp_c
        type: decimal
        required: true
s3_resources:
  - integration_id: aws_s3_hr_documents
    bucket: hr-documents
    region: ap-southeast-1
    operations:
      - get_current_weather
    path_template: employee/{employee_id}/{document_id}/{filename}
    encryption: AES256
email_providers:
  - id: smtp_payroll
    transport: smtp
    host: smtp.company.com
    port: 587
    username_secret:
    password_secret:
    from_email: payroll@company.com
    from_name: HR Payroll System
info:
  name: Employee Attendance, Payroll & HR Document System
  version: '1.2'
  description: System for managing employee attendance, payroll delivery, and HR
    document storage on Amazon S3
  author: HR Tech Team
  stack: fastapi
  frameworks:
    - fastapi
  languages:
    - python
  keywords:
    - attendance
    - payroll
    - hr-documents
    - s3-storage
    - weather-integration
  tags:
    - hr
    - payroll
    - document-management
    - cloud-storage
datasources:
  - id: main_db
    engine: postgres
    connector: asyncpg
    database: hr_system
    host: localhost
    port: 5432
    default: true
  - id: s3_storage
    engine: postgres
    connector: asyncpg
    database: hr_system
    host: localhost
    port: 5432
tables:
  - id: employees
    description: Employee master data
    datasource: main_db
    columns:
      - name: id
        type: UUID
        required: true
        constraints:
          primary_key: true
      - name: employee_code
        type: VARCHAR
        required: true
        constraints:
          unique: true
      - name: name
        type: VARCHAR
        required: true
      - name: email
        type: VARCHAR
        required: true
        constraints:
          unique: true
      - name: department
        type: VARCHAR
        required: false
      - name: position
        type: VARCHAR
        required: false
      - name: status
        type: VARCHAR
        required: true
      - name: created_at
        type: TIMESTAMP
        required: true
        constraints:
          default: CURRENT_TIMESTAMP
    indexes:
      - name: idx_employee_code
        columns:
          - employee_code
        unique: true
      - name: idx_email
        columns:
          - email
        unique: true
  - id: attendance_records
    description: Employee attendance check-in records
    datasource: main_db
    columns:
      - name: id
        type: UUID
        required: true
        constraints:
          primary_key: true
      - name: employee_id
        type: UUID
        required: true
        constraints:
          foreign_key: employees.id
      - name: date
        type: DATE
        required: true
      - name: check_in_time
        type: TIMESTAMP
        required: true
      - name: check_out_time
        type: TIMESTAMP
        required: false
      - name: status
        type: VARCHAR
        required: true
      - name: total_work_hours
        type: DECIMAL
        required: false
      - name: weather_description
        type: VARCHAR
        required: false
      - name: temperature
        type: DECIMAL
        required: false
    indexes:
      - name: idx_employee_date
        columns:
          - employee_id
          - date
        unique: true
  - id: payrolls
    description: Employee payroll records
    datasource: main_db
    columns:
      - name: id
        type: UUID
        required: true
        constraints:
          primary_key: true
      - name: employee_id
        type: UUID
        required: true
        constraints:
          foreign_key: employees.id
      - name: period_start
        type: DATE
        required: true
      - name: period_end
        type: DATE
        required: true
      - name: net_salary_amount
        type: DECIMAL
        required: true
      - name: net_salary_currency
        type: VARCHAR
        required: true
        constraints:
          default: VND
      - name: status
        type: VARCHAR
        required: true
      - name: created_at
        type: TIMESTAMP
        required: true
        constraints:
          default: CURRENT_TIMESTAMP
    indexes:
      - name: idx_employee_period
        columns:
          - employee_id
          - period_start
          - period_end
  - id: payslips
    description: Payslip email delivery records
    datasource: main_db
    columns:
      - name: id
        type: UUID
        required: true
        constraints:
          primary_key: true
      - name: payroll_id
        type: UUID
        required: true
        constraints:
          foreign_key: payrolls.id
      - name: employee_id
        type: UUID
        required: true
        constraints:
          foreign_key: employees.id
      - name: file_url
        type: TEXT
        required: true
      - name: sent_at
        type: TIMESTAMP
        required: false
      - name: email_status
        type: VARCHAR
        required: true
    indexes:
      - name: idx_payroll
        columns:
          - payroll_id
  - id: hr_documents
    description: HR document metadata stored in database with S3 references
    datasource: main_db
    columns:
      - name: id
        type: UUID
        required: true
        constraints:
          primary_key: true
      - name: employee_id
        type: UUID
        required: true
        constraints:
          foreign_key: employees.id
      - name: document_type
        type: VARCHAR
        required: true
      - name: file_name
        type: VARCHAR
        required: true
      - name: file_url
        type: TEXT
        required: true
      - name: s3_bucket
        type: VARCHAR
        required: true
      - name: s3_key
        type: VARCHAR
        required: true
      - name: uploaded_by
        type: UUID
        required: true
      - name: uploaded_at
        type: TIMESTAMP
        required: true
        constraints:
          default: CURRENT_TIMESTAMP
    indexes:
      - name: idx_employee_documents
        columns:
          - employee_id
      - name: idx_document_type
        columns:
          - document_type
policies:
  - id: document_ownership_policy
    description: Each document must be associated with an employee
    scope: entity:HRDocument
    conditions:
      - field: employee_id
        op: neq
        value:
    effects:
      - type: deny
        params:
          message: Document must be associated with an employee
    tags:
      - document
      - ownership
    source: master-brief section 5 - Business Rules
  - id: file_size_limit_policy
    description: Maximum file size is 20MB
    scope: entity:HRDocument
    conditions:
      - field: file_size
        op: gt
        value: 20971520
    effects:
      - type: deny
        params:
          message: File size exceeds 20MB limit
    tags:
      - document
      - validation
    source: master-brief section 5 - Business Rules
  - id: own_documents_access_policy
    description: Employees can only view their own documents
    scope: entity:HRDocument
    conditions:
      - field: employee_id
        op: eq
        value: '{{actor.employee_id}}'
    effects:
      - type: allow
    tags:
      - document
      - access
      - ownership
    source: master-brief section 5 - RBAC permissions
  - id: own_payroll_access_policy
    description: Employees can only view their own payroll
    scope: entity:Payroll
    conditions:
      - field: employee_id
        op: eq
        value: '{{actor.employee_id}}'
    effects:
      - type: allow
    tags:
      - payroll
      - access
      - ownership
    source: master-brief section 5 - RBAC permissions
  - id: own_attendance_access_policy
    description: Employees can only view their own attendance records
    scope: entity:AttendanceRecord
    conditions:
      - field: employee_id
        op: eq
        value: '{{actor.employee_id}}'
    effects:
      - type: allow
    tags:
      - attendance
      - access
      - ownership
    source: master-brief section 5 - RBAC permissions
  - id: view_own_payroll_ownership_policy
    description: Ownership policy for permission view_own_payroll
    scope: entity:Payroll
    conditions:
      - field: actor.id
        op: eq
        value: actor.id
    effects:
      - type: allow
        params: {}
    tags:
      - view_own_payroll
      - ownership
    source: auto-generated by contract repair safety fix
  - id: view_own_attendance_ownership_policy
    description: Ownership policy for permission view_own_attendance
    scope: entity:AttendanceRecord
    conditions:
      - field: actor.id
        op: eq
        value: actor.id
    effects:
      - type: allow
        params: {}
    tags:
      - view_own_attendance
      - ownership
    source: auto-generated by contract repair safety fix
  - id: view_own_documents_ownership_policy
    description: Ownership policy for permission view_own_documents
    scope: query:GetEmployeeDocuments
    conditions:
      - field: actor.id
        op: eq
        value: actor.id
    effects:
      - type: allow
        params: {}
    tags:
      - view_own_documents
      - ownership
    source: auto-generated by contract repair safety fix
access:
  roles:
    - id: Employee
      description: Regular employee
    - id: HR
      description: HR staff member
    - id: Admin
      description: System administrator
  permissions:
    - id: view_own_payroll
      description: View own payroll information
      resource: entity:Payroll
      action: read
    - id: view_own_attendance
      description: View own attendance records
      resource: entity:AttendanceRecord
      action: read
    - id: check_in
      description: Record attendance check-in
      resource: command:CheckIn
      action: write
    - id: view_own_documents
      description: View own HR documents
      resource: query:GetEmployeeDocuments
      action: read
    - id: upload_employee_documents
      description: Upload employee HR documents
      resource: command:UploadEmployeeDocument
      action: write
    - id: delete_employee_documents
      description: Delete employee HR documents
      resource: command:DeleteEmployeeDocument
      action: delete
    - id: view_all_documents
      description: View all employee documents
      resource: query:GetEmployeeDocuments
      action: read
    - id: send_payslip_email
      description: Send payslip email to employees
      resource: command:SendPayslipEmail
      action: write
    - id: manage_payroll
      description: Manage employee payroll
      resource: entity:Payroll
      action: write
    - id: view_all_attendance
      description: View all attendance records
      resource: entity:AttendanceRecord
      action: read
    - id: manage_employees
      description: Manage employee records
      resource: entity:Employee
      action: admin
    - id: manage_users
      description: Manage system users
      resource: entity:Employee
      action: admin
    - id: view_system_logs
      description: View system logs
      resource: document:system_logs
      action: read
  bindings:
    - role: Employee
      permissions:
        - view_own_payroll
        - view_own_attendance
        - check_in
        - view_own_documents
    - role: HR
      permissions:
        - upload_employee_documents
        - delete_employee_documents
        - view_all_documents
        - send_payslip_email
        - manage_payroll
        - view_all_attendance
    - role: Admin
      permissions:
        - upload_employee_documents
        - delete_employee_documents
        - view_all_documents
        - send_payslip_email
        - manage_payroll
        - view_all_attendance
        - manage_employees
        - manage_users
        - view_system_logs
rules:
  - id: document_access_authorization
    description: "Verify user has permission to access employee documents"
    applies_to: "GetEmployeeDocuments"
    severity: "error"
    tags:
      - authorization
      - documents
    inputs:
      - user_role
      - target_employee_id
      - requesting_user_id
    outputs:
      - access_granted
    rows:
      - when:
          user_role: "Admin"
        then:
          access_granted: true
      - when:
          user_role: "HR"
        then:
          access_granted: true
      - when:
          user_role: "Employee"
          target_employee_id: "{{ requesting_user_id }}"
        then:
          access_granted: true
      - when:
          user_role: "Employee"
        then:
          access_granted: false
  
  - id: document_deletion_authorization
    description: "Verify user has permission to delete employee documents"
    applies_to: "DeleteEmployeeDocument"
    severity: "error"
    tags:
      - authorization
      - documents
    inputs:
      - user_role
    outputs:
      - can_delete
    rows:
      - when:
          user_role: "Admin"
        then:
          can_delete: true
      - when:
          user_role: "HR"
        then:
          can_delete: true
      - when:
          user_role: "Employee"
        then:
          can_delete: false
  
  - id: document_upload_size_limit
    description: "Enforce file size limits for document uploads"
    applies_to: "UploadEmployeeDocument"
    severity: "warning"
    tags:
      - validation
      - documents
    inputs:
      - file_size_bytes
    outputs:
      - size_valid
      - max_size_mb
    rows:
      - when:
          file_size_bytes: "{{ <= 10485760 }}"
        then:
          size_valid: true
          max_size_mb: 10
      - when:
          file_size_bytes: "{{ > 10485760 }}"
        then:
          size_valid: false
          max_size_mb: 10
  
  - id: payslip_email_authorization
    description: "Verify user has permission to send payslip emails"
    applies_to: "SendPayslipEmail"
    severity: "error"
    tags:
      - authorization
      - payroll
    inputs:
      - user_role
    outputs:
      - can_send_email
    rows:
      - when:
          user_role: "Admin"
        then:
          can_send_email: true
      - when:
          user_role: "HR"
        then:
          can_send_email: true
      - when:
          user_role: "Employee"
        then:
          can_send_email: false
  
  - id: attendance_check_in_validation
    description: "Validate check-in requests for attendance tracking"
    applies_to: "CheckIn"
    severity: "warning"
    tags:
      - validation
      - attendance
    inputs:
      - check_in_time
      - employee_id
    outputs:
      - check_in_valid
    rows:
      - when:
          check_in_time: "{{ not null }}"
          employee_id: "{{ not null }}"
        then:
          check_in_valid: true
      - when:
          check_in_time: "{{ null }}"
        then:
          check_in_valid: false
      - when:
          employee_id: "{{ null }}"
        then:
          check_in_valid: false
scenarios:
  - id: upload_employee_document_success
    description: HR uploads employee document successfully
    actors:
      - HR
    preconditions:
      - HR is authenticated
      - Employee exists in system
      - File size is under 20MB
    steps:
      - type: command
        ref: UploadEmployeeDocument
        input:
          employee_id: valid-employee-uuid
          document_type: contract
          file: binary-file-data
          uploaded_by: hr-user-uuid
        expect:
          document_id: generated-uuid
          file_url: s3-url
    postconditions:
      - File stored in S3
      - Metadata stored in database
    tags:
      - hr_documents
      - upload
    source: Master Brief Section 3 - Luồng C
  - id: upload_document_file_size_exceeded
    description: HR uploads document exceeding size limit
    actors:
      - HR
    preconditions:
      - HR is authenticated
      - File size exceeds 20MB
    steps:
      - type: command
        ref: UploadEmployeeDocument
        input:
          employee_id: valid-employee-uuid
          document_type: contract
          file: large-file-data
          uploaded_by: hr-user-uuid
        expect:
          error: FileSizeExceeded
    tags:
      - hr_documents
      - validation
    source: 'Master Brief Section 5 - Rule: File Size Limit'
  - id: view_employee_documents
    description: HR views all documents for an employee
    actors:
      - HR
    preconditions:
      - HR is authenticated
      - Employee exists with documents
    steps:
      - type: query
        ref: GetEmployeeDocuments
        input:
          employee_id: valid-employee-uuid
        expect:
          documents:
            - id: document-uuid
              document_type: contract
              file_name: contract.pdf
              file_url: s3-url
              uploaded_at: timestamp
              uploaded_by: hr-user-uuid
    tags:
      - hr_documents
      - query
    source: Master Brief Section 3 - Luồng D
  - id: download_document_with_presigned_url
    description: HR generates pre-signed URL for document download
    actors:
      - HR
    preconditions:
      - HR is authenticated
      - Document exists
    steps:
      - type: query
        ref: GetDocumentDownloadURL
        input:
          document_id: valid-document-uuid
          expiration: 3600
        expect:
          download_url: presigned-s3-url
          expires_at: timestamp
    postconditions:
      - Pre-signed URL generated
      - URL expires after specified time
    tags:
      - hr_documents
      - security
    source: 'Master Brief Section 5 - Rule: Secure File Access'
  - id: delete_employee_document
    description: HR deletes employee document
    actors:
      - HR
    preconditions:
      - HR is authenticated
      - Document exists
    steps:
      - type: command
        ref: DeleteEmployeeDocument
        input:
          document_id: valid-document-uuid
          deleted_by: hr-user-uuid
        expect:
          success: true
    postconditions:
      - File deleted from S3
      - Metadata removed from database
    tags:
      - hr_documents
      - delete
    source: Master Brief Section 4 - DeleteEmployeeDocumentCommand
  - id: send_payslip_email_success
    description: HR sends payroll email to employee
    actors:
      - HR
    preconditions:
      - HR is authenticated
      - Payroll is approved
      - Employee email is valid
    steps:
      - type: command
        ref: SendPayslipEmail
        input:
          payroll_id: valid-payroll-uuid
          employee_id: valid-employee-uuid
        expect:
          payslip_id: generated-uuid
          email_status: sent
    postconditions:
      - Payslip file generated
      - Email sent to employee
      - Payslip status updated
    tags:
      - payroll
      - email
    source: Master Brief Section 3 - Luồng B
  - id: send_payslip_email_failed
    description: Email delivery fails when sending payslip
    actors:
      - HR
    preconditions:
      - HR is authenticated
      - Payroll is approved
      - Email service unavailable
    steps:
      - type: command
        ref: SendPayslipEmail
        input:
          payroll_id: valid-payroll-uuid
          employee_id: valid-employee-uuid
        expect:
          error: EmailDeliveryFailed
    tags:
      - payroll
      - email
      - error
    source: Master Brief Section 6 - Payroll State Machine
  - id: employee_check_in_with_weather
    description: Employee checks in and receives weather info
    actors:
      - Employee
    preconditions:
      - Employee is authenticated
      - Weather API is available
    steps:
      - type: command
        ref: CheckIn
        input:
          employee_id: valid-employee-uuid
          check_in_time: timestamp
          location: office-location
        expect:
          attendance_id: generated-uuid
          weather_info:
            condition: sunny
            description: clear sky
            temperature: 28.5
            retrieved_at: timestamp
    postconditions:
      - Attendance record created
      - Weather data fetched and stored
    tags:
      - attendance
      - weather
    source: Master Brief Section 3 - Luồng A
  - id: employee_view_own_payslips
    description: Employee retrieves their payslips
    actors:
      - Employee
    preconditions:
      - Employee is authenticated
      - Employee has payslips
    steps:
      - type: query
        ref: GetEmployeePayslips
        input:
          employee_id: valid-employee-uuid
        expect:
          payslips:
            - id: payslip-uuid
              payroll_id: payroll-uuid
              file_url: s3-url
              sent_at: timestamp
              email_status: sent
    tags:
      - payroll
      - employee
    source: Master Brief Section 4 - GetEmployeePayslips
  - id: employee_view_own_documents
    description: Employee views their own HR documents
    actors:
      - Employee
    preconditions:
      - Employee is authenticated
      - Employee has documents
    steps:
      - type: query
        ref: GetEmployeeDocuments
        input:
          employee_id: own-employee-uuid
        expect:
          documents:
            - id: document-uuid
              document_type: contract
              file_name: contract.pdf
              file_url: s3-url
              uploaded_at: timestamp
    tags:
      - hr_documents
      - employee
    source: Master Brief Section 5 - RBAC Permissions
  - id: unauthorized_document_access
    description: Unauthorized user attempts to access documents
    actors:
      - Anonymous
    preconditions:
      - User is not authenticated
    steps:
      - type: query
        ref: GetEmployeeDocuments
        input:
          employee_id: any-employee-uuid
        expect:
          error: Unauthorized
    tags:
      - security
      - authorization
    source: Master Brief Section 2 - Errors
  - id: document_not_found
    description: User attempts to access non-existent document
    actors:
      - HR
    preconditions:
      - HR is authenticated
      - Document does not exist
    steps:
      - type: query
        ref: GetDocumentDownloadURL
        input:
          document_id: invalid-document-uuid
        expect:
          error: DocumentNotFound
    tags:
      - hr_documents
      - error
    source: Master Brief Section 2 - Errors
workflows:
  - id: PayrollWorkflow
    description: Payroll approval and email delivery workflow
    entity: Payroll
    initial_state: draft
    states:
      - id: draft
        description: Payroll in draft state
        kind: initial
      - id: approved
        description: Payroll approved by HR
        kind: normal
      - id: sent
        description: Payslip sent to employee
        kind: final
      - id: failed
        description: Email delivery failed
        kind: final
    transitions:
      - from_state: draft
        to_state: approved
        on_command: SendPayslipEmail
        guards:
          - id: auth.role
            params:
              roles:
                - HR
                - Admin
      - from_state: approved
        to_state: sent
        on_command: SendPayslipEmail
        guards:
          - id: auth.role
            params:
              roles:
                - HR
                - Admin
        effects:
          - id: emit.event
            params:
              event: PayslipSent
      - from_state: approved
        to_state: failed
        on_command: SendPayslipEmail
        effects:
          - id: emit.event
            params:
              event: PayslipFailed
    required_roles:
      - HR
      - Admin
  - id: HRDocumentWorkflow
    description: HR document upload and deletion workflow
    entity: HRDocument
    initial_state: uploaded
    states:
      - id: uploaded
        description: Document uploaded to S3
        kind: initial
      - id: active
        description: Document active and accessible
        kind: normal
      - id: deleted
        description: Document deleted from S3
        kind: final
    transitions:
      - from_state: uploaded
        to_state: active
        on_event: EmployeeDocumentUploaded
      - from_state: active
        to_state: deleted
        on_command: DeleteEmployeeDocument
        guards:
          - id: auth.role
            params:
              roles:
                - HR
                - Admin
        effects:
          - id: emit.event
            params:
              event: EmployeeDocumentDeleted
    required_roles:
      - HR
      - Admin

Khi nào cách làm này phù hợp

Fit

Nếu đánh giá theo mô hình Midi Coder đang triển khai, contract coding phù hợp nhất khi bài toán có domain đủ rõ để formalize. Các dấu hiệu thường gặp là hệ thống có entity rõ, workflow rõ, rule hoặc policy rõ, và team cần review, truy vết hoặc audit tốt hơn.

Phù hợp hơn khi

  • hệ thống có multi-tenant, subscription, billing, auth, reporting hoặc integration
  • nhiều hành vi lặp lại cần consistency qua nhiều vòng thay đổi
  • team muốn review intent nghiệp vụ trước khi review patch code
  • auditability và traceability là yêu cầu thực tế, không chỉ là nice-to-have

Ít phù hợp hơn khi

  • bài toán còn quá exploratory và logic đổi liên tục
  • team chỉ cần vài local edit nhỏ mà không cần duy trì một lớp contract rõ ràng
  • chi phí formalization lớn hơn giá trị kiểm soát trong bối cảnh hiện tại

Nếu muốn đi sâu hơn thì xem gì

Next

Nếu muốn đi sâu hơn theo đúng hướng triển khai hiện tại, phần nên đọc tiếp không phải là thêm một lời giải thích marketing, mà là các trang giúp đối chiếu mô hình này với bối cảnh áp dụng thực tế, cách bắt đầu pilot, và các góc nhìn kỹ thuật liên quan đến contract-first workflow.