update skill and docs
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
# CTR-nn · contracts/asyncapi/<domain>-events.yaml — AsyncAPI 3.0
|
||||
# Nguồn: ICD_<P> §4 (hợp đồng sự kiện) · DOM_<P> §5 (domain event) · DAT §4.1 (outbox/saga) · SEC §5 (PII)
|
||||
# Quy ước: at-least-once, người nhận khử trùng bằng eventId; breaking change ⇒ eventVersion mới + channel mới
|
||||
asyncapi: 3.0.0
|
||||
info:
|
||||
title: <Domain> Events
|
||||
version: 1.0.0
|
||||
description: |
|
||||
Sự kiện phát từ CMP-nn qua IF-nnn. File này THẮNG bảng ICD §4 khi lệch.
|
||||
Không chứa PII ngoài id trừ khi SEC §5 cho phép đích danh.
|
||||
defaultContentType: application/json
|
||||
servers:
|
||||
prod:
|
||||
host: <broker-host>
|
||||
protocol: sqs # kafka | sqs | amqp | eventbridge
|
||||
description: production
|
||||
channels:
|
||||
orderPlaced:
|
||||
address: <domain>.<event>.v1
|
||||
description: Phát khi aggregate <Root> commit xong (DOM §5); publish qua outbox (ADR-nnn)
|
||||
messages:
|
||||
OrderPlaced:
|
||||
$ref: '#/components/messages/OrderPlaced'
|
||||
operations:
|
||||
publishOrderPlaced:
|
||||
action: send
|
||||
channel: { $ref: '#/channels/orderPlaced' }
|
||||
summary: CMP-nn publish — IF-nnn
|
||||
x-if: IF-nnn
|
||||
x-producer: CMP-nn
|
||||
x-consumers: [CMP-06, CMP-09]
|
||||
x-ordering: theo partition key <aggregateId>
|
||||
x-delivery: at-least-once · DLQ giữ 14 ngày (FAIL FM-nn)
|
||||
components:
|
||||
messages:
|
||||
OrderPlaced:
|
||||
name: OrderPlaced
|
||||
title: Đơn hàng đã đặt
|
||||
contentType: application/json
|
||||
headers:
|
||||
$ref: '#/components/schemas/EventHeaders'
|
||||
payload:
|
||||
$ref: '#/components/schemas/OrderPlacedPayload'
|
||||
examples:
|
||||
- name: ok
|
||||
headers: { eventId: "018f…", eventVersion: "1.0", occurredAt: "2026-09-22T03:00:00Z", correlationId: "req-…" }
|
||||
payload: { orderId: "018f…", customerId: "018e…", sellerIds: ["018d…"], totalAmount: { amount: "150000.00", currency: "VND" } }
|
||||
schemas:
|
||||
EventHeaders:
|
||||
type: object
|
||||
required: [eventId, eventVersion, occurredAt, correlationId]
|
||||
properties:
|
||||
eventId: { type: string, description: 'Khoá khử trùng cho consumer (ICD §4)' }
|
||||
eventVersion: { type: string, pattern: '^[0-9]+\.[0-9]+$' }
|
||||
occurredAt: { type: string, format: date-time }
|
||||
correlationId: { type: string, description: 'Truyền xuyên suốt từ request gốc (ICD §1 điểm 8)' }
|
||||
Money:
|
||||
type: object
|
||||
required: [amount, currency]
|
||||
properties:
|
||||
amount: { type: string, pattern: '^-?[0-9]+(\.[0-9]{1,2})?$' }
|
||||
currency: { type: string, minLength: 3, maxLength: 3 }
|
||||
OrderPlacedPayload:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [orderId, sellerIds, totalAmount]
|
||||
properties:
|
||||
orderId: { type: string }
|
||||
customerId: { type: [string, 'null'], description: 'null = Guest' }
|
||||
sellerIds: { type: array, items: { type: string }, minItems: 1 }
|
||||
totalAmount: { $ref: '#/components/schemas/Money' }
|
||||
@@ -0,0 +1,155 @@
|
||||
# CTR-nn · contracts/openapi/<module>.yaml — OpenAPI 3.1
|
||||
# Nguồn: ICD_<P> §3 (IF-nnn) · API_<US> của BA · SRS §4.1 (mã lỗi) · SEC §3 (quyền)
|
||||
# Quy ước: ICD §1 — số lớn là string, thời gian date-time UTC, lỗi nghiệp vụ 4xx, phân trang theo ADR-nnn
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: <Module> API
|
||||
version: 1.0.0
|
||||
description: |
|
||||
Contract cho IF-nnn. Tài liệu này THẮNG bảng mô tả trong ICD/API khi lệch.
|
||||
Mã lỗi theo SRS §4.1; quyền theo SEC §3.
|
||||
servers:
|
||||
- url: https://api.<domain>/v1
|
||||
description: production
|
||||
- url: https://api-stg.<domain>/v1
|
||||
description: staging
|
||||
tags:
|
||||
- name: <resource>
|
||||
security:
|
||||
- bearerAuth: []
|
||||
paths:
|
||||
/<resource>:
|
||||
get:
|
||||
operationId: <module>.list<Resource>
|
||||
summary: <Mục đích một câu — khớp ICD §3.x>
|
||||
tags: [<resource>]
|
||||
x-if: IF-nnn
|
||||
x-roles: [ROLE-01, ROLE-02]
|
||||
x-error-codes: [E-<DOMAIN>-0401, E-<DOMAIN>-0403, E-<DOMAIN>-0503]
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/PageCursor'
|
||||
- $ref: '#/components/parameters/PageSize'
|
||||
responses:
|
||||
'200':
|
||||
description: Danh sách
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/<Resource>Page'
|
||||
examples:
|
||||
ok:
|
||||
value: { items: [], nextCursor: null, hasNext: false }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'403': { $ref: '#/components/responses/Forbidden' }
|
||||
'503': { $ref: '#/components/responses/Unavailable' }
|
||||
post:
|
||||
operationId: <module>.create<Resource>
|
||||
summary: <Mục đích>
|
||||
tags: [<resource>]
|
||||
x-if: IF-nnn
|
||||
x-roles: [ROLE-01]
|
||||
x-idempotency: header Idempotency-Key, giữ 24h (ADR-nnn)
|
||||
x-error-codes: [E-<DOMAIN>-0400, E-<DOMAIN>-0409, E-<DOMAIN>-0503]
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/IdempotencyKey'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/<Resource>Create'
|
||||
examples:
|
||||
ok:
|
||||
value: { name: "Cửa hàng 01" }
|
||||
responses:
|
||||
'201':
|
||||
description: Đã tạo
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/<Resource>' }
|
||||
'200':
|
||||
description: Trùng Idempotency-Key — trả bản ghi cũ, không tạo mới
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/<Resource>' }
|
||||
'400': { $ref: '#/components/responses/BadRequest' }
|
||||
'409': { $ref: '#/components/responses/Conflict' }
|
||||
'503': { $ref: '#/components/responses/Unavailable' }
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
parameters:
|
||||
IdempotencyKey:
|
||||
name: Idempotency-Key
|
||||
in: header
|
||||
required: true
|
||||
schema: { type: string, maxLength: 64 }
|
||||
PageCursor:
|
||||
name: cursor
|
||||
in: query
|
||||
schema: { type: string }
|
||||
PageSize:
|
||||
name: size
|
||||
in: query
|
||||
schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
|
||||
schemas:
|
||||
Id:
|
||||
type: string
|
||||
description: Số lớn truyền dạng string (ICD §1 điểm 1)
|
||||
pattern: '^[0-9a-f-]{36}$'
|
||||
Money:
|
||||
type: object
|
||||
required: [amount, currency]
|
||||
properties:
|
||||
amount: { type: string, pattern: '^-?[0-9]+(\.[0-9]{1,2})?$', description: 'decimal dạng string' }
|
||||
currency: { type: string, minLength: 3, maxLength: 3, example: VND }
|
||||
Error:
|
||||
type: object
|
||||
required: [code, message]
|
||||
properties:
|
||||
code: { type: string, pattern: '^E-[A-Z]+-[0-9]{4}$', description: 'Mã lỗi SRS §4.1' }
|
||||
message: { type: string, description: 'Text hiển thị theo SRS §4.2 hoặc mã để client dịch (ICD §1 điểm 6)' }
|
||||
details:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
field: { type: string }
|
||||
code: { type: string }
|
||||
<Resource>:
|
||||
type: object
|
||||
required: [id, createdAt]
|
||||
properties:
|
||||
id: { $ref: '#/components/schemas/Id' }
|
||||
createdAt: { type: string, format: date-time, description: 'UTC ISO-8601' }
|
||||
<Resource>Create:
|
||||
type: object
|
||||
required: [name]
|
||||
properties:
|
||||
name: { type: string, minLength: 1, maxLength: 40, description: '40 code point — khớp FLD-<SCR>-nn' }
|
||||
<Resource>Page:
|
||||
type: object
|
||||
required: [items, hasNext]
|
||||
properties:
|
||||
items: { type: array, items: { $ref: '#/components/schemas/<Resource>' } }
|
||||
nextCursor: { type: [string, 'null'] }
|
||||
hasNext: { type: boolean }
|
||||
responses:
|
||||
BadRequest:
|
||||
description: Sai dữ liệu vào
|
||||
content: { application/json: { schema: { $ref: '#/components/schemas/Error' }, example: { code: E-<DOMAIN>-0400, message: "…" } } }
|
||||
Unauthorized:
|
||||
description: Hết phiên
|
||||
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
|
||||
Forbidden:
|
||||
description: Không đủ quyền — client không xoá dữ liệu đã nhập (ICD §6)
|
||||
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
|
||||
Conflict:
|
||||
description: Vi phạm ràng buộc nghiệp vụ (BR-nnn)
|
||||
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
|
||||
Unavailable:
|
||||
description: Phụ thuộc hỏng/timeout (FAIL FM-nn) — client cho thử lại, giữ dữ liệu đã nhập
|
||||
content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } }
|
||||
Reference in New Issue
Block a user