Admin tạo gói package
Feature URL
Module
admin
Status
shipped
Priority
P1
Platforms
fe · be
AC progress
15 / 15
Last reviewed
2026-06-08
Mục tiêu
Cho phép admin tạo một gói thuê bao mới trong catalog mà không cần deploy code: đặt tên, mã code duy nhất, mô tả, giá theo từng chu kỳ, các flag quyền lợi, trust score band, listing limit, daily listing distribution limit, affiliate rate. Hệ thống tự sinh các giá trị mặc định hợp lý khi admin không truyền (default plans, affiliate rate, status) để giảm sai sót khi nhập liệu.
Phạm vi
Trong phạm vi (In scope):
- API tạo gói
POST /admin/subscriptions/packages, chỉ roleadmin. - Body
CreateSubscriptionPackageRequest:name,code,description,monthlyPriceVnd,monthlyPriceCredits,annualPriceCredits?,annualBonusMonths?,plans?,packageTypes?,listingLimit?,dailyListingDistributionLimit?,addressMasked,aiToolsEnabled,ownerLikelihoodEnabled,trustScoreMaxExclusive,status?,affiliateRate?. - Validate đầy đủ input: range giá, trust score, affiliate rate, plans theo cycle.
- Đảm bảo
codeunique (normalize uppercase trước khi so sánh). - Sinh default khi thiếu:
plans[](1 tháng + 12 tháng),affiliateRate = 0.1000,status = ACTIVE, các flag theo defaults của code. - Trả
201 Created+SubscriptionPackageResponse.
Ngoài phạm vi (Out of scope):
- Cập nhật gói đã có — xem admin-package-update.
- Xem / list gói cho admin (gồm
INACTIVE) — xem admin-package-list. - Xoá gói — không hỗ trợ; dùng
INACTIVEđể ngừng bán. - Seed default packages tự động (thuộc khởi tạo hệ thống, không phải thao tác admin).
- Các flow phía user (xem / mua / đổi / gia hạn) — thuộc module
subscription-package.
User Stories
- Là admin, tôi muốn tạo gói mới với mã code duy nhất, các flag quyền lợi và giá theo chu kỳ để bổ sung vào catalog mà không cần dev deploy.
- Là admin, tôi muốn chỉ nhập các field tối thiểu và để hệ thống tự sinh plans/affiliate rate/status mặc định để tạo gói nhanh.
- Là admin, tôi muốn nhận lỗi rõ ràng khi
codetrùng để không vô tình ghi đè gói khác. - Là hệ thống, tôi muốn validate chặt giá, trust score và affiliate rate để catalog luôn hợp lệ.
Luồng chức năng
sequenceDiagram
actor Admin
participant App as FE Admin
participant BE
Admin->>App: Nhập form tạo gói
App->>BE: POST /admin/subscriptions/packages (CreateSubscriptionPackageRequest)
BE->>BE: Kiểm tra role admin
BE->>BE: Validate name, prices, trustScore, affiliateRate, plans
BE->>BE: Normalize code uppercase
alt Code đã tồn tại
BE-->>App: 409 ResourceAlreadyExists
else OK
BE->>BE: Sinh default plans/affiliateRate/status nếu thiếu
BE->>BE: Build Package entity, normalize plans
BE-->>App: 201 SubscriptionPackageResponse
endAcceptance Criteria
- AC-1:
POST /admin/subscriptions/packagesyêu cầu roleadmin. - AC-2: Body theo
CreateSubscriptionPackageRequest; các field bắt buộc:name,code,monthlyPriceVnd,monthlyPriceCredits,addressMasked,aiToolsEnabled,ownerLikelihoodEnabled,trustScoreMaxExclusive. - AC-3: Validate:
namekhông blank;monthlyPriceVnd >= 0;monthlyPriceCredits >= 0;annualPriceCredits >= 0(nếu có);annualBonusMonths >= 0(nếu có);listingLimit >= 0(nếu có);dailyListingDistributionLimit >= 0(nếu có). - AC-4:
trustScoreMaxExclusivebắt buộc, thuộc[1, 100]. - AC-5:
affiliateRate(nếu có) thuộc[0, 1]. - AC-6:
codenormalize uppercase trước khi lưu và so sánh (premium→PREMIUM). - AC-7: Trùng
code→ 409ResourceAlreadyExistsException. - AC-8:
affiliateRatemặc định0.1000(10%) nếu không truyền. - AC-9:
statusmặc địnhACTIVEnếu không truyền (chỉ nhậnACTIVE/INACTIVEkhi tạo). - AC-10:
plans[]không truyền → backend tự sinh default 2 plans (1 tháng, 12 tháng); 12 tháng cóbonusMonths = 3nếu giá tháng > 0. - AC-11:
plans[]có truyền → validate mỗi entry:cycleMonths > 0,priceVnd >= 0,priceCredits >= 0,bonusMonths >= 0, không có entrynull. - AC-12: Các flag không nằm trong request (smartPush, vipFlashDeal, displayPriorityRank, cleanData, avm, phoneMasked) được suy ra từ defaults theo
code. - AC-15:
dailyListingDistributionLimit(nếu có) là số tin hệ thống tự phân phối cho broker mỗi ngày;0= tắt phân phối tự động. Nếu không truyền, lấy theo default củacode. - AC-13:
trustScoreMaxInclusivelưu DB =trustScoreMaxExclusive - 0.01. - AC-14: Tạo thành công trả
201 Created+SubscriptionPackageResponseđầy đủ field.
Quy tắc nghiệp vụ
codelà machine-readable identifier viết hoa, unique trong catalog; dùng để tham chiếu từ business code.- Giá có 2 đơn vị độc lập:
priceVnd(hiển thị, reconciliation) vàpriceCredits(trừ ví khi mua). MVP: 1 VND ≈ 1 V-Credit nhưng có thể tách rời. annualPriceCreditsmặc định =monthlyPriceCredits × 12nếu không truyền.bonusMonthsmở rộng thời gian hưởng lợi nhưng không tính vào kỳ trả phí / pro-rata refund.listingLimit = nullnghĩa là không giới hạn;dailyFreeUnlockLimitlấy từpackageTypeshoặc defaults theo code.dailyListingDistributionLimitlà số tin hệ thống tự phân phối cho broker mỗi ngày;0nghĩa là tắt phân phối tự động.trustScoreMaxInclusive(DB) suy từtrustScoreMaxExclusive(input):inclusive = exclusive - 0.01.- Một số flag mặc định gắn theo code chuẩn:
smartPushbật cho PREMIUM/PRO/MAX/TEAM;vipFlashDealchỉ MAX/TEAM;displayPriorityRankMAX/TEAM=1, PRO=2, PREMIUM=3, còn lại null. - Không cho phép xoá gói qua API; ngừng bán bằng
INACTIVE. - Tạo gói chỉ thêm vào catalog (
Package), không ảnh hưởng cácUserPackageđã tồn tại.
Dữ liệu & Trạng thái
Entity nghiệp vụ:
Package: gói mới được tạo trong catalog (định nghĩa đầy đủ tại package-view).PackagePlan: entry trongplans[](JSONB) —cycleMonths,priceVnd,priceCredits,bonusMonths.PackageTypeMetadata: metadata tuỳ chọn (trust score band, dailyFreeUnlockLimit, các flag quyền lợi).CreateSubscriptionPackageRequest: payload tạo gói.SubscriptionPackageResponse: view trả về sau khi tạo.
Field đáng chú ý:
dailyListingDistributionLimit: số tin hệ thống tự phân phối cho broker mỗi ngày,0= tắt. Lưu trênPackageentity và trả về trongSubscriptionPackageResponse.
Trạng thái Package (lúc tạo):
ACTIVE— mặc định, bán ngay, hiện trên catalog public.INACTIVE— tạo nhưng chưa bán / tạm ẩn.
Liên quan
- Phụ thuộc: Chưa có.
- Ảnh hưởng: package-view, package-purchase
- Cập nhật gói: admin-package-update