Skip to content

Repository files navigation

SRIMS Backend

This is the backend for my final year project: Design and Implementation of a Smart Remote Inventory Management System Using Computer Vision and Machine Learning. The project targets small retail businesses in Nigeria (the case study is an SME outlet in Abuja) where stock counts are still done by hand on paper or in spreadsheets, and a manager who isn't physically in the store has no way to know what's on the shelf.

Instead of barcodes or RFID tags which both need machine-readable labels on every item the system uses a phone camera. The mobile app snaps a shelf, sends the photo to OpenAI's vision API to recognise products from how they look, and posts the detected counts here. This API is everything server-side: accounts and roles, stores/warehouses, the product catalogue, inventory state and history, scan ingestion, low-stock alerts, and a simple demand model that forecasts when an item will run out.

The mobile app (including the detection step) lives in its own repo; this one is just the Go API. The backend doesn't care how detections are produced it just takes a class id, a count, and a confidence per product so the detector could be swapped for an on-device model without touching this code.

How a scan becomes inventory

  1. Staff point the app at a shelf and take a photo. The app sends it to OpenAI's vision API, which returns a list of detections: a class id, a count, and a confidence score per product.
  2. The app POSTs that list to /scans. Each ml_class_id maps to an item in the catalogue, and the inventory row for that (warehouse, item) pair is updated inside a Mongo transaction, with a history record per change.
  3. After the transaction commits, alerts are re-evaluated (low stock / out of stock, transition-based so you don't get spammed on every scan) and events go out over WebSocket and FCM push so dashboards update live.
  4. The predictions endpoint uses a 14-day moving average over consumption to estimate daily demand and days-to-stockout per item, which is what turns restocking from reactive into "reorder before it runs out".

Prerequisites

  • Go 1.25+
  • Docker (for local MongoDB)

Setup

git clone <repo-url> srims-backend
cd srims-backend
cp .env.example .env

make up      # start MongoDB (single-node replica set)
make tidy    # fetch Go deps + populate go.sum
make run     # start the API on :8080

Collections and indexes are created automatically on startup (idempotent).

curl localhost:8080/healthz   # {"status":"ok","db":"ok"}

Project structure

.
├── Dockerfile                # multi-stage, ships the api binary
├── docker-compose.yml        # local MongoDB (replica set)
├── render.yaml               # Render deploy manifest (uses external Mongo Atlas)
├── Makefile                  # up | down | run | test | tidy | docker-build
├── .github/workflows/ci.yml  # lint + test + docker-build on push/PR
├── cmd/api/                 # API entrypoint (thin shell over internal/app)
├── internal/config/         # env-driven Config + Load()
└── internal/
    ├── app/                 # Build() — wires everything; reused by main and tests
    ├── auth/                # JWT + bcrypt + register/login/refresh/me
    ├── warehouses/          # CRUD + RBAC scoping
    ├── items/               # CRUD + uniqueness on sku/ml_class_id
    ├── inventory/           # rows, history, manual adjust (txn-safe)
    ├── scans/               # the scan→inventory pipeline (txn-safe + alerts + ws)
    ├── alerts/              # transition-based alert evaluator + dismiss
    ├── predictions/         # 14-day moving-average demand model
    ├── analytics/           # KPI overview + per-item trend
    ├── ws/                  # gorilla/websocket hub + client + auth
    ├── httpx/               # error envelope + sentinel errors
    └── db/                  # Mongo connect + collection/index bootstrap

API overview

Group Endpoints Auth
/auth POST register/login/refresh/logout, GET me, PUT users/:id/role (admin) public + bearer
/warehouses GET list, POST create, GET :id bearer (RBAC)
/items GET list, POST create, PUT :id, DELETE :id bearer (RBAC)
/inventory GET ?warehouse_id=, GET :id/history, PUT :id (manual adjust) bearer
/scans POST submit, GET ?warehouse_id=, GET :id bearer
/alerts GET ?active=&warehouse_id=, PUT :id/dismiss bearer (admin/mgr)
/predictions GET dashboard?warehouse_id= bearer
/analytics GET overview?warehouse_id=, GET items/:id/trend?warehouse_id=&days= bearer
/ws?token= WebSocket: subscribe/unsubscribe to warehouse events JWT in query

A scan submission looks like this — it's exactly what the detector on the phone produces:

POST /scans
{
  "warehouse_id": "",
  "detected_items": [
    { "ml_class_id": "coke_500ml",   "count": 12, "confidence": 0.91 },
    { "ml_class_id": "indomie_pack", "count": 8,  "confidence": 0.85 }
  ]
}

Deployment

Render (one-click)

  1. Set up a free MongoDB Atlas cluster, copy the connection string.
  2. New Blueprint in Render, point at this repo's render.yaml.
  3. Set MONGODB_URI in the dashboard (it's marked sync: false).
  4. Deploy. Health check: /healthz.

Docker (any host)

docker build -t srims-backend .
docker run -p 8080:8080 \
  -e MONGODB_URI='mongodb+srv://...' \
  -e JWT_SECRET='supersecret' \
  -e ENV=production \
  srims-backend

Env var reference

Var Required Default Notes
PORT 8080
MONGODB_URI Replica-set URI (Atlas or local rs0)
MONGO_DATABASE inventory
JWT_SECRET ≥32 bytes outside development
JWT_ACCESS_TTL 15m
JWT_REFRESH_TTL 168h (= 7 days); refresh tokens rotate on use
LOG_LEVEL info trace/debug/info/warn/error
ENV development
ALLOWED_ORIGINS — (allow all) Comma-separated Origins for websocket upgrades
TRUSTED_PROXIES — (use RemoteAddr) Comma-separated proxy CIDRs whose X-Forwarded-For is trusted
FIREBASE_CREDENTIALS_JSON — (pushes no-op) FCM service-account: file path or raw JSON

Testing

make test

Make targets

Target What it does
make up Start MongoDB in Docker
make down Stop MongoDB
make logs Tail MongoDB container logs
make run Run the API locally
make test Run the Go test suite
make tidy go mod tidy
make mongo-shell Open mongosh against the local instance
make docker-build Build the production Docker image

Data model

No SQL migrations — Mongo is schemaless. On startup, internal/db.Init ensures these collections exist with the right indexes:

Collection Notable indexes
users unique email
warehouses manager_id
items unique sku, unique ml_class_id
inventory unique compound (warehouse_id, item_id)
inventory_transactions (inventory_id, created_at desc), sparse scan_id
scans (warehouse_id, scanned_at desc), (user_id, scanned_at desc)
predictions (item_id, predicted_at desc)
alerts (status, created_at desc)
refresh_tokens TTL on expires_at, user_id

_id on every document is a UUID v4 string (set by the application, not Mongo).

Context

Built as part of my final year project on inventory management for Nigerian SMEs, where record accuracy without automated tracking typically sits in the 60–70% range and restocking is reactive rather than planned. The full write-up covers the motivation, the computer-vision approach, and the evaluation against manual counting at the case-study outlet.

About

Smart inventory system for small retail stores count shelf stock with a phone camera instead of barcodes.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages