Care Package Module Feature List
Feature surfaces, state models, business rules, and integration flows for care packages.
Care Package Module - Feature List
1. Feature Overview
Care Package is a service contract attached to a physical product purchase. A care package grants the buyer a set of features (pick_drop, repair, service, priority_support, diagnostics, on_site, parts_coverage, warranty_extension) for a fixed duration.
Each care package has a URL-safe slug auto-generated from its name (e.g., "Basic Care" → "basic-care"). Historical slugs are preserved in care_package_slug_history to support SEO-preserving URL redirects. An optional link to a shared seo record enables per-package meta title, description, Open Graph tags, Twitter card metadata, and JSON-LD structured data.
Supported product type: care_package (productKind on products table).
Purchase model: customer selects a care package + pricing tier for a specific cart item, then checks out normally. Payment success triggers subscription creation and activation.
Subscription lifecycle: pending_activation → active → expired (or cancelled / suspended).
2. Route Ownership and Surfaces
| Surface | Route prefix | Owner | Swagger tag |
|---|---|---|---|
| Customer eligibility API | /api/care-packages | CarePackageCustomerController | Care Packages (Mobile) |
| Mobile-composed | /api/mobile/care-packages | MobileModule via CarePackageCustomerModule | same |
| Customer cart API | /api/cart/items/:cartItemId/care-package | CarePackageCartController | Cart (Mobile) |
| Mobile-composed cart | /api/mobile/cart/items/:cartItemId/care-package | same | same |
| Customer subscription API | /api/me/care-packages | CarePackageSubscriptionCustomerController | Care Package Subscriptions (Mobile) |
| Mobile-composed subscription | /api/mobile/me/care-packages | same | same |
| Customer redemption API | /api/me/care-packages/:subscriptionId/requests | CarePackageRedemptionCustomerController | Care Package Redemptions (Mobile) |
| Mobile-composed redemption | /api/mobile/me/care-packages/:subscriptionId/requests | same | same |
| Admin packages API | /api/admin/care-packages | CarePackageAdminController | Care Packages (Admin) |
| Admin subscriptions API | /api/admin/care-package-subscriptions | CarePackageSubscriptionsAdminController | Care Package Subscriptions (Admin) |
| Admin redemptions API | /api/admin/care-package-redemptions | CarePackageRedemptionAdminController | Care Package Redemptions (Admin) |
3. Admin Feature Matrix
Admin Care Packages
| Capability | Endpoint | Permission |
|---|---|---|
| List packages | GET /api/admin/care-packages | CarePackages_READ |
| Create package | POST /api/admin/care-packages | CarePackages_CREATE |
| Get package detail | GET /api/admin/care-packages/:id | CarePackages_READ |
| Update package | PUT /api/admin/care-packages/:id | CarePackages_UPDATE |
| Delete package | DELETE /api/admin/care-packages/:id | CarePackages_DELETE |
| Duplicate package | POST /api/admin/care-packages/:id/duplicate | CarePackages_CREATE |
| Get matching products | GET /api/admin/care-packages/:id/matching-products | CarePackages_READ |
| Bulk upsert features | PUT /api/admin/care-packages/:id/features | CarePackages_UPDATE |
| Replace eligibility rules | PUT /api/admin/care-packages/:id/eligibility-rules | CarePackages_UPDATE |
| Bulk upsert pricing tiers | PUT /api/admin/care-packages/:id/pricing-tiers | CarePackages_UPDATE |
| Get notification schedule | GET /api/admin/care-packages/notification-schedule | CarePackages_READ |
| Upsert notification schedule | PUT /api/admin/care-packages/notification-schedule | CarePackages_UPDATE |
| Upsert per-package notification schedule | PUT /api/admin/care-packages/:id/notification-schedule | CarePackages_UPDATE |
Admin Subscriptions
| Capability | Endpoint | Permission |
|---|---|---|
| List subscriptions | GET /api/admin/care-package-subscriptions | CarePackageSubscriptions_READ |
| Get subscription detail | GET /api/admin/care-package-subscriptions/:id | CarePackageSubscriptions_READ |
| Suspend subscription | POST /api/admin/care-package-subscriptions/:id/suspend | CarePackageSubscriptions_UPDATE |
| Unsuspend subscription | POST /api/admin/care-package-subscriptions/:id/unsuspend | CarePackageSubscriptions_UPDATE |
| Manual activate | POST /api/admin/care-package-subscriptions/:id/activate | CarePackageSubscriptions_UPDATE |
Admin Redemptions
| Capability | Endpoint | Permission |
|---|---|---|
| List redemption requests | GET /api/admin/care-package-redemptions | CarePackageRedemptions_READ |
| Get redemption request | GET /api/admin/care-package-redemptions/:id | CarePackageRedemptions_READ |
| Update redemption status | PUT /api/admin/care-package-redemptions/:id/status | CarePackageRedemptions_UPDATE |
4. Customer/Mobile Feature Matrix
| Capability | Endpoint | Auth | Notes |
|---|---|---|---|
| List available care packages | GET /api/mobile/care-packages/available | Public | filtered by product kind eligibility rules |
| Add care package to cart item | POST /api/mobile/cart/items/:cartItemId/care-package | JWT | 1 per cart item; validates product eligibility and tier active |
| Remove care package from cart item | DELETE /api/mobile/cart/items/:cartItemId/care-package | JWT | no-op if not attached |
| List my subscriptions | GET /api/mobile/me/care-packages | JWT | filterable by status; paginated |
| Get my subscription detail | GET /api/mobile/me/care-packages/:id | JWT | includes feature slots + usage + remainingDays |
| Raise redemption request | POST /api/mobile/me/care-packages/:subscriptionId/requests | JWT | validates active sub, quota |
| List redemption requests | GET /api/mobile/me/care-packages/:subscriptionId/requests | JWT | paginated |
| Get redemption request | GET /api/mobile/me/care-packages/:subscriptionId/requests/:requestId | JWT | |
| Cancel redemption request | POST /api/mobile/me/care-packages/:subscriptionId/requests/:requestId/cancel | JWT | only if pending |
5. Key Business Rules
- Eligibility is defined per care package via
care_package_eligibility_rules. Rules use adimension(category, subcategory, brand, brand_series, product, or price_range) and amode(include/exclude). - One care package per cart item —
cartCarePackageItemshas unique index on(cart_item_id)— one per cart item. carePackageSnapshotandpricingSnapshotare written at subscription creation and are immutable after that point. They capture the care package definition and pricing tier at purchase time.- Subscription activation is triggered by the BullMQ job
care_package.activate_subscriptiondispatched on order payment success. See subscription-lifecycle.mdx. - Feature quota enforcement:
care_package_feature_usagetracksusedCountper(subscriptionId, featureType). Raise-time check comparesusedCountagainstusageCountin the snapshot. isUnlimited = truefeatures skip quota checks entirely.- Redemption status transitions are strictly gated — see redemption.mdx for
VALID_STATUS_TRANSITIONStable. suspendrequiresstatus = "active".unsuspendrequiresstatus = "suspended".manualActivaterequiresstatus = "pending_activation".
6. Subscription Status State Machine
pending_activation
│ ← order.payment_success (BullMQ activate job)
▼
active ──────────────────────────────► expired (daily sweep OR expiryDate ≤ today)
│ ▲
│ ← admin suspend │ unsuspend when expiryDate past
▼ │
suspended ─────────── unsuspend ──────── active
│
│ ← order cancel / admin cancel job
▼
cancelled
(also: any active/pending → cancelled via care_package.cancel_subscription job)Full state machine detail: subscription-lifecycle.mdx.
7. Redemption Request State Machine
pending → accepted → in_progress → completed
pending → in_progress → completed
pending → in_progress → rejected
pending → rejected
accepted → completed
cancelled (terminal, customer-initiated from pending)Full state machine detail: redemption.mdx.
8. Error UX Mapping
| errorCode | Typical HTTP | UX action |
|---|---|---|
CARE_PACKAGE_NOT_FOUND | 404 | Item not available; refresh care package list |
CARE_PACKAGE_INACTIVE | 400 | Package no longer available; remove from cart |
CARE_PACKAGE_PRICING_TIER_NOT_FOUND | 404 | Tier not available; re-select tier |
CARE_PACKAGE_PRICING_TIER_INACTIVE | 400 | Tier no longer offered; re-select tier |
CARE_PACKAGE_ELIGIBILITY_RULE_INVALID_TARGET | 400 | Admin input validation error |
CARE_PACKAGE_ELIGIBILITY_RULE_PRICE_RANGE_INVALID | 400 | Admin input validation error |
CARE_PACKAGE_NOTIFICATION_SCHEDULE_DUPLICATE | 409 | Admin: duplicate days-before-expiry entry |
CARE_PACKAGE_DELETE_HAS_ACTIVE_SUBSCRIPTIONS | 409 | Cannot delete package with active subscribers |
CARE_PACKAGE_CART_ITEM_NOT_FOUND | 404 | Cart item not found |
CARE_PACKAGE_CART_ITEM_ALREADY_HAS_PACKAGE | 409 | Cart item already has a care package; remove first |
CARE_PACKAGE_NOT_ELIGIBLE_FOR_PRODUCT | 400 | Selected package does not apply to this product; re-select from available packages |
CARE_PACKAGE_CART_PACKAGE_NO_LONGER_AVAILABLE | 400 | Package deactivated; clear and re-add |
CARE_PACKAGE_CART_PRICING_TIER_NO_LONGER_ACTIVE | 400 | Tier deactivated; re-select |
CARE_PACKAGE_SUBSCRIPTION_NOT_FOUND | 404 | Subscription not found (also used for ownership mismatch — no disclosure) |
CARE_PACKAGE_SUBSCRIPTION_NOT_ACTIVE | 400 | Subscription must be active to raise redemption request |
CARE_PACKAGE_SUBSCRIPTION_ALREADY_ACTIVE | 400 | Admin: cannot manually activate a non-pending_activation subscription |
CARE_PACKAGE_SUBSCRIPTION_ACTIVATE_FAILED | 400 | Activation failed — invalid snapshot data |
CARE_PACKAGE_SUBSCRIPTION_SUSPEND_INVALID_STATUS | 400 | Only active subscriptions can be suspended |
CARE_PACKAGE_SUBSCRIPTION_UNSUSPEND_INVALID_STATUS | 400 | Only suspended subscriptions can be unsuspended |
CARE_PACKAGE_REDEMPTION_NOT_FOUND | 404 | Redemption request not found |
CARE_PACKAGE_REDEMPTION_NOT_OWNED | 403 | Redemption request does not belong to this customer |
CARE_PACKAGE_REDEMPTION_FEATURE_NOT_ENABLED | 400 | Feature not enabled in this care package |
CARE_PACKAGE_REDEMPTION_QUOTA_EXCEEDED | 400 | Usage quota reached for this feature |
CARE_PACKAGE_REDEMPTION_INVALID_STATUS_TRANSITION | 400 | Admin: invalid status transition |
CARE_PACKAGE_REDEMPTION_CANCEL_NOT_PENDING | 400 | Customer: only pending requests can be cancelled |
9. Integration Flows
9.1 Care Package Purchase Flow
- Customer calls
GET /api/mobile/care-packages/availableto browse eligible care packages for a product. - Guest customers may include
{ carePackage: { carePackageId, pricingTierId } }on the product line inPOST /api/mobile/cart/guest/quotefor read-only totals. - After login,
POST /api/mobile/cart/syncpersists the same optional care package selection while replacing the authenticated cart from the guest/local snapshot. - Authenticated customers with an existing cart item may also call
POST /api/mobile/cart/items/:cartItemId/care-packagewith{ carePackageId, pricingTierId }. - Backend validates: cart item exists + belongs to customer when using the direct add endpoint, product is physical, care package is active, eligibility rules match the product, and tier is active. Writes
cartCarePackageItemsrow with selected IDs andunitPrice. - Customer proceeds to checkout (
POST /api/mobile/orders/checkout). Order service readscartCarePackageItems, createsorder_itemrows for each, and createscare_package_subscriptionsrows withstatus = "pending_activation". - On payment success,
order.payment_successBullMQ job runs. Processor enqueuescare_package.activate_subscriptionjob per subscription. CarePackageProcessor.processActivation()setsstatus = "active", calculatesstartDate/expiryDatefrompricingSnapshot.durationMonths, schedules 30d and 7d reminder jobs.
9.2 Redemption Flow
- Customer calls
POST /api/mobile/me/care-packages/:subscriptionId/requestswith{ featureType, description, attachmentUrls? }. - Backend validates: subscription is
active, feature is enabled in snapshot, quota not exceeded. - Admin calls
PUT /api/admin/care-package-redemptions/:id/statuswith{ status: "accepted" }. - On accept: DB transaction increments
care_package_feature_usage.usedCountand updates request status. - Admin advances through status machine (
in_progress,completed).
10. Release/QA Checklist
-
GET /api/mobile/care-packages/availablereturns only active packages matching product eligibility rules. - Adding a care package to a cart item enforces 1-per-item constraint.
- Guest quote and login sync preserve selected care package add-ons.
- Cart total includes care package prices; care package lines do not trigger shipping.
- Checkout creates
care_package_subscriptionsrows withstatus = "pending_activation". - Payment success enqueues
care_package.activate_subscriptionjobs. - Activation sets
status = "active", calculates dates from pricingSnapshot, schedules reminders. - Expiry sweep runs daily (cron) and bulk-expires active subscriptions past
expiryDate. - Customer
GET /api/mobile/me/care-packages/:idreturnsremainingDaysand feature slot usage. - Redemption raise validates active status, feature enabled, quota.
- Admin
acceptedtransition incrementscarePackageFeatureUsage.usedCountin a transaction. -
suspend/unsuspend/manualActivateenforce correct status guards. -
unsuspendrestores toactiveif expiryDate future,expiredif past. - Ownership disclosure: customer
GET /me/care-packages/:idreturns same 404 code for not-found and wrong-owner.