Steve API
Platform

Technical Architecture

Runtime architecture, data model, processing pipeline, and operational boundaries behind Steve's HTTP APIs.

Runtime topology

flowchart LR
    Mobile["Mobile App\nExpo / React Native"] --> Convex["Convex Backend"]
    Admin["Admin Panel\nReact 19 / Vite"] --> Convex
    Convex --> R2["Cloudflare R2"]
    Convex --> AI["AI Provider\nOpenRouter"]
    Convex --> OL["Open Loyalty API"]
    Convex --> Resend["Resend"]

Monorepo layout

PathPurpose
apps/adminAdmin web application
apps/mobileMobile application
convexBackend schema, functions, HTTP routes, cron jobs
packages/shared-typesShared types and schema helpers
packages/tsconfigShared TypeScript configuration
packages/eslint-configShared lint configuration
landingStatic marketing site

Core data model

Identity

Users are stored in users, with profile separation by role:

  • adminUsers
  • customers

Legacy role and isActive fields still exist on users for compatibility with older data, but the profile tables are the authoritative authorization model.

Workflow model

erDiagram
    workflows ||--o{ workflowVersions : has
    workflows ||--o{ submissions : receives
    workflowVersions ||--o{ submissions : pins
    submissions ||--o{ submissionFiles : has
    submissions ||--o{ submissionEvents : records
    submissions ||--o{ submissionFraudMatches : source

Important tables:

  • workflows: metadata, active flag, latest version pointer, Open Loyalty schema ID
  • workflowVersions: immutable six-stage config snapshots
  • submissions: current state, extracted data, fraud state, review state, sync state
  • submissionFiles: original and enhanced R2 URLs, pHash, EXIF metadata
  • submissionEvents: audit trail
  • submissionFraudMatches: structured fraud findings and reviewer resolution

Supporting tables include:

  • fraudConfig
  • imageModerationConfig
  • aiModelConfig
  • providerAvailability
  • tokenUsage
  • notifications
  • notificationReadStatus
  • apiKeys
  • apiSessions
  • rateLimitBuckets

Processing pipeline

The main orchestration lives in convex/engine/process.ts.

Stage flow

  1. Load submission, files, workflow version, and workflow metadata.
  2. Move status to processing and log processing_started.
  3. If global image moderation is enabled, run an explicit/disturbing-image pre-check before workflow processing continues.
  4. Compute and persist perceptual hashes early to reduce fraud race conditions.
  5. Optionally enhance uploaded images and write enhanced URLs back to submissionFiles.
  6. Resolve the AI model:
    • workflow-specific stage override if present
    • otherwise fall back to global AI config
  7. Run AI analysis through engine/analyze.ts.
  8. Record extracted data, confidence, certainty, summary, and token usage.
  9. Run fraud checks if enabled.
  10. Decide the terminal state for the processing pass:
  • auto-approve
  • send to review
  • fail
  1. If approved and sync is enabled, call engine/sync.ts.

If moderation blocks a submission, the pipeline exits immediately, marks the submission failed, records moderation-specific events, and skips enhancement, AI extraction, fraud checks, and sync.

Workflow stage configuration

Each workflow version stores six stage configs:

StagePurpose
UploadFile count, labels, formats, size, instructions
EnhancementImage preprocessing before AI
AI analysisPrompt, system prompt, output schema, reference images, model overrides
Fraud detectionVisual duplicate and data duplicate controls
ReviewEditable fields, instructions, auto-approve threshold
SyncOpen Loyalty event name, field mapping, static fields

Image moderation is intentionally not a workflow-version stage. It is a global system configuration, managed through imageModerationConfig, so every workflow can be protected by the same pre-step and prompt policy.

AI architecture

Providers

The provider registry is code-defined:

  • openrouter

Model selection

The analysis pipeline supports:

  • workflow-level provider and model overrides
  • optional fallback provider and model
  • global defaults in aiModelConfig

Image moderation uses its own global AI pipeline ID, image_moderation. Its default provider is OpenRouter, and its prompt comes from imageModerationConfig rather than from the workflow version.

Token usage

Moderation requests are tracked separately under sourceType: image_moderation, so the admin usage dashboard can break out moderation traffic from OCR or other workflow analysis calls. Today the active provider set contains only OpenRouter. The provider and fallback selectors remain in place so additional providers can be reintroduced later without redesigning the workflow configuration UI.

Today the active provider set contains only OpenRouter. The provider and fallback selectors remain in place so additional providers can be reintroduced later without redesigning the workflow configuration UI.

Test runs

Super admins can upload ad hoc images in the workflow builder and run unsaved prompt/schema configs through engine/testRun.ts. Those runs also record token usage.

Fraud detection

Fraud checks combine:

  • visual duplicate detection via perceptual hashing
  • data duplicate detection against extracted values

Findings are stored in submissionFraudMatches, not just embedded in a single submission document. Approval is blocked while unresolved fraud matches remain.

Storage model

Files are stored in Cloudflare R2, not Convex file storage.

Patterns:

  • clients request presigned upload URLs
  • clients upload directly to R2
  • backend stores public R2 URLs on submission records
  • enhancement and test-run flows also upload server-side to R2

Key helpers live in:

  • convex/r2Storage.ts
  • convex/lib/r2.ts

Daily orphan cleanup acts as a safety net for abandoned uploads.

Auth and authorization

Authentication

  • Convex Auth with password provider
  • admin web stores auth state through Convex React
  • mobile stores auth tokens in Expo SecureStore

Authorization

Role checks are centralized in convex/lib/roles.ts:

  • super_admin
  • admin
  • reviewer
  • customer users via customers

Notable rules:

  • self-registration is intentionally locked down for non-super-admin accounts
  • only invited customers get valid customer profiles
  • only super admins can use the workflow agent and some workflow-admin actions

Notifications and auditability

  • Submission notifications are stored in notifications
  • Per-user read state is stored in notificationReadStatus
  • Submission audit history is stored in submissionEvents
  • Review detail pages surface both timeline events and fraud-comparison context

Open Loyalty integration

There are two integration paths:

1. Schema push

workflowSchemaSync.ts creates or updates custom-event schemas in Open Loyalty based on the saved workflow sync config and output schema.

2. Submission sync

engine/sync.ts sends approved submissions as custom events. Sync uses the workflow's latest sync-stage config rather than the submission's pinned version, so integration mapping changes apply immediately.

HTTP API surface

Implemented in convex/http.ts:

RouteAudienceNotes
POST /api/agent/chatInternal admin toolingSuper admin only, streaming
GET /api/invitation/validateInvite onboardingPublic
POST /api/invitation/completeInvite onboardingPublic
GET /api/v1/companiesExternal APIAPI key auth
GET /api/v1/jobs/{sessionId}External APIAPI key auth
POST /api/v1/webhooks/testExternal APIAPI key auth

The larger session-based upload API described in the repository is still planned rather than mounted.

Scheduled jobs

Cron jobs currently handle:

  • orphaned R2 object cleanup
  • expired API session cleanup
  • expired rate-limit bucket cleanup
  • expired draft submission cleanup
  • expired trash cleanup
  • deleted notification cleanup

Delivery and current gaps

Current automated coverage is still thin:

  • admin smoke test
  • Convex API-auth tests

There is no broad end-to-end or CI coverage yet for:

  • workflow processing
  • HTTP routes
  • webhook delivery
  • full monorepo lint/typecheck/test gates