| title | FORESE HR Database - Project Documentation | ||
|---|---|---|---|
| authors |
|
The FORESE HR Database is a role-based contacts management platform used to organize Mock Placements outreach. It enables admins, incharges, and volunteers to securely authenticate, manage HR contact records, analyze progress via dashboards, and perform bulk CSV uploads. The application is built with Next.js App Router, React, and PostgreSQL, and employs JWT-based sessions with server-side authorization.
- Introduction
- Architecture Overview
- Tech Stack
- Features
- Roles and Permissions
- Environment & Configuration
- Database Schema
- Data Flows
- API Endpoints
- Server Actions
- Frontend Pages & Components
- Authentication & Session Management
- CSV Upload Flow
- Analytics & Telemetry
- Setup, Build, and Run
- Deployment
- Security Considerations
- Troubleshooting & Support
- Future Technical Improvements
- Appendix
FORESE HR Database centralizes HR outreach contacts and progress tracking with fine-grained, role-based access. It is optimized for reliability, clarity, and speed of operations across Admin, Incharge, and Volunteer user groups.
- Web application using Next.js 15 App Router and React 19.
- PostgreSQL as the primary data store with SQL queries through
pg. - Server Actions for data mutations and reads under
src/lib/actions.js. - API routes for OAuth and auxiliary data under
src/app/api. - JWT-based session management via
jose, cookies, and edge middleware for route protection. - Tailwind CSS and shadcn/ui (Radix primitives) for UI.
- Optional analytics via PostHog.
High-Level Directory Map:
src/app— App Router pages, middleware, API routessrc/components— UI and page-level building blockssrc/lib— database pool, actions, validation, session helpers, utilitiesdb.sql— PostgreSQL schema (new and legacy reference)
-
Frontend
- Next.js 15 (App Router), React 19
- UI: Tailwind CSS, shadcn/ui built on Radix UI primitives, lucide-react icons
- Charts: recharts
- State/UX: next-themes, next-nprogress-bar
-
Validation and typing
- zod for schema validation
-
Data and backend
- PostgreSQL with
pgnode client - SQL queries in server actions under
src/lib/actions.js
- PostgreSQL with
-
Authentication and security
- jose (HS256 JWT) for sessions
- bcryptjs for password hashing
- Middleware-based route protection
-
File processing
- papaparse for CSV parsing
- react-dropzone for client-side uploads
-
Analytics
- posthog-js with ingestion rewrites configured in
next.config.mjs
- posthog-js with ingestion rewrites configured in
-
Utilities and styling
- clsx + tailwind-merge for class composition
-
Tooling
- Tailwind CSS + tailwindcss-animate
- drizzle-kit present for potential migrations (not currently used in runtime)
- Authentication: Email/Password and Google OAuth 2.0.
- Role-based authorization (RBAC): Admin, Incharge, Volunteer with server-side checks.
- HR contacts CRUD with strict permissioning and pagination/search/filters.
- Bulk CSV upload with duplicate detection by phone number and downloadable duplicates report.
- Dashboards: Admin (Incharge overview), Incharge (Member distribution), Volunteer (Personal stats).
- PostHog-based analytics for events and page views (optional).
-
Admin
- Manage all users (create incharges/volunteers).
- Full read/write on all HR records.
- Access admin dashboard (
/stats).
-
Incharge
- Read/write HR records for volunteers assigned to them.
- View incharge dashboard aggregations.
-
Volunteer
- Read/write only their own HR records.
- View personal member statistics.
Route Protection (middleware):
- Protected:
/,/add-hr,/edit-hr,/hr-pitch - Admin-only:
/add-user - Public (landing):
/welcome; login redirect flow at/login
Environment variables (see example.env):
DB_URL=postgresql://USER:PASS@HOST:PORT/DBNAME
SESSION_SECRET="<strong-random-secret>"
NEXT_PUBLIC_POSTHOG_KEY=""
GOOGLE_CLIENT_ID=""
GOOGLE_CLIENT_SECRET=""
NEXT_PUBLIC_BASE_URL=http://localhost:3000
Key Config Files:
next.config.mjs: PostHog ingestion rewrites;skipTrailingSlashRedirect: true.tailwind.config.js: Dark mode via class, content globs, animations, and CSS variables for color/radius.
Primary tables (from db.sql):
-
usersid SERIAL PRIMARY KEYemail VARCHAR(255) UNIQUE NOT NULLpassword VARCHAR(255) NOT NULL(bcrypt hash)role VARCHAR(50) NOT NULLin {admin,incharge,volunteer}incharge_email VARCHAR(255)(FK tousers.email, nullable)name VARCHAR(255)
-
hr_contactsid SERIAL PRIMARY KEYhr_name VARCHAR(255)volunteer_email VARCHAR(255)(FK tousers.emailON DELETE CASCADE)phone_number VARCHAR(50)email VARCHAR(255)company VARCHAR(255)status VARCHAR(50)interview_mode VARCHAR(50)hr_count INTEGER DEFAULT 1transport VARCHAR(255)address TEXTinternship VARCHAR(50)comments TEXT
Notes:
- App logic enforces uniqueness of
phone_numberfor inserts/updates. If you need database-level enforcement, add a unique index:CREATE UNIQUE INDEX unique_phone_number ON hr_contacts (phone_number);
-
Login (Email/Password)
loginaction validates credentials withzodand bcrypt compares againstusers.password.- On success, a session JWT is set in
sessioncookie containing email, role, name, and optional incharge details.
-
Login (Google OAuth)
/api/auth/google/startredirects to Google with a CSRFstatecookie./api/auth/google/callbackverifies state and ID token, then looks up the user by email.- If user exists, sets JWT session and redirects to
/login?google=1to complete client-side routing.
-
Session & RBAC
src/lib/session.jshandles JWT sign/verify and cookie management.src/middleware.jsrestricts routes and enforces admin-only sections.- All server actions read
getSession()to authorize operations.
-
GET /api/auth/google/start- Redirects to Google OAuth 2.0 authorization endpoint. Sets
google_oauth_statecookie.
- Redirects to Google OAuth 2.0 authorization endpoint. Sets
-
GET /api/auth/google/callback- Handles OAuth callback, exchanges code for tokens, validates ID token, looks up user, sets session, redirects.
-
GET /api/incharges- Auth required (
admin/incharge/volunteer). Returns list of users with roleinchargeas{ name, email }.
- Auth required (
-
login(formData)- Validates
email,password. Compares bcrypt hash; sets session.
- Validates
-
getHrData(page, pageSize, searchParams)- Paginates HR records with role-aware filters (volunteer, incharge, admin). Returns data and total count.
-
addHrRecord(formData)- Validates and inserts HR record; enforces volunteer assignment rules per role; returns inserted row with joined names.
-
editHR(id, formData)/deleteHR(id)- Authorization checks by role and ownership; updates or deletes record accordingly.
-
addUser(state, formData)- Admin-only. Creates users; if role is volunteer, verifies specified incharge exists.
-
getMemberStats()/getInchargeStats(inchargeEmail)/getAdminStats()- Aggregated metrics per role using conditional counts over
hr_contacts.
- Aggregated metrics per role using conditional counts over
-
addHrBulk(hrDataArray)- Volunteer-only bulk insert; skips existing
phone_numberrows and returns duplicates summary.
- Volunteer-only bulk insert; skips existing
Key routes (App Router):
/welcome— public landing/login— login UI and Google OAuth finalizer/— main table/dashboard; protected/add-hr— add HR form; protected/edit-hr— edit HR flow; protected/hr-pitch— pitch resources; protected/csv-upload— CSV upload UI; protected/add-user— admin-only user creation/stats— dashboards (admin/incharge/member views)
Representative components:
src/components/hr/hr-table.jsx,search-form.jsx,pagination-controls.jsx— data table UXsrc/components/csv-upload.jsx— CSV import and duplicate exportsrc/components/admin-stats.jsx,incharge-stats.jsx,member-stats.jsx— charts viarechartssrc/components/login-page.jsx,navbar.jsx,hr-details-dialog.jsx— UI flows
- Sessions: HS256-signed JWT via
jose, stored insessioncookie (7-day expiry). - Helpers:
createSession,createSessionOnResponse,getSession,deleteSession,updateSession. - Middleware: restricts protected routes and redirects logged-in users away from
/login(except during Google finalization).
- Volunteer prepares CSV with required headers (see UI template).
- Client uploads; server-side parses with
papaparseand validates withzod. - Records inserted if
phone_numbernot present; duplicates are reported back for export.
- Optional:
posthog-jsfor page views and events. next.config.mjsincludes rewrite rules for PostHog ingestion and skipTrailingSlashRedirect.
Prerequisites: Node.js 18.18+ (or 20+), PostgreSQL 13+.
Steps:
- Clone repository and install dependencies.
- Copy
example.envto.env.localand set values (includingNEXT_PUBLIC_BASE_URL). - Create database and apply
db.sql. Seed at least one admin user. - Start dev server:
npm run dev(default port 3000). - Build and run production:
npm run build && npm start.
Environments: Production and staging environments should be configured with strong secrets, HTTPS, and managed PostgreSQL.
Options:
-
Vercel + Managed Postgres (e.g., Neon/Supabase)
- Set env vars in project settings:
DB_URL,SESSION_SECRET, Google OAuth,NEXT_PUBLIC_BASE_URL. - Import schema: apply
db.sqlon the managed database; seed an admin user. - Ensure Node.js runtime (Next.js 15) and Edge Middleware are supported (default on Vercel).
- Set env vars in project settings:
-
Docker Compose (self-hosted)
- Example (adjust volumes/secrets):
version: '3.9' services: db: image: postgres:15 environment: POSTGRES_PASSWORD: example POSTGRES_DB: hrdb ports: ["5432:5432"] volumes: - pgdata:/var/lib/postgresql/data web: image: node:20 working_dir: /app command: sh -c "npm ci && npm run build && npm start" environment: DB_URL: postgresql://postgres:example@db:5432/hrdb SESSION_SECRET: change-me NEXT_PUBLIC_BASE_URL: https://your-domain ports: ["3000:3000"] depends_on: [db] volumes: - ./:/app volumes: pgdata:
- Apply
db.sqlto thedbservice (e.g.,docker exec -i <db> psql -U postgres -d hrdb < db.sql).
-
VM/Bare Metal with PM2 + Nginx
- Install Node 20+, PostgreSQL (or use managed DB).
npm ci && npm run build && pm2 start npm --name hrdb -- start.- Terminate TLS at Nginx; proxy to
127.0.0.1:3000.
Operational notes:
- Cookies: set
httpOnly: true,secure: true,sameSite: lax/strictin production. - Database: create least-privileged DB user; enable automated backups.
- Monitoring: enable logs aggregation and uptime checks; consider PostHog for analytics.
- Scaling: use connection pooling (e.g., PgBouncer) and horizontal scaling behind a reverse proxy.
- Use a strong
SESSION_SECRETand sethttpOnly/secureon cookies in production. - Enforce HTTPS in deployment environments.
- Consider adding a unique index on
hr_contacts.phone_numberto harden duplicate prevention. - Validate all inputs with
zodand sanitize outputs where appropriate.
- Google login failing:
- Check
NEXT_PUBLIC_BASE_URL, OAuth credentials, and redirect URI.
- Check
- 401/403 on actions:
- Ensure valid session and appropriate role.
- CSV import errors:
- Confirm phone numbers are exactly 10 digits and headers match the template.
- Data layer and migrations
- Adopt migrations tool (e.g., Drizzle Kit or Prisma Migrate) instead of manual
db.sql. - Add DB constraints and indexes (unique
phone_number, partial indexes onstatus,volunteer_email).
- Adopt migrations tool (e.g., Drizzle Kit or Prisma Migrate) instead of manual
- Security & auth
- Enforce
httpOnlyandsecurecookies in prod; tightenSameSite. - Add rate limiting on API routes; centralize CSRF for mutating Server Actions.
- Consider rotating session tokens or a short-lived access token + refresh strategy.
- Enforce
- Observability
- Structured logging (request IDs), error reporting (Sentry), metrics (Prometheus/Grafana).
- Add health/readiness endpoints for orchestration.
- Performance
- Cursor-based pagination for large datasets; query optimization and indexes.
- Caching strategies (HTTP caching, SWR/React Query, server-side caches).
- Improve CSV ingestion via streaming or
COPYwhen permitted.
- Product & UX
- Accessibility (WCAG) pass; keyboard navigation; color contrast.
- i18n and localization scaffolding.
- Audit log of user actions for compliance.
- Tooling & QA
- CI/CD (GitHub Actions) with tests (unit/integration/e2e via Playwright) and lint checks.
- Codegen for types across API and DB (zod-to-ts, OpenAPI if exposing public APIs).
Dependencies (selected): Next.js 15, React 19, pg, jose, bcryptjs, zod, papaparse, posthog-js, recharts, Radix UI.
License: Internal use by FORESE; update accordingly if open-sourcing.