Bỏ qua nội dung

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ỉ role admin.
  • 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 code unique (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

  • 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.
  • 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.
  • admin, tôi muốn nhận lỗi rõ ràng khi code trùng để không vô tình ghi đè gói khác.
  • 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
    end

Acceptance Criteria

  • AC-1: POST /admin/subscriptions/packages yêu cầu role admin.
  • AC-2: Body theo CreateSubscriptionPackageRequest; các field bắt buộc: name, code, monthlyPriceVnd, monthlyPriceCredits, addressMasked, aiToolsEnabled, ownerLikelihoodEnabled, trustScoreMaxExclusive.
  • AC-3: Validate: name khô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: trustScoreMaxExclusive bắt buộc, thuộc [1, 100].
  • AC-5: affiliateRate (nếu có) thuộc [0, 1].
  • AC-6: code normalize uppercase trước khi lưu và so sánh (premiumPREMIUM).
  • AC-7: Trùng code → 409 ResourceAlreadyExistsException.
  • AC-8: affiliateRate mặc định 0.1000 (10%) nếu không truyền.
  • AC-9: status mặc định ACTIVE nếu không truyền (chỉ nhận ACTIVE / INACTIVE khi 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 = 3 nế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ó entry null.
  • 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ủa code.
  • AC-13: trustScoreMaxInclusive lư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ụ

  • code là 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.
  • annualPriceCredits mặc định = monthlyPriceCredits × 12 nếu không truyền.
  • bonusMonths mở rộng thời gian hưởng lợi nhưng không tính vào kỳ trả phí / pro-rata refund.
  • listingLimit = null nghĩa là không giới hạn; dailyFreeUnlockLimit lấy từ packageTypes hoặc defaults theo code.
  • dailyListingDistributionLimit là số tin hệ thống tự phân phối cho broker mỗi ngày; 0 nghĩ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: smartPush bật cho PREMIUM/PRO/MAX/TEAM; vipFlashDeal chỉ MAX/TEAM; displayPriorityRank MAX/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ác UserPackage đã 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 trong plans[] (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ên Package entity và trả về trong SubscriptionPackageResponse.

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