Backend (Convex)
API — dashboard
Generated catalog of Convex functions in convex/dashboard/. Regenerated by `bun run docs:api`.
Auto-generated from source. Do not edit by hand — run
bun run docs:api.
query (26)
| Function | Description | Args |
|---|---|---|
dashboardGetAuditActions | The action taxonomy the page filters by, straight from the registry in helpers/auditActions.ts, so every logged action can be filtered for. | {} |
dashboardGetAuditLogs | Get audit logs for dashboard — paginated, filterable, with the acting admin's name resolved. The scan cap is reported separately from an empty result: a filter that finds nothing and a filter that ran out of budget look identical otherwise. | { action: v.optional(v.string()), /** * One AuditActionGroup name. Matches every action the registry files * under that group, which action alone cannot … |
dashboardGetEnvironment | Which deployment the dashboard is talking to and whether it may change the shared Shopify store. Rendered as a banner on the webhooks page and the voucher and Raya generation forms so an admin on dev or a preview knows why a store-changing button was refused (helpers/shopifyWrite.ts). | {} |
dashboardGetWebhookEventHealth | Count webhook events per status for the delivery-health header. Each status reads by_status up to the cap and reports atCap when it hits it, so the page renders "200+" instead of a number the query never counted. | {} |
dashboardGetWebhookEventPayload | Read one webhook event's Shopify payload for the detail drawer. New events point at a webhookPayloads row; events written before that split still hold the JSON inline, so this follows payloadId first and falls back to the stored field, the same order webhooks/scheduled.ts resolves it in for replay. | { eventId: v.id("webhookEvents") } |
dashboardGroupBySlug | Get single group by slug (admin) Useful for URL-based lookups | { slug: v.string(), } |
dashboardGroups | List product groups (admin) | { groupType: v.optional(v.union( v.literal("featured"), v.literal("seasonal"), v.literal("category"), v.literal("promotion"), v.literal("custom") )), isPubli… |
dashboardGroupWithProducts | Get group with its products (admin) | { groupId: v.id("productGroups"), limit: v.optional(v.number()), } |
dashboardListIssuedVouchers | Issued vouchers for the dashboard "Issued Vouchers" page, filtered and paged on the server. streamVouchers picks the narrowest index for the filters, so the list scales past the 5k cap on getAllVouchers. Every filter is applied while scanning rather than trimming an already loaded page, so a filter that rejects most rows costs more reading — not a short page that looks like the end of the data. Search matches a voucher code substring or the holder's name / email / phone / id. | { limit: v.optional(v.number()), cursor: v.optional(v.object({ ts: v.number(), id: v.string() })), status: v.optional(v.union( v.literal("active"), v.literal… |
dashboardListWebhookEvents | List webhook events newest first, optionally narrowed by status and topic. A status reads by_status_created; without one the scan reads by_created_at. Topic is a JS check over the index-bounded stream, so a topic search that finds nothing within the scan cap reports isTruncated rather than passing an exhausted budget off as an empty result. | { status: v.optional(schema.doc("webhookEvents").fields.status), topic: v.optional(v.string()), limit: v.optional(v.number()), cursor: v.optional(webhookEven… |
dashboardProduct | Get single product with override (admin) | { // Deep-link reachable (/products/<id>): accept any string and normalise, so a // malformed id renders "not found" instead of a validator error (rule 12). … |
dashboardProducts | List products with their overrides (admin) | { isFeatured: v.optional(v.boolean()), hasOverride: v.optional(v.boolean()), status: v.optional(v.union(v.literal("active"), v.literal("archived"), v.literal… |
dashboardVoucherKPIs | — | { refreshKey: v.optional(v.number()), } |
dashboardVoucherShopifyHealth | Shopify sync health for issued vouchers. Reports unsynced / orphaned counts on the last 5000 vouchers. | { refreshKey: v.optional(v.number()), } |
getDashboardOverview | — | { dateFrom: v.number(), // Unix timestamp ms dateTo: v.number(), // Unix timestamp ms refreshKey: v.optional(v.number()), } |
getGamificationStats | Get gamification/loyalty statistics Returns stamp campaigns, vouchers, and shake-to-win stats | { dateFrom: v.number(), dateTo: v.number(), refreshKey: v.optional(v.number()), } |
getOrderVolumeTrend | Get order volume trend over time Returns time-series data with platform breakdown | { dateFrom: v.number(), dateTo: v.number(), bucket: v.optional(v.union(v.literal("day"), v.literal("week"), v.literal("month"))), refreshKey: v.optional(v.nu… |
getPlatformDistribution | Get platform distribution Returns breakdown of visitors by platform (iOS, Android, Web) | { dateFrom: v.number(), dateTo: v.number(), refreshKey: v.optional(v.number()), } |
getProductPerformance | Get top performing products Returns products ranked by revenue and engagement | { dateFrom: v.number(), dateTo: v.number(), limit: v.optional(v.number()), refreshKey: v.optional(v.number()), } |
getRecentSales | Get recent sales Returns list of recent orders for the dashboard | { dateFrom: v.optional(v.number()), dateTo: v.optional(v.number()), limit: v.optional(v.number()), refreshKey: v.optional(v.number()), } |
getRevenueTrend | Get revenue trend over time Returns time-series data for revenue chart | { dateFrom: v.number(), dateTo: v.number(), bucket: v.optional(v.union(v.literal("day"), v.literal("week"), v.literal("month"))), refreshKey: v.optional(v.nu… |
getShopifyWebhookById | Get a single webhook subscription by Shopify ID | { shopifyWebhookId: v.string(), } |
getShopifyWebhookStats | Get webhook subscription statistics | {} |
getUserGrowthTrend | Get user growth trend over time Returns time-series data for user signups | { dateFrom: v.number(), dateTo: v.number(), bucket: v.optional(v.union(v.literal("day"), v.literal("week"), v.literal("month"))), refreshKey: v.optional(v.nu… |
getVoucherStats | Get voucher statistics (admin dashboard) | { dateFrom: v.optional(v.number()), dateTo: v.optional(v.number()), refreshKey: v.optional(v.number()), } |
listShopifyWebhooks | List all webhook subscriptions | {} |
mutation (26)
| Function | Description | Args |
|---|---|---|
addProductsToGroup | Add multiple products to a group | { groupId: v.id("productGroups"), productIds: v.array(v.id("shopifyProducts")), } |
bulkGenerateVouchers | — | { templateId: v.id("voucherTemplates"), userIds: v.array(v.string()), channel: v.optional(issueChannelArg), notes: v.optional(v.string()), } |
bulkPublishOverrides | Bulk publish product overrides | { productIds: v.array(v.id("shopifyProducts")), } |
bulkRegisterShopifyWebhooks | Bulk register all required webhooks | {} |
bulkRevokeVouchers | Bulk revoke vouchers (admin). Caps at 50 voucher ids per call and processes them inline. Each voucher gets the same cleanup as single revoke (counter dec + Shopify delete). | { voucherIds: v.array(v.id("vouchers")), reason: v.optional(v.string()), } |
bulkSetBadge | Set product badge (bulk operation) | { productIds: v.array(v.id("shopifyProducts")), badgeLabel: v.union(v.string(), v.null()), } |
bulkSetFeatured | Set product as featured (bulk operation) | { productIds: v.array(v.id("shopifyProducts")), featured: v.boolean(), } |
createProductGroup | Create a product group | { name: v.string(), slug: v.string(), description: v.optional(v.string()), imageUrl: v.optional(v.string()), groupType: v.union( v.literal("featured"), v.lit… |
deleteAllShopifyWebhooks | Delete this deployment's own webhook subscriptions. Webhooks that call another deployment are skipped. | {} |
deleteProductGroup | Delete a product group | { groupId: v.id("productGroups"), } |
deleteProductOverride | Delete a product override | { overrideId: v.id("productOverrides"), } |
deleteShopifyWebhook | Delete a single webhook subscription | { shopifyWebhookId: v.string(), } |
extendVoucherExpiry | Extend a voucher's expiry (admin). Patches expiresAt locally; Shopify discount endsAt is not currently updated — Shopify discounts created via createShopifyDiscountForVoucher have a long endsAt window already (voucher.expiresAt + buffer). If finer sync is needed, follow up with discountCodeBasicUpdate. | { voucherId: v.id("vouchers"), newExpiresAt: v.number(), reason: v.optional(v.string()), } |
issueVoucherToUser | Issue a single voucher to a specific user (admin). Accepts channel + notes, increments the active-voucher counter and writes an audit log. | { templateId: v.id("voucherTemplates"), userId: v.string(), channel: v.optional(issueChannelArg), notes: v.optional(v.string()), } |
publishProductGroup | Publish a product group | { groupId: v.id("productGroups"), } |
refreshShopifyWebhooks | Refresh webhook list from Shopify | { baseUrl: v.optional(v.string()), } |
reissueVoucher | Reissue a voucher (admin). Cancels the original (queueing removal of its Shopify code) and creates a fresh active voucher copy with a new code linked via notes referencing the previous code. | { voucherId: v.id("vouchers"), reason: v.optional(v.string()), } |
removeProductsFromGroup | Remove multiple products from a group | { groupId: v.id("productGroups"), productIds: v.array(v.id("shopifyProducts")), } |
reorderGroupProducts | Reorder products within a group | { groupId: v.id("productGroups"), productOrder: v.array( v.object({ productId: v.id("shopifyProducts"), position: v.number(), }) ), } |
revokeVoucher | Revoke a voucher (admin) Marks voucher as cancelled, decrements activeVouchers counter, and (if the voucher has a Shopify discount node) enqueues a Shopify delete via shopifySyncPool so the code can no longer be redeemed at checkout. | { voucherId: v.id("vouchers"), reason: v.optional(v.string()), } |
syncShopifyWebhookUrls | Re-point this deployment's own outdated webhooks (same host, stale path) at its current URLs. Webhooks that call another deployment are left alone. | {} |
unpublishProductGroup | Unpublish a product group | { groupId: v.id("productGroups"), } |
updateProductGroup | Update a product group | { groupId: v.id("productGroups"), name: v.optional(v.string()), slug: v.optional(v.string()), description: v.optional(v.string()), imageUrl: v.optional(v.str… |
updateProductLocalization | Update product override localization | { overrideId: v.id("productOverrides"), locale: v.string(), title: v.optional(v.string()), description: v.optional(v.string()), heroImageUrl: v.optional(v.st… |
updateShopifyWebhookUrl | Update a webhook's callback URL | { shopifyWebhookId: v.string(), callbackUrl: v.string(), } |
upsertProductOverride | Upsert a product override (create or update) | { productId: v.id("shopifyProducts"), isFeatured: v.optional(v.boolean()), isPublished: v.optional(v.boolean()), badgeLabel: v.optional(v.string()), marketin… |
internalQuery (1)
| Function | Description | Args |
|---|---|---|
aggregateHealth | — | {} |