Skip to content

System Overview ​

Cropto is a monorepo of independently deployable apps sharing one Prisma schema and a set of TypeScript packages. The trading experience is a classic three-tier system — React clients → a stateless Express API → PostgreSQL — with side effects (SMS, image processing, scheduled work, search indexing) pushed onto BullMQ queues so request handlers stay fast and synchronous-free.

High-level component diagram ​

The apps ​

AppStackDeploys asNotes
apps/apiExpress 4, TypeScript, Prisma 6, BullMQ 5, ZodRailway (Docker, node:22-alpine)The only writer to the primary DB. Thin controllers, thick services.
apps/webReact 18, Vite 8, Tailwind 3, React Query, react-hook-form + Zod, react-i18next, LeafletRailway staticThe farmer/trader trading app. PWA. Built to port to React Native via NativeWind.
apps/adminReact 18, Vite 8, Tailwind 3Railway staticAdmin + sub-admin ops. Same design system as web; role-gated.
apps/marketingNext.js 15 (App Router), Payload CMS 3, PostgresRailwayPublic SEO site. Isolated — its own content DB, never touches the trading DB.
apps/mobileExpo 52, React Native 0.76, NativeWind 4, expo-routerEAS build (Android)Phase 2. Reuses @cropto/api-client + @cropto/hooks.

The shared packages ​

  • @cropto/types — shared domain types & enums (User, SellLead, Offer, TrustTier, …). Imported by every app so the wire contract is one source of truth.
  • @cropto/utils — shared pure utilities.
  • @cropto/api-client — a typed API client shared by web and mobile.
  • @cropto/hooks — shared React hooks (data fetching, formatting).

Backbone principles ​

  1. Stateless API. No in-memory state for domain data — every write goes to Postgres immediately. Rate-limit counters and queues live in Redis so they survive restarts and are shared across instances.
  2. Queue-based side effects. SMS, scheduled jobs, and search indexing never run inline in a request handler. Handlers enqueue and return; workers consume.
  3. Acceptance is the deal. Accepting an offer/bid materialises an Order; there is no separate "confirm" step. Stock physically moves only at buyer receipt (deduct-on-receipt), not at accept or dispatch.
  4. Batch is the source of truth. For a product, the physical Batch (lot) owns quantity, cost, sale price, quality metrics, GI status, and photos. Product.* fields are derived display snapshots.
  5. Owner-only financials. Cost, margin, supplier, and P&L are strictly private to the owning user and never appear on any counterparty-facing serializer. GST, by contrast, is a public statutory attribute of the goods.

Continue to Data & Execution Flow →.

Internal technical documentation — Cropto