https://github.com/muringi21/kijani
Full-stack leather traceability platform: Fastify REST API + offline-first Expo mobile app
https://github.com/muringi21/kijani
expo fastify monorepo react-native typescript
Last synced: 11 days ago
JSON representation
Full-stack leather traceability platform: Fastify REST API + offline-first Expo mobile app
- Host: GitHub
- URL: https://github.com/muringi21/kijani
- Owner: muringi21
- Created: 2026-01-13T21:46:50.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-06-02T20:02:11.000Z (20 days ago)
- Last Synced: 2026-06-02T21:28:27.406Z (20 days ago)
- Topics: expo, fastify, monorepo, react-native, typescript
- Language: JavaScript
- Homepage:
- Size: 19.5 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Kijani Traceability
Kijani is a leather supply chain traceability platform I've been building for the Kenyan market. Field agents use the mobile app to scan QR-tagged hides, log weight/grade/species, and batch-upload records to the API — even offline. Tanneries can then look up any hide's provenance by scanning its QR code.
This repo is the MVP monorepo: a Fastify REST API backed by SQLite, and an Expo React Native agent app.
## Status
Active development — core batch upload and offline queue are working. Next: multi-tenant auth and Postgres migration.
## Packages
| Package | Tech | Purpose |
|---|---|---|
| `apps/api` | Fastify + SQLite | REST API — batch upload, list, single-batch lookup |
| `apps/mobile` | Expo React Native | Agent app — QR scan, offline queue, GPS, batched uploads |
| `packages/shared` | Zod | Shared `BatchSchema` used by both API and mobile |
## Prerequisites
- Node.js 18+
- npm 9+ (workspaces)
- Expo Go on your phone (for mobile dev), or an iOS/Android simulator
## Quick Start
```bash
# 1. Install all workspaces
npm install
# 2. Copy & edit the API env file
cp apps/api/.env.example apps/api/.env
# 3. Start the API (Terminal 1)
npm run dev:api
# 4. Start Expo (Terminal 2)
npm run dev:mobile
```
**Physical device?** Edit `apps/mobile/src/config.js` and set `API_BASE_URL` to your laptop's local IP (e.g. `http://192.168.1.50:3333`).
## API Endpoints
All endpoints except `/health` require the `x-api-key` header.
| Method | Path | Description |
|---|---|---|
| GET | `/health` | Liveness check (no auth) |
| POST | `/v1/batches` | Upload one batch or array of batches |
| GET | `/v1/batches?limit=50` | List recent batches |
| GET | `/v1/batches/:id` | Single batch + hides (QR provenance lookup) |
**Example — upload a batch:**
```bash
curl -X POST http://localhost:3333/v1/batches \
-H "Content-Type: application/json" \
-H "x-api-key: dev-key-change-me" \
-d '{
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenantId": "demo-tenant",
"agentId": "agent-01",
"productType": "hides",
"hides": [
{ "qrCode": "KJ-001", "weight": 12.5, "grade": "A", "species": "cattle" }
],
"capturedAt": "2026-03-19T10:00:00.000Z"
}'
```
## Mobile App Screens
- **Main (Agent)** — Scan QR tags, enter weight/grade/species, build a batch, save offline, upload when connected
- **Scan** — Camera-based QR/barcode scanner (capture mode for agents, lookup mode for tanneries)
- **Batch Detail** — Provenance view: all hide records, GPS coords, timestamps
## Architecture Notes
- **SQLite** (`better-sqlite3`): zero-config for MVP. Plan to migrate to Postgres/Supabase before scaling to multiple tenants
- **API key auth**: simple `x-api-key` header for the pilot. Will swap to JWT when multi-tenant support is added
- **Offline-first**: batches saved to AsyncStorage immediately on the device. Auto-flush every 5 min + manual "Upload Now"
- **Partial-success uploads**: if some batches in an array fail validation, valid ones still save. Failed indices are returned so the client retries only those
- **Duplicate protection**: batch IDs are UUIDs generated on the phone; the DB rejects duplicate inserts gracefully
## Project Structure
kijani/
├── package.json
├── apps/
│ ├── api/
│ │ ├── server.js # Fastify routes + auth hook
│ │ ├── db.js # SQLite schema + queries
│ │ ├── .env.example
│ │ └── package.json
│ └── mobile/
│ ├── App.js
│ ├── index.js
│ ├── app.json
│ ├── metro.config.js
│ └── src/
│ ├── config.js
│ ├── lib/
│ │ ├── queue.js
│ │ └── api.js
│ └── screens/
│ ├── MainScreen.js
│ ├── ScanScreen.js
│ └── BatchDetailScreen.js
└── packages/
└── shared/
└── src/index.js