Bundles
The Bundles app lets instructors package multiple courses together and sell them at a discounted price. Each bundle has its own pricing, thumbnail, and publication status, and tracks sales and revenue independently.
Key features
Section titled “Key features”- Bundle creation with title, description, thumbnail, pricing, and compare-at price
- Course aggregation — each bundle references multiple courses with sort ordering
- Sales and revenue tracking displayed as dashboard stats
- Status management with draft, published, and inactive states
Page structure
Section titled “Page structure”| Route | Purpose |
|---|---|
/business/apps/bundles | Dashboard with stats and bundle list |
/business/apps/bundles/new | Create a new bundle |
/business/apps/bundles/[id] | Edit an individual bundle |
Data model overview
Section titled “Data model overview”The app uses types from $lib/apps/bundles/types/index.js backed by the ext_bundles database schema.
Core types
Section titled “Core types”| Type | Key fields |
|---|---|
Bundle | id, instructor_id, title, slug, price, compare_price, status, course_count, sales_count, thumbnail_url |
BundleCourse | bundle_id, course_id, sort_order — join table linking bundles to courses |
BundlePurchase | bundle_id, buyer_id, payment_id, amount, status (pending, completed, refunded) |
BundleStats | total_bundles, published_bundles, total_sales, total_revenue |
Composite types
Section titled “Composite types”BundleWithCourses— bundle with its associated course linksBundleWithInstructor— bundle with instructor profile dataBundlePurchaseWithBundle— purchase record with full bundle details
Server load
Section titled “Server load”The load function calls two service functions from $lib/apps/bundles/services/index.js:
| Function | Description |
|---|---|
getInstructorStats(userId) | Returns BundleStats for the instructor |
listInstructorBundles(userId, {}) | Returns all bundles owned by the instructor |
Key components
Section titled “Key components”The dashboard has three sections:
- Stats grid — four
Cardcomponents showing Total Bundles, Published, Total Sales, and Revenue (formatted as USD currency) - Bundle list — a
Cardwith clickable rows showing thumbnail (or stack icon placeholder), title, course count, sales count, date, price, and status badge - Empty state — simple text prompt when no bundles exist
Status badges
Section titled “Status badges”- draft —
secondaryvariant - published —
defaultvariant - inactive —
destructivevariant
Notable integrations
Section titled “Notable integrations”- Courses app dependency — bundles reference courses from the Courses app via
course_idin theBundleCoursejoin table - Compare pricing — the
compare_pricefield enables strikethrough/discount pricing display on public-facing pages - Instructor scoping — all queries are scoped to
instructor_id, ensuring instructors only see their own bundles