Backend API (Convex)
Function list by table, KISS, args and results
Overview
- KISS architecture, realtime Convex.
- Each group (module) corresponds to 1 file in
packages/backend/convex/*. - Input/output: write concisely; FE uses
api.<module>.<function>from Convex codegen.
members.ts
- create: Create new member
- Args:
{ username, passwordHash, name, phone?, order?, active? } - Returns:
member - Note: check unique username.
- Args:
- updateProfile: Update name/phone
- Args:
{ id, name?, phone? } - Returns:
member
- Args:
- changePassword: Change password
- Args:
{ id, passwordHash } - Returns:
{ success }
- Args:
- toggleActive: Hide/show member
- Args:
{ id, active } - Returns:
{ success }
- Args:
- listBrief: Brief list
- Args:
{ activeOnly? } - Returns:
[{ _id, name, username, phone, active, order }]
- Args:
- getFull: Member details + relations
- Args:
{ id, recentLimit? } - Returns:
{ member, assignedMarkets, recentSurveys }
- Args:
- markets: Assigned markets
- Args:
{ memberId, activeOnly? } - Returns:
markets[](brief)
- Args:
- surveysInRange: Member's surveys by date
- Args:
{ memberId, fromDay, toDay } - Returns:
surveys[]
- Args:
markets.ts
- create: Create market
- Args:
{ name, addressJson, order?, active? } - Returns:
market
- Args:
- update: Update market
- Args:
{ id, name?, addressJson? } - Returns:
market
- Args:
- toggleActive: Hide/show market
- Args:
{ id, active } - Returns:
{ success }
- Args:
- reorder: Update order in bulk
- Args:
{ items: [{ id, order }] } - Returns:
{ success }
- Args:
- listBrief: Brief list
- Args:
{ activeOnly? } - Returns:
markets[](brief)
- Args:
- getFull: Market details + relations
- Args:
{ id, recentLimit? } - Returns:
{ market, assignedMembers, recentSurveys }
- Args:
assignments.ts (assignments)
- assign: Assign member to market (idempotent)
- Args:
{ marketId, memberId } - Returns:
assignment
- Args:
- unassign: Unassign
- Args:
{ marketId, memberId } - Returns:
{ success }
- Args:
- listByMarket: Member list by market
- Args:
{ marketId } - Returns:
members[]
- Args:
- listByMember: Market list by member
- Args:
{ memberId } - Returns:
markets[]
- Args:
units.ts (units)
- listBrief: Unit list
- Args:
{ activeOnly? } - Returns:
units[](sorted by order)
- Args:
- create: Create unit
- Args:
{ name, abbr?, order? } - Returns:
unit(unique name)
- Args:
- update: Edit unit
- Args:
{ id, name?, abbr? } - Returns:
unit
- Args:
- toggleActive: Hide/show unit
- Args:
{ id, active } - Returns:
{ success }
- Args:
- safeDelete: Safe delete (only if no products reference it)
- Args:
{ id } - Returns:
{ success }| Error if products still use it
products.ts (products)
- listBrief: Product list
- Args:
{ activeOnly? } - Returns:
products[](by order)
- Args:
- listWithUnits: Product list with units
- Args:
{ activeOnly? } - Returns:
[{ ...product, unit }]
- Args:
- create: Create product
- Args:
{ name, unitId, note?, order? } - Returns:
product(unique name)
- Args:
- update: Edit product
- Args:
{ id, name?, unitId?, note? } - Returns:
product
- Args:
- toggleActive: Hide/show product
- Args:
{ id, active } - Returns:
{ success }
- Args:
- safeDelete: Safe delete (if no surveyItems reference it)
- Args:
{ id } - Returns:
{ success }| Error if still referenced
- Args:
- reorder: Update order in bulk
- Args:
{ items: [{ id, order }] } - Returns:
{ success }
- Args:
surveys.ts (survey sessions)
- createForMarket: Create survey for market + generate items
- Args:
{ marketId, memberId, surveyDay?, note?, copyFromPrevious? } - Returns:
survey - Note: generate item from active products by
order; can copy prices from most recent survey of same market.
- Args:
- getFull: Get survey + items (expand product/unit)
- Args:
{ id } - Returns:
{ survey, market, member, items[] }
- Args:
- listMineByRange: My survey list by date
- Args:
{ memberId, fromDay, toDay } - Returns:
surveys[](newest first)
- Args:
- deleteCascade: Delete survey and all items
- Args:
{ id } - Returns:
{ success }
- Args:
- lastInMarket: Most recent survey of market
- Args:
{ marketId } - Returns:
survey | null
- Args:
- countFilled: Count rows with entered prices
- Args:
{ id } - Returns:
{ filled, total }
- Args:
surveyItems.ts (survey lines)
- autosave: Save price/note per line (update lastUpdatedAt)
- Args:
{ id, price?, note? } - Returns:
{ success }
- Args:
- listWithProductUnit: Item list + product/unit
- Args:
{ surveyId } - Returns:
items[](expanded)
- Args:
- clearPrice: Clear price of one line
- Args:
{ id } - Returns:
{ success }
- Args:
- bulkClear: Clear prices of multiple lines or all
- Args:
{ surveyId, productIds? } - Returns:
{ success }
- Args:
reports.ts (snapshot reports)
- summaryByMarketRange: Live aggregation by date range (not saved)
- Args:
{ fromDay, toDay } - Returns:
{ summaryRows, includedSurveyIds }
- Args:
- generateRange: Create immutable snapshot report
- Args:
{ fromDay, toDay, createdByAdminId } - Returns:
report - listBrief: Recent report list
- Args:
{ limit? } - Returns:
[{ _id, fromDay, toDay, generatedAt }]
- Args:
- getFull: Report details
- Args:
{ id } - Returns:
report
- Args:
FE Usage Suggestions
- /khaosat:
- Get assigned markets:
members.markets-> "Create survey" button. - Create survey:
surveys.createForMarket-> opensurveys.getFullto display form. - Autosave:
surveyItems.autosave(debounce ~300ms). - History:
surveys.listMineByRange. - /admin:
- Catalog: units/products/markets CRUD + assignments.
- Aggregation:
reports.summaryByMarketRange-> click "Export" =reports.generateRange.