The Problem
Our parent company was paying for both Keka (HRMS) and Jira (Project Management). Two separate tools, two separate logins, two separate data silos. We decided to build one platform that does both — better.
HT Connect Features
HR Module:
Project Management Module:
Tech Stack
Frontend: Next.js 14 + Chakra UI
Backend: Express.js + Prisma ORM
Database: PostgreSQL 16
Cache: Redis 7
Deploy: Docker Compose
Auth: JWT + Refresh TokensDatabase Schema
The Prisma schema grew to 35+ models:
model Employee {
id String @id @default(cuid())
employeeId String @unique
email String @unique
firstName String
lastName String
department Department @relation(fields: [departmentId], references: [id])
departmentId String
role EmployeeRole @default(EMPLOYEE)
joiningDate DateTime
status EmployeeStatus @default(ACTIVE)
leaves Leave[]
tasks Task[]
reviews PerformanceReview[]
attendance Attendance[]
documents Document[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Sprint {
id String @id @default(cuid())
name String
goal String?
startDate DateTime
endDate DateTime
status SprintStatus @default(PLANNED)
tasks Task[]
velocity Int?
project Project @relation(fields: [projectId], references: [id])
projectId String
createdAt DateTime @default(now())
}
model Task {
id String @id @default(cuid())
title String
description String?
status TaskStatus @default(TODO)
priority Priority @default(MEDIUM)
storyPoints Int?
assignee Employee? @relation(fields: [assigneeId], references: [id])
assigneeId String?
sprint Sprint? @relation(fields: [sprintId], references: [id])
sprintId String?
timeTracked Int @default(0) // minutes
tags String[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}The Result
HT Connect now serves as the primary operational tool for a 50-person company: