"Dunzo for skilled workers" — Find a verified plumber, electrician, or carpenter in under 5 minutes.
Built for India's 500M+ blue-collar workforce with smartphones but no digital presence.
Flutter App (Android/iOS)
│
│ REST API + WebSocket
▼
Spring Boot Backend (Java 17)
│
├── PostgreSQL (all data — users, jobs, otps)
└── Redis (worker availability cache by pincode)
shramiklink/
├── backend/ ← Spring Boot API
│ ├── src/main/java/com/shramiklink/
│ │ ├── controller/ ← HTTP endpoints (REST API)
│ │ ├── service/ ← Business logic
│ │ ├── entity/ ← Database tables (JPA)
│ │ ├── repository/ ← Database queries
│ │ ├── security/ ← JWT auth filter
│ │ ├── config/ ← Redis, WebSocket, Security config
│ │ ├── dto/ ← API request/response shapes
│ │ └── enums/ ← Skill types, job status, etc.
│ ├── Dockerfile
│ └── pom.xml
│
├── flutter_app/ ← Flutter mobile app
│ ├── lib/
│ │ ├── main.dart ← App entry point
│ │ ├── models/ ← Data classes (Worker, Job, etc.)
│ │ ├── services/ ← API calls (http package)
│ │ ├── providers/ ← State management (Riverpod)
│ │ ├── screens/
│ │ │ ├── auth/ ← Login, OTP screens
│ │ │ ├── worker/ ← Worker dashboard, profile setup
│ │ │ ├── employer/ ← Home, search, booking screens
│ │ │ └── shared/ ← Job detail screen
│ │ └── utils/ ← Constants, theme, router
│ └── pubspec.yaml
│
├── docker-compose.yml ← Runs backend + postgres + redis together
└── .github/workflows/ ← CI/CD (auto test + deploy)
- Java 17+
- Flutter 3.16+
- Docker + Docker Compose
- Android Studio or VS Code
# From the root shramiklink/ folder
docker-compose up --buildThis starts:
- PostgreSQL on port 5432
- Redis on port 6379
- Spring Boot API on port 8080
Verify it's running:
curl http://localhost:8080/api/auth/health
# → {"status":"UP","service":"ShramikLink"}cd flutter_app
flutter pub get
flutter run
⚠️ For Android emulator, the API URL10.0.2.2:8080automatically points to your computer's localhost. For a real device, updateapiBaseUrlinlib/utils/app_constants.dartto your computer's IP.
All protected routes require: Authorization: Bearer <token>
| Method | Endpoint | Body | Description |
|---|---|---|---|
| POST | /api/auth/send-otp |
{"phone":"9876543210"} |
Send OTP |
| POST | /api/auth/verify-otp |
{"phone":"...","otp":"123456","role":"WORKER"} |
Verify OTP → JWT |
| Method | Endpoint | Description |
|---|---|---|
| PUT | /api/workers/profile |
Update worker profile |
| GET | /api/workers/{id} |
View worker profile |
| PATCH | /api/workers/availability?status=AVAILABLE_NOW |
Toggle availability |
| GET | /api/workers/search?skill=PLUMBER&pincode=201001 |
Search workers |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/jobs |
Create booking |
| PATCH | /api/jobs/{id}/status?status=ACCEPTED |
Accept/complete job |
| POST | /api/jobs/{id}/rate |
Rate worker |
| GET | /api/jobs/worker |
Worker's job history |
| GET | /api/jobs/employer |
Employer's job history |
- Employers search "show me plumbers in 201001" thousands of times a day
- Going to PostgreSQL every time = slow + expensive
- Redis caches the result for 5 minutes in RAM = 10x faster
- When a worker changes status →
@CacheEvictclears that pincode's cache
- Without it: Flutter app must ask "any new jobs?" every 5 seconds = wasteful
- With it: Server pushes "new job!" the instant it happens = efficient + instant
- Workers get notified in real-time via STOMP over WebSocket
- Mobile apps can't use browser cookies
- JWT is a signed token stored on device — server verifies the signature without DB lookup
- Stateless = works across multiple server instances (horizontal scaling)
- Most workers don't remember complex passwords
- Phone number is the universal Indian identity — everyone knows their number
- Reduces support burden (no "forgot password" flow needed)
The 5% platform fee is calculated automatically in JobService.java:
BigDecimal platformFee = totalAmount.multiply(new BigDecimal("0.05"));| Metric | Numbers |
|---|---|
| 500 bookings/month | ₹50,000+ revenue |
| ₹99 per booking | Tier 1 city pricing |
| ₹299/month worker subscription | Premium listing |
DATABASE_URL=jdbc:postgresql://your-db-host:5432/shramiklink
DB_USERNAME=shramiklink
DB_PASSWORD=<strong-password>
REDIS_HOST=your-redis-host
JWT_SECRET=<256-bit-random-string>
OTP_MOCK=false# On your server
git clone your-repo && cd shramiklink
docker-compose up -dPush to main branch → GitHub Actions automatically:
- Runs backend tests
- Builds Flutter APK
- Deploys new Docker image to your server
Add these GitHub Secrets: SERVER_HOST, SSH_PRIVATE_KEY
In application.properties, set app.otp.mock-enabled=false
Then in OtpService.java, implement:
// Fast2SMS (cheapest for India, ₹0.15 per SMS)
// API: https://fast2sms.com/dev/bulk
private void sendSmsViaFast2SMS(String phone, String otp) {
// HTTP POST to Fast2SMS API
}- Visit 5 housing societies personally
- Onboard their regular plumbers/electricians
- Show employers the app — "find your usual guy here"
- 20 workers + 10 employers = first real traction
- Word of mouth → 5 housing societies → 50
Zero marketing budget. Zero travel. One city.