Contract Coding hoạt động như thế nào?
Trang này giải thích cách Contract Coding biến yêu cầu thành contract có thể validate, compile và review trước khi đi vào codebase. Nội dung được nhìn theo hai mức: mức một là khi team tự định nghĩa contract cho hệ thống của mình, mức hai là khi Midi Coder triển khai cách làm đó thành pipeline đầy đủ từ contract đến patch có thể review trong repo.
Contract là gì trong ngữ cảnh này
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ả đó.
- 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
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
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:
-
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.
-
02
Chuyển thành contract
Chuyển yêu cầu đó thành contract.
-
03
Validate
Validate contract ở mức schema và mức quan hệ giữa các file.
-
04
Compile thành IR
Compile contract hợp lệ thành IR.
-
05
Tạo code plan
Tạo code plan từ IR theo stack đích.
-
06
Generate patch
Generate patch tương ứng.
-
07
Apply và review
Apply patch vào codebase và review kết quả.
-
08
Feedback loop
Nếu phát hiện issue, ghi feedback, sửa contract và chạy lại flow.
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
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
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ò |
|---|---|
Entity | Mô 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ó. |
Command | Mô 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 / Projection | Mô 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 / Policy | Mô 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. |
Workflow | Mô 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. |
Effect | Mô 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ì”. |
API | Là 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. |
Scenario | Mô 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. |
Validation | Là 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
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
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.
# Master Brief: Employee Attendance, Payroll & HR Document System
---
# 1. Tổng quan
### Mục tiêu sản phẩm/dịch vụ
Xây dựng hệ thống quản lý nhân sự bao gồm:
* chấm công nhân viên
* gửi bảng lương qua email
* hiển thị thời tiết khi check-in
* **lưu trữ hồ sơ nhân sự trên cloud (Amazon S3)**
Hệ thống giúp:
* HR quản lý hồ sơ nhân sự tập trung
* nhân viên truy cập bảng lương
* lưu trữ tài liệu an toàn và có thể mở rộng.
---
### Đối tượng sử dụng chính
| Actor | Mô tả |
| -------- | ----------------------------- |
| Employee | check-in, nhận bảng lương |
| HR | quản lý nhân sự, upload hồ sơ |
| Admin | quản trị hệ thống |
---
### Phạm vi
**In scope**
* attendance management
* payroll email delivery
* weather integration
* **upload / download HR documents**
* **lưu hồ sơ nhân sự trên S3**
**Out of scope**
* document OCR
* document approval workflow
* DMS phức tạp
---
### Bối cảnh hệ thống liên quan
Hệ thống tích hợp với:
* HRM System
* Payroll System
* Email Service
* Weather API
* **Amazon S3 Storage**
---
### Thuật ngữ chính
| Term | Meaning |
| ----------- | ---------------- |
| Payroll | bảng lương |
| Payslip | file bảng lương |
| HR Document | tài liệu nhân sự |
| S3 Object | file lưu trên S3 |
---
### Metadata version
```yaml
owner: HR Tech Team
version: 1.2
environment: production
contact: hr-tech@company.com
```
---
# 2. Domain & Data
## Entities (map to `domain/entities.yaml`)
### Employee
```yaml
id: UUID
employee_code: string
name: string
email: string
department: string
position: string
status: string
created_at: timestamp
```
### AttendanceRecord
```yaml
id: UUID
employee_id: UUID
date: date
check_in_time: timestamp
check_out_time: timestamp
status: string
total_work_hours: decimal
weather_description: string
temperature: decimal
```
### Payroll
```yaml
id: UUID
employee_id: UUID
period_start: date
period_end: date
net_salary: Money
status: string
created_at: timestamp
```
### Payslip
```yaml
id: UUID
payroll_id: UUID
employee_id: UUID
file_url: string
sent_at: timestamp
email_status: EmailStatus
```
### HRDocument
```yaml
id: UUID
employee_id: UUID
document_type: DocumentType
file_name: string
file_url: string
s3_bucket: string
s3_key: string
uploaded_by: UUID
uploaded_at: timestamp
```
---
## Value Objects (map to `domain/value_objects.yaml`)
### WeatherInfo
```yaml
condition: string
description: string
temperature: decimal
retrieved_at: timestamp
```
### Money
```yaml
amount: decimal
currency: string (default: "VND")
```
### DocumentMetadata
```yaml
file_size: integer
mime_type: string
upload_time: timestamp
```
---
## Enum (map to `domain/entities.yaml` or separate enum definitions)
### DocumentType
```yaml
values:
- cv
- contract
- identity_card
- tax_document
- other
```
### EmailStatus
```yaml
values:
- pending
- sent
- failed
```
### AttendanceStatus
```yaml
values:
- present
- absent
- late
- half_day
```
---
## Errors (map to `domain/errors.yaml`)
```yaml
EmployeeNotFound:
code: "EMPLOYEE_NOT_FOUND"
message: "Employee not found"
http_status: 404
AttendanceNotFound:
code: "ATTENDANCE_NOT_FOUND"
message: "Attendance record not found"
http_status: 404
PayrollNotFound:
code: "PAYROLL_NOT_FOUND"
message: "Payroll not found"
http_status: 404
DocumentNotFound:
code: "DOCUMENT_NOT_FOUND"
message: "HR document not found"
http_status: 404
FileUploadFailed:
code: "FILE_UPLOAD_FAILED"
message: "Failed to upload file"
http_status: 500
S3StorageError:
code: "S3_STORAGE_ERROR"
message: "S3 storage operation failed"
http_status: 500
EmailDeliveryFailed:
code: "EMAIL_DELIVERY_FAILED"
message: "Failed to send email"
http_status: 500
Unauthorized:
code: "UNAUTHORIZED"
message: "Unauthorized access"
http_status: 401
FileSizeExceeded:
code: "FILE_SIZE_EXCEEDED"
message: "File size exceeds 20MB limit"
http_status: 400
```
---
## Persistence Model
### hr_documents
```
id UUID
employee_id UUID
document_type VARCHAR
file_name VARCHAR
file_url TEXT
s3_bucket VARCHAR
s3_key VARCHAR
uploaded_by UUID
uploaded_at TIMESTAMP
```
---
# 3. Luồng nghiệp vụ chính & Scenarios
---
## Luồng A: Check-in
1. employee gửi request check-in
2. system xác thực JWT
3. system gọi Weather API
4. system tạo attendance record
---
## Luồng B: Gửi bảng lương
1. HR approve payroll
2. system tạo payslip
3. system gửi email
4. employee nhận bảng lương
---
## Luồng C: Upload hồ sơ nhân sự
Actor: HR
Steps
1. HR chọn employee
2. HR upload file
3. system upload file lên **Amazon S3**
4. system lưu metadata vào database
5. trả về file_url
---
## Luồng D: Xem hồ sơ nhân sự
Actor: HR / Admin
Steps
1. request document list
2. system truy vấn database
3. trả về **S3 file URL**
---
## Acceptance Scenarios
### Scenario 1
```
Given HR uploads employee document
When upload succeeds
Then file stored in S3
And metadata stored in database
```
---
### Scenario 2
```
Given employee payroll approved
When HR sends payroll
Then employee receives email
```
---
# 4. Commands & Queries
---
## Commands (map to `app/commands.yaml`)
### UploadEmployeeDocumentCommand
**Goal**: Upload HR document to S3 and store metadata
**Input**:
```yaml
employee_id: UUID
document_type: DocumentType
file: binary
uploaded_by: UUID
```
**Output**:
```yaml
document_id: UUID
file_url: string
```
**Side Effects**:
- Upload file to S3 bucket
- Store metadata in hr_documents table
**Errors**:
- EmployeeNotFound
- FileUploadFailed
- S3StorageError
- FileSizeExceeded
- Unauthorized
**Events**:
- EmployeeDocumentUploaded
---
### DeleteEmployeeDocumentCommand
**Goal**: Delete document from S3 and remove metadata
**Input**:
```yaml
document_id: UUID
deleted_by: UUID
```
**Output**:
```yaml
success: boolean
```
**Side Effects**:
- Delete file from S3
- Remove metadata from database
**Errors**:
- DocumentNotFound
- S3StorageError
- Unauthorized
**Events**:
- EmployeeDocumentDeleted
---
### SendPayslipEmailCommand
**Goal**: Send payroll email to employee
**Input**:
```yaml
payroll_id: UUID
employee_id: UUID
```
**Output**:
```yaml
payslip_id: UUID
email_status: EmailStatus
```
**Side Effects**:
- Generate payslip file
- Send email via SMTP/SES
- Update payslip status
**Errors**:
- PayrollNotFound
- EmployeeNotFound
- EmailDeliveryFailed
**Events**:
- PayslipSent
---
### CheckInCommand
**Goal**: Record employee check-in with weather info
**Input**:
```yaml
employee_id: UUID
check_in_time: timestamp
location: string (optional)
```
**Output**:
```yaml
attendance_id: UUID
weather_info: WeatherInfo
```
**Side Effects**:
- Create attendance record
- Fetch weather data from API
**Errors**:
- EmployeeNotFound
- Unauthorized
**Events**:
- EmployeeCheckedIn
---
## Queries (map to `app/queries.yaml`)
### GetEmployeeDocuments
**Goal**: Retrieve all documents for an employee
**Input**:
```yaml
employee_id: UUID
document_type: DocumentType (optional)
```
**Output**:
```yaml
documents:
- id: UUID
document_type: DocumentType
file_name: string
file_url: string
uploaded_at: timestamp
uploaded_by: UUID
```
**Entities Read**: HRDocument, Employee
---
### GetDocumentDownloadURL
**Goal**: Generate pre-signed S3 URL for secure download
**Input**:
```yaml
document_id: UUID
expiration: integer (seconds, default: 3600)
```
**Output**:
```yaml
download_url: string (pre-signed S3 URL)
expires_at: timestamp
```
**Entities Read**: HRDocument
**Errors**:
- DocumentNotFound
- S3StorageError
- Unauthorized
---
### GetEmployeePayslips
**Goal**: Retrieve payslips for an employee
**Input**:
```yaml
employee_id: UUID
period_start: date (optional)
period_end: date (optional)
```
**Output**:
```yaml
payslips:
- id: UUID
payroll_id: UUID
file_url: string
sent_at: timestamp
email_status: EmailStatus
```
**Entities Read**: Payslip, Payroll
---
# 5. Rules & Policy
---
## Business Rules
### Rule: Document Ownership
```
mỗi document phải gắn với một employee
```
---
### Rule: Secure File Access
```
download phải thông qua pre-signed S3 URL
```
---
### Rule: File Size Limit
```
max file size = 20MB
```
---
## RBAC (map to `policy/rbac.yaml`)
### Roles
```yaml
Employee:
description: "Regular employee"
HR:
description: "HR staff member"
Admin:
description: "System administrator"
```
### Permissions (map to `policy/permissions_map.yaml`)
```yaml
Employee:
- view_own_payroll
- view_own_attendance
- check_in
- view_own_documents
HR:
- upload_employee_documents
- delete_employee_documents
- view_all_documents
- send_payslip_email
- manage_payroll
- view_all_attendance
Admin:
- manage_employees
- manage_users
- view_system_logs
- all_hr_permissions
```
### Permission Mapping
```yaml
UploadEmployeeDocumentCommand:
- HR
- Admin
DeleteEmployeeDocumentCommand:
- HR
- Admin
GetEmployeeDocuments:
- HR
- Admin
- Employee (own documents only)
SendPayslipEmailCommand:
- HR
- Admin
CheckInCommand:
- Employee
- HR
- Admin
```
---
# 6. Workflow / State Machine
---
## State Machines (map to `workflows/*.yaml` if complex)
### Payroll States
```yaml
states:
- draft
- approved
- sent
- failed
transitions:
draft -> approved:
trigger: ApprovePayrollCommand
condition: payroll is complete
actor: HR, Admin
approved -> sent:
trigger: SendPayslipEmailCommand
condition: email delivery succeeds
actor: HR, Admin
event: PayslipSent
approved -> failed:
trigger: SendPayslipEmailCommand
condition: email delivery fails
event: PayslipFailed
```
### HRDocument States
```yaml
states:
- uploaded
- active
- deleted
transitions:
uploaded -> active:
trigger: automatic after validation
active -> deleted:
trigger: DeleteEmployeeDocumentCommand
actor: HR, Admin
event: EmployeeDocumentDeleted
```
---
## Domain Events (map to `domain/events.yaml`)
```yaml
EmployeeCheckedIn:
payload:
employee_id: UUID
attendance_id: UUID
check_in_time: timestamp
weather_info: WeatherInfo
PayrollGenerated:
payload:
payroll_id: UUID
employee_id: UUID
period_start: date
period_end: date
PayslipSent:
payload:
payslip_id: UUID
payroll_id: UUID
employee_id: UUID
sent_at: timestamp
EmployeeDocumentUploaded:
payload:
document_id: UUID
employee_id: UUID
document_type: DocumentType
file_url: string
uploaded_by: UUID
EmployeeDocumentDeleted:
payload:
document_id: UUID
employee_id: UUID
deleted_by: UUID
```
---
# 7. API
---
## API Routes (map to `api/http.yaml`)
### Upload Employee Document
```yaml
route: POST /api/v1/employees/{employee_id}/documents
command: UploadEmployeeDocumentCommand
auth: required (JWT)
roles: [HR, Admin]
request:
content_type: multipart/form-data
fields:
file: binary (required)
document_type: string (required)
response:
status: 201
body:
document_id: UUID
file_url: string
uploaded_at: timestamp
errors:
- 400: FileSizeExceeded
- 401: Unauthorized
- 404: EmployeeNotFound
- 500: S3StorageError
```
### List Employee Documents
```yaml
route: GET /api/v1/employees/{employee_id}/documents
query: GetEmployeeDocuments
auth: required (JWT)
roles: [HR, Admin, Employee (own only)]
query_params:
document_type: string (optional)
response:
status: 200
body:
documents: array
errors:
- 401: Unauthorized
- 404: EmployeeNotFound
```
### Download Document
```yaml
route: GET /api/v1/documents/{document_id}/download
query: GetDocumentDownloadURL
auth: required (JWT)
roles: [HR, Admin, Employee (own only)]
response:
status: 200
body:
download_url: string
expires_at: timestamp
errors:
- 401: Unauthorized
- 404: DocumentNotFound
- 500: S3StorageError
```
### Send Payroll Email
```yaml
route: POST /api/v1/payroll/{payroll_id}/send
command: SendPayslipEmailCommand
auth: required (JWT)
roles: [HR, Admin]
response:
status: 200
body:
payslip_id: UUID
email_status: string
errors:
- 401: Unauthorized
- 404: PayrollNotFound
- 500: EmailDeliveryFailed
```
### Check In
```yaml
route: POST /api/v1/attendance/check-in
command: CheckInCommand
auth: required (JWT)
roles: [Employee, HR, Admin]
request:
body:
location: string (optional)
response:
status: 201
body:
attendance_id: UUID
check_in_time: timestamp
weather_info: object
errors:
- 401: Unauthorized
- 404: EmployeeNotFound
```
### API Conventions
```yaml
versioning: URL path (/api/v1/)
auth: JWT Bearer token
error_response_format:
error:
code: string
message: string
details: object (optional)
```
---
# 8. Phi chức năng
Security
```
JWT authentication
RBAC authorization
S3 private bucket
pre-signed URL access
```
---
Performance
```
API latency < 200ms
file upload async
```
---
Observability
Metrics
```
document_upload_rate
email_delivery_rate
attendance_checkin_rate
```
---
Logging
```
log document uploads
log S3 errors
log payroll email delivery
```
---
# 9. Ràng buộc kỹ thuật
Stack
```
Backend: FastAPI
Database: PostgreSQL
Cache: Redis
Storage: Amazon S3
Email: SMTP / SES
```
---
S3 Storage Pattern
```
bucket: hr-documents
key: employee/{employee_id}/{document_id}/{filename}
```
---
Upload Flow
```
Client
│
│ upload
▼
Backend
│
├─ validate file
├─ upload to S3
└─ store metadata
```
---
Transaction
```
upload success → commit DB
upload fail → rollback
```
---
# 10. Phụ lục
Future features
```
document versioning
document approval workflow
HR self-service portal
mobile attendance
AI resume parser
```
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ế
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.
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
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ì
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.