Naming Conventions — FitZalo V2
Purpose: Chuẩn hóa naming cho Task IDs, API routes, Events, Permissions, Files. Scope: Áp dụng bắt buộc cho toàn bộ dự án.
1. Task ID
Format: WP-{Phase}.{ModuleKey}.{Seq}
Example: WP-1.IAM.001, WP-3.ORDER.005, WP-0.GOV.002| Field | Rule |
|---|---|
| Phase | 0–8 (theo IMPLEMENTATION_ROADMAP) |
| ModuleKey | UPPERCASE, max 8 chars — xem bảng Module Keys bên dưới |
| Seq | 3 digits, zero-padded |
Module Keys
| Key | Module | Domain |
|---|---|---|
GOV | Governance & Baseline | Phase 0 |
IAM | Identity & Access Mgmt | Core Platform |
TENANT | Multi-Tenancy | Core Platform |
AUDIT | Audit Log | Core Platform |
NOTIFY | Notification Hub | Core Platform |
PLUGIN | Plugin System | Core Platform |
BILLING | Billing & Usage | Core Platform |
CATALOG | Product Catalog | Commerce |
MDM | Master Data | Admin |
ORDER | Order Lifecycle | Commerce |
VOUCHER | Voucher/Promotion | Commerce |
CART | Cart & Checkout | Commerce |
INV | Inventory WMS | Supply Chain |
PROC | Procurement | Supply Chain |
VENDOR | Vendor Management | Supply Chain |
PARTNER | Partner/Customer | CRM |
INBOX | Unified Inbox | CRM |
AFFIL | Affiliate & Loyalty | CRM |
CMS | Content Management | Content |
ESN | Internal Comms | Content |
AI | AI Studio / KB | AI Platform |
ZALO | Zalo Integrations | Integrations |
SHIP | Shipping Layer | Logistics |
ADMIN | System Admin | Admin |
2. API Routes
Format: /api/v2/{domain-plural}/{resource-plural}[/{id}][/{action}]
Example:
GET /api/v2/ecommerce/orders
POST /api/v2/ecommerce/orders/:id/split
PATCH /api/v2/iam/members/:id/role
DELETE /api/v2/catalog/products/:idRules:
- kebab-case for all segments
- Plural nouns for resources
- Verbs only for actions (sub-resources):
/confirm,/validate,/split - No trailing slashes
- Query params for filtering:
?status=ACTIVE&page=1&limit=20
3. Events
Format: {domain}.{entity}.{action}
Example: ecommerce.order.created, inventory.picking.validated, iam.member.invitedRules:
- All lowercase, dot-separated
- Past tense for actions:
created,updated,deleted,confirmed - Domain matches module key (lowercase)
4. Permissions
Format: {DOMAIN}_{ACTION}[_{SCOPE}]
Example: ORDER_VIEW, ORDER_MANAGE, ORDER_REFUND_PROCESS
CAT_MANAGE, INV_ADJUST, CRM_INBOX_REPLYRules:
- UPPERCASE, underscore-separated
- Domain: 2–6 chars abbreviation (IAM, CAT, ORDER, INV, CRM, NOTIFY, etc.)
- Action:
VIEW,MANAGE,CREATE,DELETE,PROCESS,ADMIN,REPLY,PUBLISH - Scope (optional): further qualification
Standard Roles & Permissions Mapping
| Role | Scope | Permission Baseline |
|---|---|---|
SYSTEM_ADMIN | Global | ADMIN_FULL, TENANT_ADMIN, all SYS_* |
TENANT_OWNER | Tenant | All permissions within the tenant |
TENANT_ADMIN | Tenant | Most *_VIEW and *_MANAGE |
TENANT_OPERATOR | Tenant | Daily ops (ORDER_MANAGE, INV_VIEW, CRM_REPLY) |
TENANT_MEMBER | Tenant | Basic *_VIEW only |
Permission Registry Mapping
| Current | Standard | Module |
|---|---|---|
PROD_VIEW_ALL | PROD_VIEW | catalog |
CRM_VIEW_ORDERS | ORDER_VIEW | ecommerce |
SHOP_PROFILE | TENANT_VIEW | iam |
TENANT_READ | TENANT_VIEW | iam |
TENANT_UPDATE | TENANT_MANAGE | iam |
CRM_INBOX_WRITE | INBOX_REPLY | inbox |
5. File Naming
| Type | Convention | Example |
|---|---|---|
| Schema | {entity}.schema.ts | order.schema.ts |
| Controller | {entity}.controller.ts | order.controller.ts |
| Service | {entity}.service.ts | order.service.ts |
| DTO | {entity}.dto.ts | order.dto.ts |
| Consumer | {domain}-{event}.consumer.ts | billing-usage.consumer.ts |
| Spec (test) | {entity}.{type}.spec.ts | order.integration.spec.ts |
| Frontend Page | PascalCase.tsx | OrderList.tsx |
6. Branch & Commit
Branch: feat/{module-key}/{short-description}
Example: feat/order/state-machine, feat/iam/invite-flow
Commit: {type}({module}): {description}
Example: feat(order): implement state machine transitions
fix(iam): tenant guard null check
test(voucher): add stacking validation tests7. Relation Fields & Population Naming
Full spec:
RELATIONSHIP_POPULATION_RULES.md
Persisted Foreign Keys (DB Schema)
| Pattern | Example | Rule |
|---|---|---|
<relation>Id | createdById, categoryId, assigneeId | Singular FK → stores ObjectId |
<relation>Ids | tagIds, roleIds, whitelistUserIds | Array FK → stores ObjectId[] |
Response-Only Relations (API DTO)
| Pattern | Example | Rule |
|---|---|---|
<relation>Summary | createdBySummary, categorySummary | Preferred — projected relation in response |
<relation> | createdBy, category | Allowed ONLY in response DTO; NEVER as DB field storing ID |
Mandatory Audit Fields
All mutable entities MUST have:
createdById: ObjectId— user who createdupdatedById: ObjectId— user who last updateddeletedById: ObjectId(if soft-delete) — user who deleted
❌ FORBIDDEN Patterns
| Forbidden | Why | Correct |
|---|---|---|
createdBy: ObjectId in schema | Ambiguous — can be confused with populated object | createdById: ObjectId |
owner: ObjectId in schema | Ambiguous | ownerId: ObjectId |
| Overwriting FK with populated object | Mutates persisted data | Separate <name>Summary in DTO |
8. Audit Fields Naming
Full spec:
AUDIT_STAMPING_STANDARD.md
| Field | Type | Mandatory | Notes |
|---|---|---|---|
createdAt | Date | ✅ | Auto — { timestamps: true } |
updatedAt | Date | ✅ | Auto — { timestamps: true } |
createdById | ObjectId | ✅ | Service-stamped — NEVER from client |
updatedById | ObjectId | ✅ | Service-stamped on every update |
isDeleted | boolean | ⚠️ | Only if soft-delete enabled |
deletedAt | Date | ⚠️ | Only if soft-delete enabled |
deletedById | ObjectId | ⚠️ | Only if soft-delete enabled |
❌ Forbidden Audit Naming
| Forbidden | Correct |
|---|---|
createdBy: ObjectId | createdById: ObjectId |
updatedBy: ObjectId | updatedById: ObjectId |
deletedBy: ObjectId | deletedById: ObjectId |
createdBy: string | createdById: ObjectId (fix type too) |
9. Time / Date Field Naming
Full spec:
TIME_DATE_STANDARD.md
| Suffix | Semantics | DB Type | Example |
|---|---|---|---|
*At | Server-controlled instant (lifecycle/audit) | Date (UTC) | createdAt, publishedAt, processedAt |
*Date | Business-controlled instant (user-provided range) | Date (UTC) | startDate, endDate, dueDate |
*On | User-provided date-only (calendar day) | String YYYY-MM-DD | birthOn, invoiceDueOn |
*Month | Month granularity | String YYYY-MM | reportMonth, billingMonth |
*Year | Year granularity | Number | fiscalYear |
❌ Forbidden Time Naming
| Forbidden | Why | Correct |
|---|---|---|
startAt / endAt on business fields | *At implies server-controlled | startDate / endDate |
createdDate / updatedDate | *Date implies user-controlled | createdAt / updatedAt |
bare date | Too generic | orderDate, birthOn, etc. |
Changelog
| Date | Change |
|---|---|
| 2026-02-23 | Initial creation — consolidated from RBAC_PERMISSION_MATRIX + conventions |
| 2026-02-23 | Added §7: Relation Fields & Population Naming (D-008) |
| 2026-02-23 | Added §8: Audit Fields Naming, §9: Time/Date Naming (GOV-AUDIT, GOV-TIME) |