Skip to content

Software Requirements & Specifications

This document specifies the software requirements, dependencies, and technical specifications for developing and deploying the Dharini platform.

ComponentVersionNotes
Node.js22.x LTSRequired for NestJS runtime
PostgreSQL16.xWith PostGIS 3.4 extension
RedisAny current release (Compose uses the unpinned redis:alpine image)Job queue (BullMQ) and cache
ComponentVersionNotes
Node.js22.x LTSRequired for Next.js
Browser SupportChrome 64+, Edge 79+, Firefox 67+, Safari 12+The browsers Next.js 15 builds for (its default target; newer versions of these are fine)
ComponentVersionNotes
Flutter SDK3.29.0 (pinned in mobile/.fvmrc; pubspec.yaml allows ≥3.16.0)Cross-platform framework
Dart SDK^3.5.4Language runtime
AndroidAPI 23+ (Android 6.0)Minimum supported version (minSdk)
iOS12.0+Minimum supported version (planned)

ToolVersionPurpose
Docker24.x+Container runtime
Docker Compose2.x+Multi-container orchestration
Git2.x+Version control
Node.js22.x LTSBackend and web development
Flutter SDK3.29.0 (via fvm)Mobile development
Android StudioLatestAndroid SDK and emulator
VS Code / IDELatestRecommended IDE
Terminal window
# Clone repository
git clone https://github.com/dsih-artpark/dharini.git
cd dharini
# Copy environment template
cp .env.example .env
# Start development services
docker compose --profile development up -d --build

In development mode the backend creates the schema with TypeORM synchronize, so there is no migration step. Outside development, the backend runs pending migrations and the seeder on startup.

ServicePortURL
Backend API4000http://localhost:4000
Web Frontend3000http://localhost:3000
Mobile web (Flutter web build)3002http://localhost:3002
PostgreSQL5432localhost:5432
Redis6379localhost:6379
pgAdmin5050http://localhost:5050
Garage (optional, garage profile)3900-3903S3 API on 3900, other ports for RPC, web and admin

ComponentSpecificationNotes
Compute2 vCPU, 4GB RAM minimumt3.medium or equivalent
DatabasePostgreSQL 16 with PostGISAWS RDS recommended
Storage50GB+ SSDFor database and logs
Object StorageS3-compatible (AWS S3 or self-hosted Garage)For media uploads and sequencing files
SSLTLS 1.2+Required for HTTPS
ServicePurpose
EC2Application hosting
RDSManaged PostgreSQL
S3File storage (photos, reports)
Route 53DNS management
ACMSSL certificates
PortProtocolPurpose
22TCPSSH access (restricted)
80TCPHTTP (redirects to HTTPS)
443TCPHTTPS
5432TCPPostgreSQL (internal only)

Core Framework:

  • NestJS 11.x
  • TypeScript 5.x
  • TypeORM 0.3.x

Key Dependencies:

PackageVersionPurpose
@nestjs/passport11.xAuthentication
@nestjs/jwt11.xJWT tokens
@nestjs/bullmq11.xJob queue
bullmq5.xQueue engine
@casl/ability6.xAuthorization (RBAC)
@aws-sdk/client-s33.xS3 file uploads
typeorm0.3.xDatabase ORM
pg8.xPostgreSQL driver
nodemailer7.xEmail sending (SMTP)
@nestjs/throttler6.xRate limiting on auth routes
@nestjs/schedule6.xScheduled jobs
helmet8.xSecurity headers
ioredis5.xRedis client (cache)
twilio5.xSMS/OTP

Core Framework:

  • Next.js 15.x (App Router)
  • React 18.x
  • TypeScript 5.x

Key Dependencies:

PackageVersionPurpose
jotai2.xState management
axios1.xHTTP client
leaflet1.9.xMaps
react-leaflet4.xReact map components
recharts2.xCharts/visualization
tailwindcss3.xStyling
next15.4.xFramework

Core Framework:

  • Flutter 3.29.0
  • Dart ^3.5.4

Key Dependencies:

PackageVersionPurpose
flutter_bloc8.xState management
flutter_hooks0.20.xHooks for widgets
fquery1.5.xData fetching/caching
hive2.xLocal database
dio5.xHTTP client
go_router14.xNavigation
flutter_map8.xMaps
geolocator13.xGPS location
mobile_scanner6.xQR/barcode scanning
sentry_flutter9.xError tracking

TableDescriptionKey Relations
usersUser accounts→ teams, roles
projectsSurveillance projects→ teams, sites, diseases
teamsTeam organization→ users, projects
rolesPermission definitions→ users (via user_roles)
sitesCollection locations→ projects, visits (PostGIS geometry)
visitsSite visit records→ sites, samples, users
samplesSample records→ visits, lab_tests, diseases
lab_testsTest results→ samples, diseases
diseasesDisease definitions→ projects, samples
sample_typesSample type catalog→ samples
mediaUploaded files→ S3 references
workspacesTenant organizations→ projects, members
invitesPending invitations→ users, roles
sequencing_*Sequencing submissions, jobs and pipeline webhook deliveries→ samples
bio_*GeoLens reference layers (water boundaries, wetlands, poultry farms, cattle markets)PostGIS geometry

The list above is a summary. See Database Setup for details.

CREATE EXTENSION IF NOT EXISTS postgis;
CREATE EXTENSION IF NOT EXISTS postgis_topology;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS pg_trgm;

pg_trgm is created by a migration and is used for fast substring search. It is available in the standard PostgreSQL contrib package and in the postgis/postgis image.


  • Method: JWT Bearer tokens
  • Token Expiry: 7 days (fixed in code, not configurable). The web app’s cookie lasts one day longer than the token, so the app can tell an expired session from a missing one.
  • OTP Delivery: SMS via Twilio, or email via SMTP
  • Format: OpenAPI 3.0 (Swagger)
  • Interactive UI: /docs on the backend (/api/docs behind the Nginx layout)
  • Published spec: API Reference, rendered from /openapi/openapi.json. The file is committed at docs/public/openapi/openapi.json and regenerated with npm run openapi:generate in backend/
  • Generated Client: es_client package for mobile

The backend limits the auth and OTP routes (login, OTP verification and resend, signup) to 10 requests per 60 seconds per IP address. Other routes have no backend rate limit. If you need one, set it in the reverse proxy (see Nginx Configuration).


  • OTP-based login (SMS/email)
  • JWT tokens signed with HS256 (JWT_SECRET), valid for 7 days
  • httpOnly, SameSite=Lax cookies for web sessions, lasting as long as the token plus one day
  • No token refresh: users sign in again when the token expires
  • Role-based access control (CASL)
  • Scope hierarchy: System → Workspace → Project → Team
  • A global JWT guard covers every route; routes opt out with @Public()
  • CASL policy guards on the controllers that expose project data
  • Security headers (helmet) and a CORS allowlist (CORS_ORIGINS)
  • Serve every app over HTTPS. Nginx Configuration shows the proxy layout.
  • Encryption at rest is a setting of the services you use, not of Dharini. Enable storage encryption on the PostgreSQL database (for example RDS) and on the S3 bucket. Production Setup lists these steps.

  • The mobile app stores its data in a local Hive database
  • Data syncs with the backend in the background on a timer, and can also be synced by hand
  • Photos are compressed on the phone before upload

  • Service: Sentry
  • Coverage: Mobile app only
  • Data sent: Stack traces, device details and the shape of failed requests, not their values. See Error reporting.
EndpointPurpose
/healthBackend liveness
/docs (/api/docs behind the Nginx layout)API availability
  • The backend writes plain-text logs to standard output (console.log and the NestJS logger); there is no structured JSON logging
  • Retention is whatever your container runtime or log collector provides

See Environment Variables Reference for the complete list of configuration options.

Required variables depend on which features you use (for example, CORS_ORIGINS is mandatory outside development, and sequencing needs the PIPELINE_* and WEBHOOK_SECRET keys). The reference lists which variables are required and which are optional.


Docker Compose supports multiple deployment profiles:

ProfileServicesUse Case
developmentPostgres, Redis, pgAdmin, backend, webLocal development
stagingRedis, pgAdmin, backend, webStaging
productionRedis, backend, webProduction
bundled-dbThe bundled PostgreSQLAdd-on; deploy.sh adds it when DB_HOST=postgres
garageGarage (self-hosted S3-compatible storage)Add-on, combine with another profile
mobile-webFlutter web build (port 3002)Add-on; built per deployment, not published

deploy.sh starts the bundled Postgres only when DB_HOST in .env is postgres. To use an external database such as RDS, set DB_HOST to its address and the other DB_* variables to match; the bundled container is then not started. Add --profile garage to run Garage as the object store.

On a server, use ./deploy.sh staging or ./deploy.sh production. It pulls the backend and web images from dsihartpark on Docker Hub (published when a pull request is merged into staging or production; override with IMAGE_TAG and IMAGE_REGISTRY) and starts the profile. See Production Setup.

Terminal window
# Development (builds from the checkout)
docker compose --profile development up -d --build
# Production or staging server
./deploy.sh production

ComponentCurrent Version
Backend API0.1.0
Web Frontend0.1.0
Mobile App0.2.7
Database SchemaMigration-based (run the latest migration)

Document generated from the staging branch. Last updated: October 2026.