This document explains the repository structure, the relationship between the two main applications (root client/server vs agro-production/client/server), and how the 6 Soroban contract crates fit into the system.
Agrocylo-Global is a dual-application Agro-DeFi platform on Stellar/Soroban:
- Root
client/+server/— Original marketplace application (peer-to-peer farmer-consumer trade with escrow) agro-production/client/+agro-production/server/— Campaign-based production crowdfunding (investors fund agricultural campaigns and claim returns)
Both applications use Stellar wallets, on-chain escrow, and WebSocket-based real-time updates. They are independent but share some architectural patterns and contract infrastructure.
Status: Earlier-stage, simpler escrow pattern Use case: Peer-to-peer goods trade with immediate payment-on-delivery escrow
- Next.js 13+ (App Router)
- Wallet: Freighter API (
@stellar/freighter-api) - State: React Context (WalletContext, OrderContext)
- Features:
- Product listing and search
- Order creation and tracking
- Escrow state transitions (confirm/refund/dispute)
- Notifications and real-time updates via WebSocket
- Key files:
src/app/(root)/orders/— order detail and managementsrc/components/— reusable UI componentssrc/services/stellar/— contract interaction, transaction signingsrc/context/— global state (wallet, orders)
- Express.js
- Prisma ORM with PostgreSQL
- Services:
- Order and product management (REST API)
- WebSocket server for real-time notifications
- Event indexing from Stellar ledger (via Soroban RPC)
- Contract watcher for escrow state changes
- Key files:
src/routes/— REST API endpoints (orders, products, auth)src/services/contractWatcher.ts— polls RPC for escrow eventssrc/services/wsManager.ts— WebSocket client/subscription managementsrc/controllers/— business logic for orders, products
Contracts used: contracts/escrow/ (direct payment escrow)
Status: Current development focus (Stellar Wave bounty program) Use case: Campaign-based crowdfunding for agricultural production (investors lock funds, farmers execute production, investors claim returns)
- Next.js 14+ (App Router)
- Wallet: Freighter API (same pattern as root client)
- State: React Context + custom hooks
- Features:
- Campaign creation (by farmers)
- Campaign browsing and details
- Investment flow (XDR building, transaction signing, indexing polls)
- Investor dashboards and return claims
- Real-time campaign status updates
- Key files:
src/app/campaigns/— campaign listing and detailssrc/app/invest/— investment flowsrc/lib/contractService.ts— builds invest XDR, interacts with production_escrow contractsrc/lib/signTransaction.ts— signs and submits transactionssrc/hooks/— custom React hooks (useInvest, useCampaign, etc.)
- Express.js
- Prisma ORM with PostgreSQL
- Services:
- Campaign and investment REST API
- WebSocket for real-time campaign/investment updates
- Soroban event watcher (polls RPC for production_escrow events)
- Image upload endpoint for campaign photos
- Key files:
src/routes/— REST API for campaigns, investments, authsrc/services/contractWatcher.ts— indexes production_escrow events (campaign.created, campaign.invested)src/services/wsManager.ts— broadcasts Soroban events to WebSocket clientssrc/controllers/campaignController.ts— campaign business logic
Contracts used:
agro-production/contract/production_escrow/— main crowdfunding escrowagro-production/contract/registry/— campaign/farmer registrationagro-production/contract/investment_basket/— investor pool managementagro-production/contract/governance/— DAO/governance features (future)
All contracts are written in Rust for Soroban (Stellar's smart contract platform).
- Purpose: Direct payment escrow for root marketplace (peer-to-peer trade)
- Events:
order.created— buyer initiates escroworder.confirmed— buyer receives goods and releases paymentorder.disputed— buyer/seller disputeorder.refunded— payment returned to buyer
- Consumed by:
server/(contract watcher),client/(order management)
- Purpose: Weather-based parametric insurance for farmers (complementary feature)
- Status: Standalone; future integration planned
- Consumed by: Not yet integrated into main app flows
- Purpose: Campaign-based escrow for crowdfunded agricultural production
- Key interactions:
create_campaign()— farmer initiates campaign (target amount, deadline)invest()— investor locks funds in campaignsettle_campaign()— campaign settles when deadline passesclaim_returns()— investor claims proportional returns from campaign results
- Events:
campaign.created— campaign initializedcampaign.invested— investor depositscampaign.settled— campaign reached deadlinecampaign.claimed— investor withdrew returns
- Consumed by:
agro-production/server/(watcher),agro-production/client/(invest flow)
- Purpose: Farmer/investor identity and KYC registration on-chain
- Key interactions:
register_farmer()— on-board farmer with identityregister_investor()— on-board investorget_farmer()— look up farmer details
- Consumed by:
agro-production/server/(campaign creation validation),agro-production/client/(farmer onboarding)
- Purpose: Manages investor fund pooling and returns distribution
- Key interactions:
deposit()— investor adds funds to pooldistribute()— distribute returns proportionally to investors
- Status: Used by production_escrow for multi-investor campaigns
- Consumed by:
production_escrow/(internally)
- Purpose: DAO-style governance for platform decisions (future feature)
- Status: Under development; not yet integrated into main flows
- Planned interactions:
propose()— propose platform changesvote()— vote on proposals
- Consumed by: Planned for future releases
Client Server Stellar Ledger
│ │ │
├─ User creates order ──→ REST POST /orders │
│ ├─ Save to DB │
│ └─ Broadcast WS ├─ Contract initialized
│ │
├─ User signs escrow XDR ──→ POST /orders/:id/confirm
│ and submits to Stellar ├─ Submit to ledger ──→ Escrow locked
│ └─ Broadcast WS
│
├─ Buyer waits for ────────→ Contract watcher polls RPC
│ delivery ├─ Detects escrow confirmation
│ ├─ Updates DB + broadcasts WS
└─ User confirms/refunds ──→ POST /orders/:id/action
and signs XDR ├─ Submit to Stellar ──→ Funds released
└─ Broadcast WS
Client Server Stellar Ledger
│ │ │
├─ User creates campaign ──→ POST /campaigns │
│ (farmer) ├─ Save to DB ├─ production_escrow initialized
│ └─ Broadcast WS │
│
├─ Investor browses campaigns ────→ GET /campaigns │
│ ├─ Query DB │
│ └─ Return list │
│
├─ Investor reviews campaign ──→ GET /campaigns/:id
│ └─ Return details
│
├─ contractService.buildInvest() ──→ (local to client)
│ (builds XDR against mock RPC)
│
├─ User signs invest XDR ──→ POST /campaigns/:id/invest
│ and submits to Stellar ├─ Submit to ledger ──→ Funds locked in pool
│ └─ Broadcast WS
│
│ (campaign lifecycle)
└─ After deadline, ────────→ Contract watcher detects
investor claims returns settlement + auto-broadcasts
├─ POST /campaigns/:id/claim_returns
├─ Submit to ledger ──→ Returns released
└─ Broadcast WS
Both apps follow the same pattern:
- XDR Building — Client builds transaction (sometimes with mock RPC for testing)
- Signing — User signs with Freighter wallet
- Submission — Send to Stellar network
- Indexing Polling — Server polls Soroban RPC for confirmation
- DB Update & Broadcast — Once indexed, update DB and notify WebSocket clients
- WebSocket server broadcasts events from
contract watcherto connected clients - Events are keyed by wallet address (e.g.,
farmer:0x...,investor:0x...) - Clients subscribe to wallet-specific channels after authentication
Both apps use classifyError() utility to categorize contract errors:
- User errors (e.g., insufficient funds) → 400 Bad Request
- Contract logic (e.g., CampaignNotSettled) → 422 Unprocessable Entity
- Network errors → 503 Service Unavailable
- Unexpected errors → 500 Internal Server Error
- Production escrow campaigns (
agro-production/) — MVP for agricultural crowdfunding - Critical issues: wallet auth, contract integration, error handling, observability
- Weather insurance integration (
contracts/weather-insurance/) - Governance features (
agro-production/contract/governance/) - Root marketplace enhancements
client/andserver/(root marketplace) — production-ready but not under active development for Stellar Wave
NEXT_PUBLIC_SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
NEXT_PUBLIC_NETWORK_PASSPHRASE="Test SDF Network ; September 2015"
NEXT_PUBLIC_CONTRACT_ID=<address> # agro-production/client only
DATABASE_URL=postgresql://...
SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
CONTRACT_ID=<address>
RUN_CONTRACT_WATCHER=true
PORT=3001
-
Understand the split:
- For campaign/production features: Work in
agro-production/ - For marketplace features: Work in root
client/andserver/ - For shared contracts: Check which app(s) consume it
- For campaign/production features: Work in
-
Pick an area:
- Backend:
agro-production/server/(contract watcher, API routes, WebSocket) - Frontend:
agro-production/client/(investment flow, campaign pages) - Contracts:
agro-production/contract/(Rust/Soroban)
- Backend:
-
Run locally:
- See
agro-production/README.mdfor E2E test setup - See
client/README.mdandserver/README.mdin each directory
- See
-
File issues:
- Use GitHub Issues with appropriate labels (
area:frontend,area:backend,type:bug, etc.) - Reference this document if explaining architectural decisions
- Use GitHub Issues with appropriate labels (
- Repo structure: See this ARCHITECTURE.md
- API endpoints: See
server/API.mdoragro-production/server/API.md - Contract interfaces: See Rust crate READMEs in
contract/andagro-production/contract/ - Deployment: Check CI workflows in
.github/workflows/