Bỏ qua

SMP User Stories + Acceptance Criteria

Format: Story + Gherkin · Audience: BA, Dev, QC · Updated: v3.3


Cách viết user story

Mỗi story dùng template:

Là <role>, tôi muốn <action> để <benefit>.

Mỗi story có acceptance criteria viết bằng Gherkin (Given/When/Then) — QC viết test case directly từ đây.


Epic 1 · Customer order journey

US-1.1 · Customer đặt đơn dịch vụ

Customer, tôi muốn đặt đơn sửa AC qua app, để không phải gọi điện và biết được giá ước tính.

Acceptance criteria:

Feature: Customer create order

Scenario: Tạo đơn thành công với address mặc định
 Given tôi đã login với account "Nguyễn Văn A"
 And tôi có địa chỉ mặc định "15 Lê Lợi, Q.1"
 When tôi chọn service "Sửa điều hoà"
 And tôi confirm địa chỉ mặc định
 And tôi tap "Đặt ngay"
 Then đơn được tạo với order_id dạng "ord_..."
 And current_stage = "01_created"
 And dispatch tự động trigger trong 5 giây
 And tôi nhận push notification "Đang tìm thợ cho bạn"

Scenario: Lỗi không có thợ qualified trong zone
 Given tôi ở khu vực "Côn Đảo" không có thợ
 When tôi đặt đơn
 Then hệ thống trả về 422 với error "no_agent_available"
 And UI hiển thị "Hiện chưa có thợ ở khu vực này, mời thử khu vực khác"

Scenario: Voucher áp dụng đúng
 Given tôi có voucher HOTSUMMER20 (giảm 20%, max 200k)
 And tôi chọn service trị giá 750k
 When tôi nhập mã HOTSUMMER20
 Then discount = 150,000đ (20% × 750k)
 And total_amount = 600,000đ + VAT 60k = 660,000đ

US-1.2 · Customer xem tracking 2 thợ

Customer, tôi muốn thấy được thợ khảo sát và thợ thực hiện đang ở đâu trong quy trình, để biết khi nào họ tới.

Acceptance criteria:

Scenario: Hiển thị Survey Agent vào stage 3
 Given đơn của tôi đang stage "03_survey_accepted"
 And Survey Agent là "Trương Minh K."
 When tôi mở màn tracking
 Then thấy section "Thợ khảo sát" với:
 - Tên "Trương Minh K."
 - Avatar
 - Pin trên map đang di chuyển
 - ETA "10 phút"
 - Badge SUR màu violet

Scenario: Stage 7 chuyển sang hiển thị Execution Agent
 Given đơn đang stage "07_dispatched_execution"
 And Execution Agent là "Phạm Quốc M."
 When tôi mở tracking
 Then thấy section "Thợ sửa chữa" với badge EXC màu teal
 And section "Thợ khảo sát" thu gọn (hoàn thành)

US-1.3 · Customer duyệt báo giá

Customer, tôi muốn xem báo giá chi tiết từ thợ khảo sát và quyết định duyệt/từ chối, để kiểm soát chi phí.

Scenario: Báo giá có labor + materials
 Given Survey Agent đã hoàn thành khảo sát
 And đề xuất gồm:
 - Step "Thay tụ điện" · labor 100k + Sanyo CBB60-35 80k
 - Step "Nạp gas R32" · labor 120k + SubZero R32-800 400k
 When tôi mở màn báo giá
 Then thấy breakdown:
 - Labor: 220,000đ
 - Material: 480,000đ
 - Phí khảo sát: 80,000đ (đã trả)
 - VAT 10%: 70,000đ
 - Total: 770,000đ
 And 2 button "Duyệt" và "Từ chối"

Scenario: Duyệt báo giá trigger dispatch Execution Agent
 Given tôi đang xem báo giá
 When tôi tap "Duyệt"
 And confirm payment method
 Then đơn chuyển sang stage "06_quote_approved"
 And dispatch Execution Agent bắt đầu
 And wms reserve materials đã chọn

Scenario: Từ chối báo giá cancel đơn
 When tôi tap "Từ chối"
 And nhập lý do
 Then đơn chuyển sang stage "cancelled"
 And tôi được refund phí khảo sát 50% (theo policy)
 And wms release any pending reservations

Epic 2 · Technician work flow

US-2.1 · Thợ nhận đơn từ dispatch

Technician, tôi muốn thấy đơn mới qua push notification và accept nhanh, để không bỏ lỡ cơ hội kiếm tiền.

Scenario: Push notification với 60s window
 Given tôi online và qualified cho đơn ord_X
 When dispatch invite tôi
 Then tôi nhận push trong 2 giây
 And mở app thấy bottom sheet "Đơn mới · 60s"
 And countdown timer hiển thị
 And 2 button "Nhận" / "Bỏ qua"

Scenario: Accept thành công khi tôi là người đầu
 When tôi tap "Nhận" trong 60s
 And tôi là thợ đầu accept
 Then đơn assigned cho tôi
 And UI chuyển sang "Việc của tôi"
 And các thợ khác nhận thông báo "Đơn đã có thợ khác nhận"

Scenario: Accept nhưng đã có thợ khác accept trước
 When tôi tap "Nhận"
 And server detect tôi accept thứ 2
 Then API trả về 409 conflict
 And UI hiển thị "Đơn đã được thợ khác nhận, tiếp tục tìm việc"

US-2.2 · Thợ Survey nhập báo giá với material picker

Survey Agent, tôi muốn chọn vật tư từ danh sách wms với stock real-time, để tránh hứa khách rồi không có vật tư.

Scenario: Material picker hiện variants có stock
 Given step "ac-replace-capacitor" cần material_type "mtyp_capacitor_35uf"
 And catalog có 3 variants: Sanyo (stock 3 cá nhân), Panasonic (stock 12 chung), TQ (hết)
 When tôi tap "Chọn vật tư" cho step này
 Then list hiển thị:
 - "Sanyo CBB60-35 · 80k · Kho cá nhân: 3 cái" (highlight, default selected)
 - "Panasonic AT-35F · 95k · Kho chung HCMC: 12 cái"
 - "TQ no-brand GEN-35 · 45k · Hết hàng" (disabled)

Scenario: Chọn variant xong cập nhật báo giá
 When tôi chọn "Panasonic AT-35F"
 And tap "Xác nhận"
 Then báo giá update:
 - Labor 100k + Material 95k = 195k cho step này

Scenario: Free-form material cho tình huống đặc biệt
 When tôi tap "Vật tư khác"
 And nhập tên "Dầu lạnh POE 100ml"
 And nhập qty 0.1 lit
 And nhập giá bán 80k
 Then thêm dòng material với verify_status = "pending_verify"
 And ops admin nhận task verify sau khi step done

US-2.3 · Thợ Execution upload photo proof

Execution Agent, tôi muốn chụp ảnh trước/sau để chứng minh đã làm, để tránh tranh chấp với khách.

Scenario: Bắt buộc photo proof trước khi finish step
 Given tôi đang ở step "08_in_progress"
 And step yêu cầu photo proof
 When tôi tap "Hoàn thành step"
 And tôi chưa upload photo
 Then UI hiển thị error "Cần upload ít nhất 2 ảnh (before + after)"
 And button "Hoàn thành" disabled

Scenario: Upload ảnh thành công
 When tôi tap "Chụp ảnh trước"
 And chụp 1 ảnh
 And tap "Chụp ảnh sau"
 And chụp 1 ảnh
 Then 2 ảnh upload lên storage (S3/R2)
 And metadata lưu: timestamp, GPS, step_id, agent_id
 And button "Hoàn thành" enabled

Epic 3 · Partner platform

US-3.1 · Partner Owner đặt đơn cho khách cuối

Partner Owner (vd Hùng AC Service), tôi muốn đặt đơn nhân danh khách của tôi với dispatch chỉ trong đội thợ của tôi, để kiểm soát chất lượng.

Scenario: Tạo đơn private dispatch
 Given tôi login với role partner_owner cho "Hùng AC Service"
 And partner có 8 agents qualified
 And wallet balance = 8,500,000đ
 When tôi tạo đơn cho khách "Nguyễn Văn A"
 And chọn dispatch_visibility = "private"
 And tổng tiền dự kiến 750k
 Then đơn được tạo với source = "partner_customer"
 And dispatch chỉ gửi cho 8 agents của partner
 And wallet trừ 750k (balance = 7,750,000đ)

Scenario: Không đủ wallet balance
 Given wallet balance = 500,000đ
 When tôi tạo đơn 750k
 Then API trả về 402 insufficient_balance
 And UI hiển thị "Cần nạp thêm 250,000đ vào ví"
 And button "Nạp tiền ngay"

Scenario: Open dispatch fallback
 When tôi tạo đơn với dispatch_visibility = "open"
 Then dispatch round 1-2 gửi cho 8 agents của partner
 And nếu không ai accept sau 2 rounds → mở rộng cho mọi agents qualified

US-3.2 · Partner Finance xem báo cáo

Partner Finance, tôi muốn xem báo cáo wallet transactions và payout pending, để đối chiếu sổ sách.

Scenario: Xem wallet transactions của tháng
 Given tôi login partner_finance
 When tôi mở "Tài chính" → "Wallet transactions"
 And filter month = "2026-05"
 Then thấy list 87 giao dịch (debit/credit/topup)
 And mỗi row có: time, amount, order_ref, balance_after
 And total debit = 12,800,000đ
 And total topup = 5,000,000đ

Scenario: Export CSV
 When tôi tap "Export CSV"
 Then file download với columns chuẩn:
 txn_id, created_at, type, amount, order_id, balance_after, notes
 And audit log entry created

US-3.3 · Partner Dispatcher tắt agent tạm thời

Partner Dispatcher, tôi muốn toggle on/off agent khi họ nghỉ ốm/phép, để không nhận đơn họ không thể làm.

Scenario: Toggle off agent
 Given tôi có 8 agents
 And agent "Phạm Quốc M." đang online
 When tôi tap toggle off agent này
 Then agent.is_online = false ngay lập tức
 And không nhận đơn mới
 And đơn đang xử lý của agent này không bị ảnh hưởng

Scenario: Toggle on agent đang KYC pending
 Given agent "Phan Nam" có status = pending_kyc
 When tôi tap toggle on
 Then toggle disabled (không thực hiện được)
 And tooltip "Cần SMP duyệt KYC trước"

US-3.4 · Ops admin onboard partner mới

Ops Admin, tôi muốn review KYC docs và approve partner mới, để đảm bảo chất lượng đối tác.

Scenario: Approve partner basic KYC
 Given partner "FreshAir Group" status = "pending_kyc"
 And đã upload GPKD + CCCD + STK
 When tôi mở partner detail
 And click "Approve KYC basic"
 Then partner status = "active"
 And kyc_level = "basic"
 And partner_owner nhận email + SMS thông báo
 And audit log entry

Scenario: Reject KYC vì doc không rõ
 When tôi review GPKD và thấy mờ
 And click "Request re-upload"
 And ghi note "GPKD scan không rõ, vui lòng chụp lại"
 Then partner nhận notification với note
 And status giữ nguyên "pending_kyc"

Epic 4 · Material BOM

US-4.1 · Ops admin tạo Material Variant mới

Ops Admin, tôi muốn thêm SKU mới vào catalog với giá bán, để thợ có nhiều lựa chọn cho khách.

Scenario: Tạo variant Sanyo CBB60-35 mới
 Given material_type "Tụ điện 35μF" đã tồn tại
 When tôi tap "Tạo variant" và nhập:
 - Brand: Sanyo
 - Model: CBB60-35
 - wms_sku: SKU-CAP-SAN-35
 - sell_price: 80,000đ
 - warranty_months: 6
 Then variant tạo thành công
 And system pull cost_price từ wms = 50,000đ
 And margin tự động tính = +60%

Scenario: wms SKU đã tồn tại (duplicate)
 When tôi nhập wms_sku đã có
 Then API trả về 409 conflict
 And error "SKU này đã được dùng cho variant khác"

US-4.2 · Ops verify free-form material

Ops Admin, tôi muốn review vật tư thợ nhập free-form, để đảm bảo không gian lận.

Scenario: Review free-form material
 Given thợ nhập "Bơm xả Daikin TQ" qty 1, giá 280k
 And ghi chú "Khách yêu cầu dùng bơm TQ giá rẻ"
 When tôi mở material_verify page
 And click row này
 Then thấy panel "Expected (BOM)" và "Actual (thợ nhập)"
 And 3 button: "Request clarification", "Reject + refund", "Approve off-catalog"

Scenario: Approve off-catalog
 When tôi click "Approve off-catalog"
 Then material entry status = "verified"
 And đơn này không bị flag
 And audit log entry

Epic 5 · Integration với inside/wms

US-5.1 · System sync customer data từ inside

System, tôi muốn lấy customer data real-time từ inside, để không cần đồng bộ DB duplicate.

Scenario: Get customer info success
 Given SMP có customer_id = "cus_01HX5K"
 When SMP gọi GET inside.local/api/v1/customers/cus_01HX5K
 Then nhận response với name, phone, addresses, tier
 And cache trong Redis 30 giây

Scenario: inside down → degraded mode
 Given inside service không response (timeout > 3s)
 When SMP cần customer data
 Then circuit breaker open
 And UI hiển thị "Đang cập nhật" thay vì tên khách
 And alert ops team

US-5.2 · Webhook payment.succeeded từ inside

System, tôi muốn nhận webhook payment.succeeded để update order status.

Scenario: Valid webhook
 When inside gửi POST /integrations/inside/payment-webhook
 With body: {"event":"payment.succeeded","intent_id":"pi_X","amount_paid":750000,...}
 And HMAC signature valid
 Then SMP tìm order theo metadata.smp_order_id
 And update payment_status = "paid"
 And trigger dispatch survey agent
 And response 200 OK

Scenario: Invalid HMAC signature
 When webhook đến với signature wrong
 Then response 401 unauthorized
 And log security event
 And NOT update order

Epic 6 · Quality & rating

US-6.1 · Customer đánh giá thợ

Customer, tôi muốn đánh giá thợ 1-5 sao và viết review, để giúp các khách khác.

Scenario: Rate sau khi đơn hoàn thành
 Given đơn "ord_X" đang stage "09_completed"
 When tôi mở app sau khi thợ rời đi
 Then tự động hiển thị màn rating
 And bắt buộc chọn 1-5 sao
 And textarea review optional

Scenario: Submit rating
 When tôi chọn 5 sao
 And viết "Thợ K. làm rất nhanh và sạch"
 And tap submit
 Then đơn chuyển sang "10_rated"
 And agent.avg_rating recalculate
 And nếu rating &lt; 3 → tự động tạo dispute task cho ops

Epic 7 · Multi-Agent Step Assignment (v3.5+ DRAFT)

Stories cho cơ chế nhiều thợ cùng 1 step với role + split ratio riêng. Schema Doc 02 §7.7, rules Doc 15 Section Q.

US-7.1 · Lead invites helper into step

As a lead agent on a step I want to invite a helper into my step So that we can work together on tasks that need more hands

Acceptance Criteria: - [ ] Lead có button "Invite helper" trong step detail screen (mobile app) - [ ] Lead chọn helper từ list available agents (filter by location proximity + online status) - [ ] Lead set initial split_bps cho helper (default by service template, có thể adjust) - [ ] System verify SUM(splits including new helper) = 10000 → nếu không, prompt lead adjust existing splits - [ ] Helper nhận push notification với invitation details - [ ] Helper có 30 phút để accept/reject (BR-MA-007) - [ ] After accept, helper thấy step trong "My active orders" - [ ] Audit log: StepAgentAssigned event emitted

Story points: 8

US-7.2 · Lead overrides split ratio for team

As a lead agent on a step I want to adjust split ratios between team members So that I can reflect actual contribution fairly

Acceptance Criteria: - [ ] Lead có button "Adjust splits" khi step in_progress hoặc earlier - [ ] Modal show current splits với editable inputs (display as %, store as bps) - [ ] Real-time validation: SUM MUST = 100% before submit - [ ] Constraint: KHÔNG được giảm split của agent đã status='completed' (BR-MA-004) - [ ] Optional reason text field - [ ] After submit, all agents nhận notification "Split ratio updated" - [ ] Audit log: StepSplitOverridden event với before/after diff - [ ] History viewable: list các override với timestamps

Story points: 5

US-7.3 · Agent views earnings per step

As an agent (lead or helper) I want to see my earnings broken down per step So that I understand exactly how much I made and from what

Acceptance Criteria: - [ ] Earnings screen show list orders → click 1 order → list steps - [ ] Each step show: role (lead/helper/specialist), split %, step revenue, my earned amount - [ ] Status indicator: pending/confirmed/paid - [ ] Helpers chỉ thấy split + amount của mình (KHÔNG thấy của lead/others) per BR-MA-010 - [ ] Lead có thêm view "Team breakdown" show all agents in step (transparency) - [ ] Filter by date range + role - [ ] Sum total at top: total earnings in period - [ ] Currency format theo locale

Story points: 5

US-7.4 · Ops admin configures service step weights

As an Ops admin I want to configure step weights + role splits per service template So that the system has correct defaults for new orders

Acceptance Criteria: - [ ] Admin Web page "Service templates" list all services - [ ] Click service → see N steps with editable step_weight_bps (display as %) - [ ] Real-time validation: SUM of step weights = 100% - [ ] For each step, configure role splits (lead 100% by default, can add helper/specialist with split) - [ ] Specialty dropdown for specialist role (electrician, plumber, etc.) - [ ] Save → validation runs, errors shown inline - [ ] After save, new orders use updated defaults; existing orders unchanged - [ ] Audit log: who changed what (PII compliance) - [ ] Read-only view for Partner Manager role

Story points: 13

US-7.5 · System distributes earnings on step completion

As the finance system I want to automatically post journal entries when a step completes So that each agent receives correct earnings per their split

Acceptance Criteria: - [ ] When order_step.statuscompleted, finance-svc triggered via StepEarningsCalculated event - [ ] Compute step_revenue + per-agent amount_earned per Doc 04 §1.15.3 - [ ] Lead absorbs residual rounding - [ ] Post 1 journal entry with N+1 lines (1 debit revenue_commission + N credit agent_payable per agent) - [ ] SUM(debits) == SUM(credits) exactly (BR-MA-005) - [ ] Idempotent: retry doesn't double-post - [ ] Update order_step_agents.amount_earned for each row - [ ] Emit StepEarningsCalculated event with full breakdown - [ ] Daily reconcile job verify: SUM(order_step_agents.amount_earned) per step ≈ step_revenue

Story points: 13


Epic 8 · Warranty Package (Maintenance Subscription) (v3.5+ DRAFT)

Stories cho gói thuê bao bảo trì + sửa chữa. Schema Doc 02 §7.8, rules Doc 15 Section R, policy Doc 19 §9.

US-8.1 · Customer browses warranty package catalog

As a customer with existing devices I want to browse warranty packages for my device categories So that I can choose a suitable maintenance plan

Acceptance Criteria: - [ ] Catalog screen show packages filtered by device categories KH có - [ ] Mỗi package card show: tên, thời hạn, giá, quotas (vệ sinh + repair), trải nghiệm key features - [ ] Tap package → detail page show full covered_issues + exclusions + T&C - [ ] CTA button "Mua ngay" → kicks off purchase flow

Story points: 5

US-8.2 · Customer registers device

As a customer I want to register my devices (AC, washer, etc.) So that I can purchase warranty for them

Acceptance Criteria: - [ ] "My Devices" screen với add button - [ ] Form: category (dropdown), brand, model, serial, install_date, install_location - [ ] Optional: photo of device - [ ] Save → device available for warranty purchase - [ ] Edit/delete devices (with restrictions if active warranty)

Story points: 5

US-8.3 · Customer purchases warranty package

As a customer I want to purchase a warranty package for my device So that I can get scheduled maintenance + free repairs

Acceptance Criteria: - [ ] After selecting package + device, show summary screen with price + T&C - [ ] Checkbox "I agree to terms" required before payment - [ ] Payment via gateway hoặc wallet - [ ] On success → notification + "My Warranties" updated - [ ] Confirmation email/SMS với gói details + start/end dates - [ ] Validation BR-WPKG-002: cannot buy duplicate active package for same device

Story points: 8

US-8.4 · Customer opens claim for cleaning

As a customer with active warranty I want to schedule a cleaning service using my quota So that I can maintain my device

Acceptance Criteria: - [ ] "My Warranties" → tap warranty → "Sử dụng gói" button - [ ] Show available actions: cleaning (if quota), repair (input issue) - [ ] For cleaning: pick date + time window - [ ] Submit → auto-approved (BR-WPKG-006), free order created - [ ] Quota decremented immediately - [ ] Notification: "Đã xếp lịch vệ sinh vào ngày X"

Story points: 5

US-8.5 · Customer opens claim for repair (with whitelist check)

As a customer I want to request repair when device has issues So that I get free repair if covered

Acceptance Criteria: - [ ] Form: issue_category (dropdown), description, photos - [ ] Pre-validation: check if issue in covered_issues whitelist - [ ] If not covered → show message "Issue này không trong scope. Đặt order trả phí?" + link to normal order - [ ] If covered → submit pending approval - [ ] Push notification when Ops approves/rejects - [ ] On approve: free order created + agent dispatched

Story points: 8

US-8.6 · Ops admin reviews repair claims

As an Ops admin I want to review pending repair claims and decide approve/reject So that quality is maintained and abuse prevented

Acceptance Criteria: - [ ] Admin Web "Warranty Claims" queue · sortable by claimed_at_utc - [ ] Each row: customer name, device, issue, photos, package info - [ ] One-click approve (with optional notes) - [ ] One-click reject (with reason field required) - [ ] On approve: emit WarrantyClaimApproved event, order created - [ ] On reject: customer notified with reason + suggestion - [ ] SLA tracker: claims pending > 5 minutes highlighted red

Story points: 8

US-8.7 · System auto-suggests maintenance scheduling

As a system I want to auto-suggest customers to schedule periodic maintenance So that they use their quota and stay engaged

Acceptance Criteria: - [ ] Cron daily 09:00 VN time - [ ] For each warranty với auto_suggest=TRUE và last cleaning > suggest_interval_days ago - [ ] Send push notification "Đã 3 tháng từ lần vệ sinh trước. Đặt lịch ngay?" - [ ] Deep link to claim flow with cleaning pre-selected - [ ] KH có toggle opt-out trong settings (per warranty) - [ ] No spam: max 1 suggestion per warranty per 30 days

Story points: 5

US-8.8 · System recognizes revenue monthly (deferred → revenue)

As the finance system I want to recognize revenue monthly from deferred warranty subscriptions So that P&L matches actual service delivery

Acceptance Criteria: - [ ] Cron nightly 02:00 UTC - [ ] Process all warranty_revenue_recognition due (recognition_date_utc <= NOW + not posted yet) - [ ] Post journal entry per Doc 16 §3.6.3 - [ ] Update warranty's total_amount_recognized incrementally - [ ] Idempotent: re-run does NOT double-post - [ ] For last month: absorb residual to make total = net_amount exactly - [ ] Daily reconcile: SUM(deferred_revenue) == SUM(price_paid - total_amount_recognized)

Story points: 13

US-8.9 · Customer cancels warranty (cooling-off or proportional refund)

As a customer I want to cancel my warranty package So that I get my money back if I changed mind

Acceptance Criteria: - [ ] "My Warranties" → warranty detail → "Cancel" button (with warning) - [ ] Show estimated refund amount based on policy (cooling-off vs proportional) - [ ] Require explicit confirmation - [ ] Within 7 days: full refund per BR-WPKG-003 - [ ] After 7 days: proportional refund per Doc 16 §3.6.5 - [ ] On confirm: refund initiated, warranty status → cancelled - [ ] Email confirmation with refund timeline

Story points: 8

US-8.10 · Customer renews expiring warranty

As a customer I want to renew my warranty before it expires So that I keep continuous coverage

Acceptance Criteria: - [ ] Notification 7 days before end_date_utc - [ ] "Renew" button in My Warranties (active 30 days before expiry) - [ ] Show renewal price (with loyalty discount if eligible) - [ ] On renew: new warranty starts at old.end_date + 1 day, no gap - [ ] Quotas reset to package defaults (NOT carried over by default per BR-WPKG-012) - [ ] Confirmation email

Story points: 5


Definition of Done

Mỗi story coi như done khi:

  • Code implement đúng acceptance criteria
  • Unit tests cover positive + negative scenarios (≥ 70% coverage)
  • Integration test cho happy path
  • API spec OpenAPI updated
  • Database migration up + down
  • Manual test với mock data ở dev
  • PR review by 2 engineers
  • QA acceptance test pass
  • Doc updated nếu liên quan
  • Deployed to staging và smoke test pass

Story sizing (Fibonacci)

Points Description
1 Trivial · ≤2h · vd thêm field UI
2 Small · ≤4h · vd thêm 1 endpoint đơn giản
3 Medium · ≤1 day · vd CRUD 1 resource
5 Large · ≤3 days · vd flow đa bước có integration
8 Very large · 1 week · vd new feature complex
13 Epic-level · cần break down trước khi commit

Sprint capacity: ~50 story points per team per 2-week sprint (10 dev).