AI-powered crop insurance & claim management platform for farmers and insurers.
FarmClaim is a full-stack application that digitizes the entire crop-insurance lifecycle — from registration and policy purchase to AI-assisted claim verification and payout. Farmers file claims with photos of damaged crops; the backend automatically pulls historical weather data for the incident day and runs a Google Gemini vision model to estimate the damage; and admins review the evidence, approve/reject claims, and process payments — all with real-time notifications and a full audit trail.
Live deployment: https://farmclaim.naheel.me
- Overview
- Key Features
- Tech Stack
- Architecture
- Project Structure
- Getting Started
- Environment Variables
- Usage
- Screenshots
- API Documentation
- Testing
- Deployment
- Technical Highlights
- What I Learned
- Future Improvements
- Author
Crop insurance claims are traditionally handled on paper or through slow, manual workflows. Verifying that damage actually occurred — and its severity — usually requires an in-person inspector, which means weeks of delay for farmers and high operating costs for insurers.
FarmClaim solves this by providing:
- Farmers a self-serve portal to register, geotag their farms on a map, browse insurance plans, buy and manage policies, pay premiums online, and file claims with damage photos.
- Insurers/admins a review dashboard to verify claims using automated evidence: historical weather at the farm's coordinates on the incident date, plus an AI damage assessment (estimated damage percentage, description, and confidence) generated from the uploaded photos.
This replaces manual inspection with reproducible, data-backed verification, making the process faster, cheaper, and more transparent for both sides.
Non-technical summary: think of it as an online insurance app for farmers — where claims are checked automatically using satellite-weather data and computer vision instead of a human inspector visiting the farm.
- Role-based platform — separate Farmer and Admin experiences with claim, farm, policy, and user workflows.
- Secure authentication flow — email OTP verification, JWT access tokens with rotating refresh tokens stored in HttpOnly cookies, password reset, and secure email change.
- Farm management with map picker — farmers geotag their farms using an interactive Leaflet map; coordinates feed the weather verification pipeline.
- Full policy lifecycle — browse admin-managed insurance plans, apply for policies (pending approval), renew, cancel, and expire — including installment-based premium schedules.
- Online payment processing — Razorpay checkout for one-time or installment premiums, with server-side signature-verified webhooks.
- Automated claim verification:
- Weather analysis — fetches historical weather (Open-Meteo) for the farm's location on the incident date.
- AI damage analysis — Google Gemini Vision estimates damage percentage, description, and confidence from claim photos (Cloudinary-hosted).
- Admin claim pipeline — review → approve/reject → mark paid, with a rich dashboard (KPIs, charts, trends, top farms).
- Admin controls — approve/reject/cancel policies, suspend/block/activate users, and browse a full audit log of sensitive actions.
- Real-time notifications — SignalR pushes claim status, weather, and AI-analysis updates to farmers instantly.
- Background job engine — Hangfire processes weather/AI jobs with retries and runs recurring maintenance (policy expiry, token cleanup, expiry reminders, overdue-installment cancellation).
- Engineering hardening — rate limiting, structured error middleware, health endpoints (liveness/readiness/DB), audit trail via EF Core interceptor, and Polly-based resilience on external APIs.
- CI/CD & containerized deployment — GitHub Actions builds Docker images to GHCR and deploys to Azure Container Apps; a docker-compose file provides a self-hostable stack (SQL Server, reverse proxy, auto-HTTPS).
| Technology | Purpose |
|---|---|
| Next.js 16 (App Router) · React 19 · TypeScript | Application framework & UI |
| Tailwind CSS 4 · shadcn/ui · Radix UI | Styling & accessible component primitives |
| Zustand | Client-side state & app store |
| TanStack Query · TanStack Table | Server-state caching & data tables |
| React Hook Form · Zod | Form state & schema validation |
| Leaflet / react-leaflet | Interactive farm location picker |
| Recharts | Admin dashboard charts |
| SignalR (@microsoft/signalr) | Real-time notification client |
| Technology | Purpose |
|---|---|
| ASP.NET Core 8 Web API (C#) | REST API |
| Clean Architecture (Domain / Application / Infrastructure / API) | Layered, testable design |
| MediatR · CQRS | Command/query separation with pipeline behaviors |
| FluentValidation | Request validation (runs inside the MediatR pipeline) |
| EF Core 8 · SQL Server 2022 | ORM + 24 schema migrations |
| Hangfire | Background jobs & scheduling |
| SignalR | Real-time notifications |
| Swashbuckle (Swagger/OpenAPI) | Interactive API docs |
| Polly | Retry/resilience for external HTTP calls |
| Custom middleware | Global exception handling & rate limiting |
| Service | Used for |
|---|---|
Google Gemini (Vision, gemini-2.0-flash) |
AI crop-damage assessment from claim photos |
| Open-Meteo | Historical weather lookup at incident date & location |
| Razorpay | Premium payments + signed webhooks |
| Cloudinary | Claim image storage/CDN |
| ElasticEmail (SMTP) | Transactional email (welcome, OTP, reset, notifications) |
| Technology | Purpose |
|---|---|
| Docker · docker-compose | Multi-stage images for API & frontend; full local stack |
| GitHub Actions | CI/CD to Azure Container Apps via GHCR |
| Azure Container Apps | Hosting backend & frontend |
| Nginx proxy + acme-companion + DuckDNS | Self-host template with automated HTTPS |
| npm / Bun · ESLint (flat config) | Frontend tooling |
The backend follows Clean Architecture with four projects:
FarmClaim.API HTTP layer: controllers, middleware, SignalR hub
FarmClaim.Application CQRS features (commands/queries/validators), business rules
FarmClaim.Domain Entities & enums (no dependencies)
FarmClaim.Infrastructure EF Core, external service implementations, jobs, email
Requests flow in through the API layer, are validated by FluentValidation pipeline behaviors inside MediatR, executed against ApplicationDbContext, and external side-effects (Emails, AI, payments) are dispatched through abstraction interfaces implemented in Infrastructure.
flowchart LR
subgraph Client
F[Next.js Frontend<br/>Zustand + React Query + SignalR]
end
subgraph API["ASP.NET Core 8 API (FarmClaim.API)"]
C[Controllers<br/>api/v1/*]
M[MediatR CQRS +<br/>Validation/Logging behaviors]
H[SignalR Hub]
MW[Middleware:<br/>Exceptions · Rate Limiting · JWT]
end
subgraph App["Application Layer"]
FV[FluentValidation Validators]
SE[Services:<br/>Policy Creation]
IF[Interfaces: Email, Payment,<br/>AI, Weather, File Storage]
end
subgraph Infra["Infrastructure Layer"]
DB[(SQL Server<br/>EF Core · Hangfire tables)]
AU[AUDIT Tracker<br/>SaveChanges Interceptor]
HJ[Hangfire Jobs<br/>Weather · AI · Email · Maintenance]
RAZ[Razorpay]
CL[Cloudinary]
GE[Gemini Vision]
WM[Open-Meteo]
EM[ElasticEmail]
end
F -->|JSON / Bearer JWT / cookies| C
F <-->|SignalR notifications| H
C --> M --> SE
C --> IF
M --> FV
SE --> DB
HJ --> GE
HJ --> WM
HJ --> EM
IF --> RAZ
IF --> CL
RAZ -->|signed webhook| C
How a claim is processed (end to end):
- A farmer files a claim (incident type, date, description) on an active policy and uploads damage photos → stored in Cloudinary.
- The API enqueues two Hangfire background jobs:
- Weather — fetches Open-Meteo historical data for the farm's coordinates on the incident date.
- AI — downloads the Cloudinary images (host-allowlisted to prevent SSRF) and sends them to Gemini Vision, returning estimated damage %, description, and confidence.
- Results are persisted on the claim; SignalR pushes real-time status updates to the farmer.
- An admin reviews the claim in the dashboard (with the weather & AI evidence), then approves/rejects it and marks it paid.
- Premiums are collected via Razorpay; webhooks are signature-verified before payment state changes.
- Emails (welcome, OTP, password reset, policy status, claim paid) are queued via Hangfire and sent through ElasticEmail.
FarmClaim/
├── .github/workflows/ # CI/CD: build → GHCR → Azure Container Apps
├── docker-compose.yml # Full self-host stack (nginx + certs + app + SQL)
│
├── FarmClaim/ # .NET backend (slnx solution)
│ ├── FarmClaim.API/
│ │ ├── Controllers/ # api/v1/* (Auth, Claims, Policies, Payments, Admin…)
│ │ ├── Hubs/ # SignalR NotificationHub
│ │ ├── Middleware/ # Exception handling, rate limiting, Hangfire auth
│ │ ├── Program.cs # DI, JWT, Hangfire, MediatR, CORS, health checks
│ │ ├── appsettings.json # Config template (env-secrets kept out of VCS)
│ │ └── Dockerfile
│ ├── FarmClaim.Application/ # CQRS features + FluentValidation + behaviors
│ │ └── Features/
│ │ ├── Auth/ · Claims/ · Farms/ · Farmers/
│ │ ├── InsurancePlans/ · InsurancePolicies/ · Payments/
│ │ └── Admin/ · AuditLogs/ · Notifications/
│ ├── FarmClaim.Domain/ # Entities + enums
│ └── FarmClaim.Infrastructure/ # EF Core, migrations, jobs, email, integrations
│ ├── Data/ # ApplicationDbContext + audit interceptor
│ ├── Migrations/ # 24 EF Core schema migrations
│ ├── Jobs/ # Weather, AI, maintenance (Hangfire)
│ ├── Email/ # Razor templates + SMTP/ElasticEmail + queue
│ └── Services/ # Gemini, Weather, Razorpay, Cloudinary, JWT
│
└── farmclaim-frontend/ # Next.js 16 + React 19 + TypeScript
├── public/
└── src/
├── app/ # Root layout / routes
├── components/ # landing, auth, farmer, admin, layout, ui (shadcn)
└── lib/ # api client, store (Zustand), notifications, types
- .NET SDK 8
- A SQL Server instance (or SQL Server LocalDB included with Visual Studio)
- Node.js 20+ (Bun optionally used for installs) for the frontend
- Docker + Docker Compose if you want the full stack in one command
git clone https://github.com/naheel0/FarmClaim.git
cd FarmClaimcd FarmClaim/FarmClaim.API
# restore packages
dotnet restore
# (optional) apply EF Core migrations explicitly — otherwise the API applies
# pending migrations automatically when running with ASPNETCORE_ENVIRONMENT=Development
dotnet ef database update
# run with Swagger at http://localhost:5161/swagger
dotnet run --launch-profile httpSet the environment variables listed in Environment Variables (startup fails fast if the JWT secret is missing, too short, or a placeholder).
cd farmclaim-frontend
cp .env.example .env.local # set NEXT_PUBLIC_API_BASE_URL to your API
npm install # or: bun install
npm run dev # http://localhost:3000Make sure your API's
AllowedOriginsincludeshttp://localhost:3000(see the API CORS policy inProgram.cs).
Create a .env at the repo root with the values from Environment Variables, then:
docker compose up -d --buildThis starts SQL Server 2022, the API, the frontend, an nginx reverse proxy with automatic HTTPS, and (optionally) a DuckDNS updater.
| Task | Command |
|---|---|
| Run API (dev) | dotnet run --launch-profile http |
| Apply migrations | dotnet ef database update (from FarmClaim/FarmClaim.API) |
| Run frontend | npm run dev |
| Build frontend | npm run build |
| Lint frontend | npm run lint |
| Full stack (Docker) | docker compose up -d --build |
Sample .env file for the root of the repository (used by docker-compose.yml):
# ── SQL Server ──────────────────────────────
SA_PASSWORD=ChangeMe_StrongPassword_123!
# ── Security ────────────────────────────────
JWT_SECRET=change-me-to-a-random-string-of-at-least-32-chars
# ── AI Vision ───────────────────────────────
GEMINI_API_KEY=AIza...
GEMINI_MODEL=gemini-2.0-flash
# ── File storage ────────────────────────────
CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_API_KEY=your-api-key
CLOUDINARY_API_SECRET=your-api-secret
# ── Payments (Razorpay) ─────────────────────
RAZORPAY_KEY_ID=rzp_test_xxxxxxxx
RAZORPAY_KEY_SECRET=your-key-secret
RAZORPAY_WEBHOOK_SECRET=your-webhook-secret
RAZORPAY_DUMMY_MODE=false
# ── Email ───────────────────────────────────
EMAIL_PROVIDER=ElasticEmail # or Smtp
EMAIL_SMTP_HOST=smtp.elasticemail.com
EMAIL_SMTP_PORT=2525
EMAIL_SMTP_USER=your-sender@example.com
EMAIL_SMTP_PASSWORD=your-smtp-password
EMAIL_FROM=your-sender@example.com
EMAIL_DUMMY_MODE=false
# ── (Self-host) Dynamic DNS ─────────────────
DUCKDNS_TOKEN=your-duckdns-tokenNever commit real secrets. The frontend
.env.exampledocumentsNEXT_PUBLIC_RAZORPAY_KEY_ID(public key only) andNEXT_PUBLIC_API_BASE_URL. All server-side secrets live in the API configuration or environment variables.
Farmer workflow
- Register → verify your email with the OTP sent to your inbox.
- Add a farm → pick its location on the map and set the crop type.
- Buy insurance → browse active plans, apply for a policy, then pay the premium (or first installment) via Razorpay once an admin approves it.
- File a claim → select an incident type, date, and description; upload damage photos (up to 5 are AI-analyzed).
- Track progress → watch live updates over SignalR as weather data is fetched and the AI assesses the damage percentage.
Admin workflow
- Open the admin dashboard for an overview (users, policies, claims, premiums collected, claim trends).
- Approve/reject/cancel policies submitted by farmers.
- Review claims using the AI damage estimate and weather snapshot, then
approve(with amount) orreject.Payapproved claims. - Manage users — suspend or block accounts with a recorded reason.
- Audit log — inspect who changed what (with IP, HTTP metadata, old/new values).
Screenshots are not included in this repository yet. Replace the placeholders below with your own captures.
Interactive Swagger UI is served at /swagger in development. Base path: /api/v1.
| Method | Endpoint | Description | Auth |
|---|---|---|---|
| POST | /Auth/register |
Create an account (returns verification requirement) | – |
| POST | /Auth/verify-email |
Confirm email via OTP; issues JWT + refresh-token cookie | – |
| POST | /Auth/resend-otp |
Re-send verification OTP | – |
| POST | /Auth/login |
Sign in; returns access token, sets refresh cookie | – |
| POST | /Auth/refresh |
Rotate refresh token and issue new access token | cookie |
| POST | /Auth/logout |
Revoke refresh token and clear cookie | Bearer |
| POST | /Auth/forgot-password |
Send password-reset email | – |
| POST | /Auth/reset-password |
Reset password with token | – |
| POST | /Auth/change-email · /Auth/confirm-email-change |
Secure email change | Bearer / token |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
| GET/PUT | /Farmers/me |
Read / update own profile | Farmer |
| CRUD | /Farms |
Manage own farms | Farmer |
| GET | /InsurancePlans · /InsurancePlans/{id} |
Browse insurance plans | Farmer |
| CRUD | /Policies · /Policies/{id}/renew |
Manage own policies & renew | Farmer |
| CRUD | /Claims |
File, update, delete claims | Farmer |
| POST | /Claims/{id}/images · DELETE /Claims/{id}/images/{imageId} |
Upload/remove damage photos | Farmer |
| GET | /Claims/{id}/timeline |
Claim status history | Farmer |
| GET | /Weather/current?lat=&lon= |
Current weather snapshot | Farmer |
| GET | /Payments/policy/{policyId} |
Payment history for a policy | Farmer |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
| POST | /Payments/create-order/{policyId} |
Create a Razorpay order (one-time or installment) | Farmer |
| POST | /Payments/verify |
Verify a completed payment server-side | Farmer |
| POST | /Payments/webhook |
Razorpay-signed webhook → updates payment state | signature |
| GET | /config/razorpay-key |
Public Razorpay key for checkout | – |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
| GET | /Admin/Dashboard |
Aggregated KPIs and charts | Admin |
| GET | /Admin/Claims · /Admin/Claims/{id} |
List/detail claims (filters, search) | Admin |
| PUT | /Admin/Claims/{id}/review · .../approve · .../reject · .../pay |
Claim pipeline | Admin |
| POST | /Admin/Claims/{id}/reprocess |
Re-run weather/AI verification | Admin |
| GET | /Admin/Policies |
List policies | Admin |
| PUT | /Admin/Policies/{id}/approve · .../reject · .../cancel |
Policy moderation | Admin |
| CRUD | /Admin/Plans · .../{id}/activate · .../{id}/deactivate |
Manage insurance plans | Admin |
| GET | /Admin/Users · /Admin/Users/{id} |
List/detail users | Admin |
| PATCH | /Admin/Users/{id}/suspend · .../block · .../activate |
User moderation | Admin |
| GET | /Admin/AuditLogs · /Admin/AuditLogs/{id} |
Audit trail | Admin |
POST /api/v1/Claims
Authorization: Bearer <access-token>
Content-Type: application/json
{
"policyId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"incidentType": "Flood",
"incidentDate": "2026-07-24T00:00:00Z",
"description": "Heavy rain flooded 2 acres of rice field"
}{
"id": "f47ac10b-58cc-4372-a567-0e02b2c1d479",
"policyId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"incidentType": "Flood",
"status": "Pending",
"weatherStatus": "Pending",
"aiAnalysisStatus": "Pending"
}PUT /api/v1/Admin/Claims/{claimId}/approve
Authorization: Bearer <admin-access-token>
Content-Type: application/json
{ "approvedAmount": 15000, "adminNotes": "Weather + AI evidence verified" }No automated test suite is committed to this repository yet. The codebase is structured to make testing straightforward later (Clean Architecture layering, dependency-injected interfaces in FarmClaim.Application, and MediatR pipeline behaviors). Adding xUnit integration/unit tests against the Application layer is the top priority in Future Improvements — test coverage is not claimed here.
The repository ships with two deployment paths:
1. Cloud CI/CD (used for the live deployment)
A GitHub Actions workflow (.github/workflows/deploy.yml) runs on every push to main:
- Builds the backend and frontend as Docker images and pushes them to GHCR (
ghcr.io/naheel0/farmclaim-backend/farmclaim-frontend). - Authenticates to Azure (
AZURE_CREDENTIALSsecret) and updates the Azure Container Apps environments. - Verifies the deployment by curling the API health endpoint.
2. Self-hosted template
docker-compose.yml runs the whole platform on a single host:
nginx-proxy+acme-companion→ reverse proxy with automatic Let's Encrypt certificates.- Frontend + backend app containers.
- SQL Server 2022 with a persisted volume.
- Optional DuckDNS container for dynamic-DNS hosts.
The engineering decisions this project demonstrates:
- Security
- JWT access tokens with rotating refresh tokens stored in HttpOnly, Secure, SameSite cookies; single-flight refresh on the client to avoid refresh storms.
- Startup fail-fast validation that rejects placeholder/short JWT secrets in production.
- SSRF protection in the AI pipeline — Gemini can only download images from an allowlisted host (
res.cloudinary.com) and validates magic bytes to detect MIME types. - Razorpay webhook signature verification before any payment state changes.
- Rate limiting (fixed-window, global policy) and structured 401/403/429/500 responses via custom middleware.
- Full audit trail captured automatically with an EF Core
SaveChangesInterceptor(actor, IP, HTTP metadata, old/new values).
- Architecture & design
- Clean Architecture with CQRS + MediatR, plus
ValidationBehaviorandLoggingBehaviorpipeline concerns kept out of controllers. - Unit-of-Work + domain-driven entities with string-based progress states (weather/AI) for idempotent retries.
- 24 additive EF Core migrations evolving the schema through the project's lifecycle.
- Clean Architecture with CQRS + MediatR, plus
- Reliability & background processing
- Hangfire jobs with
AutomaticRetrybackoff andDisableConcurrentExecutionlocks for Gemini processing; failed jobs are markedFailed(not rethrown) so an admin can re-process instead of wedging the queue. - Polly retry/backoff (with 429 handling) around all external HTTP calls.
- Safe client retry semantics — only
GET/HEADrequests are retried, avoiding duplicate policies, claims, and charges.
- Hangfire jobs with
- Integrations
- Three real third-party APIs behind clean interfaces: Gemini Vision, Open-Meteo, Razorpay — plus Cloudinary storage and ElasticEmail delivery, all swappable by DI registration.
- Email rendered from Razor templates and queued through Hangfire for reliable delivery.
- Observability
- Liveness, readiness (
/health/detail, admin-only), and DB health endpoints wired to DockerHEALTHCHECKand the deployment pipeline.
- Liveness, readiness (
- UI/UX
- Responsive dashboards with Recharts visualizations, form validation via React Hook Form + Zod, map-based location picking, and real-time SignalR notifications.
Building FarmClaim taught me how the pieces of a production-grade full-stack system fit together:
- Designing an async verification pipeline — scheduling weather/AI work as durable background jobs with retries, timeouts, and idempotent status transitions rather than blocking HTTP requests.
- Security as a first-class concern — SSRF allowlisting, webhook signature checks, HttpOnly cookie handling, token rotation, and fail-fast secret validation.
- Wrapping third-party services — putting Gemini, Open-Meteo, Razorpay, Cloudinary, and email providers behind stable interfaces so the domain logic never depends on a vendor.
- CQRS + Clean Architecture at a real scale — keeping controllers thin, validation in the pipeline, and business rules in the Application layer.
- Monitoring and robustness — health checks, rate limiting, structured error responses, and retry policies with safe retry semantics.
- Shipping — containerizing a .NET + Next.js monorepo and automating deployment with CI/CD end to end.
Planned ideas — not yet implemented.
- Automated test suite — xUnit unit + integration tests for the Application/Infrastructure layers (highest priority).
- Observability — OpenTelemetry tracing/metrics, structured logging to a central sink, and error alerting.
- Caching — response caching for plan lists and dashboard aggregates to reduce DB load.
- Notification channels — in-app push plus email/policy reminders for state changes beyond claims.
- Admin UX — bulk claim/policy actions and richer filtering.
- Multi-tenancy — support multiple insurer organizations within one deployment.
- Localization — multilingual interface for farmers.
- Fraud heuristics — flag claims whose incident date lacks severe weather AND low AI confidence.
Your Name Here
- GitHub: github.com/yourusername
- LinkedIn: linkedin.com/in/yourprofile
- Portfolio: yourwebsite.com
- Email: youremail@example.com
(Replace the placeholders above with your real details.)



