Employee & Project Allocation, Tracking & Management Platform - Angular, TypeScript, MongoDB, Prisma, Serverless API, AI Drafting, Contentful, Resend Full-Stack Project (including Real-time Dashboard, Calendar, Timeline, Gantt Chart, Business Insights)
EmpowerHub is a comprehensive, full-stack Employee & Project Management learning project built with Angular 20, a Vercel serverless API, Prisma + MongoDB, optional AI overview drafting, Contentful briefs, and email notifications (Resend / SMTP). It demonstrates real-world CRUD, session auth, dashboards, calendar / Gantt / timeline views, business insights, and API docs & monitoring.
- Live demo: https://employee-project-management.vercel.app/
- Security: Private reports → SECURITY.md · contact@arnobmahmud.com
- Author: Arnob Mahmud | LinkedIn: https://www.linkedin.com/in/arnob-mahmud-05839655/ | GitHub: https://github.com/arnobt78
- Overview
- Who This Project Is For
- Features
- Technology Stack
- Architecture Walkthrough
- Project Structure
- Getting Started
- Environment Variables
- Demo Login
- Routes & Navigation
- API Endpoints
- Backend & Data Layer
- Frontend Components & Reuse
- Key Libraries Explained
- Code Snippets for Learners
- Scripts Reference
- Deployment (Vercel)
- Observability (Sentry)
- Further Docs in This Repo
- Keywords
- Conclusion
- License
- Happy Coding
EmpowerHub helps learners explore how a modern SPA talks to a serverless backend and a document database:
| Layer | What it does |
|---|---|
| Angular SPA | Pages for login, dashboard, employees, projects, assignments, insights, calendar/timeline, API docs/status |
| API | Node handlers under api/employee-management/ on Vercel (locally via tools/dev-api-server.mjs) |
| Database | MongoDB via Prisma (prisma/schema.prisma) with a native Mongo fallback path where needed |
| Auth | HttpOnly session cookie (eh_session), bcrypt-hashed demo user, route guards |
| Extras | AI overview draft (multi-provider fallback), Contentful brief fetch, email notifications, Sentry tunnel |
You can run the UI against the live demo immediately, or clone and run locally with MongoDB. Most optional services (AI, CMS, email, Sentry) can stay empty—the core CRUD and UI still work when DATABASE_URL and a seeded auth user are available.
- Beginners learning Angular standalone components, signals, and RxJS Observables
- Developers exploring serverless APIs on Vercel without a long-running Node server in production
- Anyone wanting a portfolio CRUD app with dashboards, charts-like schedule views, and API status pages
- Learners studying session cookies, route guards, and API auth middleware
- Authentication — Demo admin login with bcrypt + HttpOnly cookie;
authGuard/guestGuard - Employees — Full CRUD with department hierarchy (parent / child)
- Projects — Create/update/delete, approval workflow, reviewer comments, rich project form
- Project assignments — Link employees to projects with roles and allocation fields
- Dashboard — Aggregated KPIs with loading skeletons (avoids empty-state flash)
- Business insights — Analytics over projects and assignments
- Calendar, timeline & Gantt — Schedule visualization components
- API documentation & status — In-app docs plus live request monitoring metrics
- Notifications — Optional Resend and/or SMTP emails on key CRUD / approval events
- AI overview drafting — Optional Gemini → Groq → OpenRouter
:free→ Hugging Face fallback - Contentful briefs — Optional CMS fetch into project overview
- Error tracking — Optional Sentry with same-origin tunnel
/api/monitoring(ad-blocker friendly)
- Single API client:
MasterService(prefer extending this over adding new HTTP clients) - Feature flags via public env (
NG_APP_FEATURE_*) .env.exampledocuments every variable and where to obtain keys- Lint (
npm run lint), unit tests (npm test), production build (npm run build)
| Area | Choice | Why it matters (beginner note) |
|---|---|---|
| UI | Angular 20 (standalone) | Components without NgModules; modern default |
| Language | TypeScript ~5.8 | Types catch mistakes before runtime |
| Styling | Tailwind CSS 3.4 + shadcn-style UI | Utility classes + reusable button/cva patterns |
| Icons | Lucide Angular | Icon sets for nav and actions |
| State / HTTP | RxJS + HttpClient |
Streams for async API calls |
| API | Vercel Serverless Functions | Pay-per-request backend, no always-on server |
| ORM / DB | Prisma 6 + MongoDB | Schema in code; Mongo for flexible documents |
| Auth | bcryptjs + HttpOnly cookies | Password hashing; cookie not readable by JS |
| Resend API and/or Nodemailer SMTP | Transactional mail | |
| AI | Gemini / Groq / OpenRouter / HF | Free-tier fallback chain |
| CMS | Contentful Delivery API | Headless content for project briefs |
| Errors | Sentry (@sentry/angular + tunnel) |
Production error visibility |
| Hosting | Vercel | Static Angular dist/ + /api/* functions |
Browser (Angular SPA)
│ HTTPS / proxy in dev
▼
MasterService ──► /api/employee-management/<Action>
│
▼
[...segments].js → handler.mjs → repository.mjs / auth.mjs / notifications.mjs / ai-providers.mjs
│
▼
Prisma / MongoDB
Local development: ng serve proxies /api/employee-management and /api/monitoring to http://localhost:4310 (proxy.conf.json + tools/dev-api-server.mjs).
Production: Vercel serves Angular dist/ (framework preset) and runs api/employee-management/[...segments].js plus api/monitoring.js (Sentry tunnel).
employee-management/
├── src/
│ ├── index.html # SEO metadata, canonical URL, JSON-LD
│ ├── environments/ # Public client config (no secrets)
│ └── app/
│ ├── app.routes.ts # Routes + guards
│ ├── pages/ # Feature pages (login, dashboard, CRUD, …)
│ ├── components/ # Calendar, Gantt, timeline, UI primitives
│ ├── service/ # MasterService, AuthService
│ ├── guards/ # authGuard, guestGuard
│ ├── interceptors/ # credentials + 401 handling
│ ├── lib/sentry/ # Client Sentry init + noise filters
│ └── model/ # Interfaces + Employee class
├── api/
│ ├── monitoring.js # Sentry same-origin tunnel
│ ├── _lib/ # prisma-client, sentry helpers
│ └── employee-management/
│ ├── [...segments].js # Vercel entry
│ ├── handler.mjs # Routing + auth + notifications triggers
│ ├── repository.mjs # Data access + AI/CMS helpers
│ ├── auth.mjs # Login / session / logout
│ ├── notifications.mjs # Resend / SMTP
│ ├── ai-providers.mjs # LLM fallback chain
│ └── monitoring.mjs # In-memory API request metrics (not Sentry)
├── prisma/ # schema.prisma + seed
├── tools/ # dev-api-server, seed-demo-user, env/sentry scripts
├── public/ # favicon, robots.txt, sitemap.xml
├── docs/ # Playbooks, LLM selection, Sentry guide
├── .env.example # Template (copy to .env)
├── SECURITY.md # Private vulnerability reporting
├── vercel.json # Output dir, headers, function limits
└── package.json
- Node.js 24.x (see
enginesinpackage.json;.nvmrcif present) - npm
- MongoDB reachable via a connection string (local or Atlas / VPS)
git clone https://github.com/arnobt78/Employee-Management--Angular-FullStack-Fundamental-Project-1.git
cd Employee-Management--Angular-FullStack-Fundamental-Project-1
npm installpostinstall generates src/environments/environment.prod.ts (gitignored).
cp .env.example .envMinimum for a useful local demo:
- Set
DATABASE_URLto your MongoDB URI - Seed domain data from
dataset/:npm run db:seed - Seed the demo auth user:
npm run db:seed:auth
To wipe and reseed a local Mongo only: ALLOW_DB_WIPE=1 npm run db:reseed:local (refuses non-localhost unless EH_ALLOW_REMOTE_WIPE=1 / EH_ALLOW_ATLAS_WIPE=1).
You do not need AI, CMS, email, or Sentry keys to explore CRUD UI. Leave those blank; features that need them simply stay disabled or no-op.
npm startThis runs:
- API on http://localhost:4310 (
npm run api:dev) - Angular on http://localhost:4200 with proxy (
npm run start:frontend)
Open http://localhost:4200 → sign in with the demo account.
npm run lint
npm test -- --watch=false --browsers=ChromeHeadless
npm run buildCopy .env.example → .env. Never commit .env.
| Goal | Need .env? |
|---|---|
| Browse the live Vercel demo | No |
| Run UI + API locally with real data | Yes — at least DATABASE_URL (+ seed auth) |
| AI overview draft | Optional — GOOGLE_GEMINI_API_KEY and/or Groq / OpenRouter / HF |
| Contentful briefs | Optional — CMS_* |
| Email notifications | Optional — RESEND_TOKEN and/or SMTP_* |
| Sentry | Optional — empty DSN disables Sentry |
This Angular build does not inject Vercel NG_APP_* secrets into a secure server-only store for the API. AI / CMS / email / DB / SENTRY_AUTH_TOKEN must stay unprefixed server env vars. NG_APP_* is only for public client-safe values (API base path, feature flags). DSN for Sentry is public by design and is baked at build from SENTRY_DSN.
| Variable | Purpose | Where to get it |
|---|---|---|
DATABASE_URL |
MongoDB connection for Prisma | MongoDB Atlas or your host |
APP_BASE_URL |
Links in emails; OpenRouter referer | Local: http://localhost:4200 · Prod: your Vercel URL |
NG_APP_API_BASE_URL |
Client API prefix | Usually /api/employee-management/ |
API_PORT |
Local API port | Default 4310 |
SESSION_TTL_HOURS |
Session cookie lifetime | Default 24 |
NG_APP_FEATURE_READINESS_V2=true
NG_APP_FEATURE_AI_SUMMARY=false
NG_APP_FEATURE_WORKFLOW_TIMELINE=falseGOOGLE_GEMINI_API_KEY= # https://aistudio.google.com/apikey
GROQ_LLAMA_API_KEY= # https://console.groq.com/keys
OPENROUTER_API_KEY= # https://openrouter.ai/keys (use :free models)
HUGGINGFACE_API_KEY= # https://huggingface.co/settings/tokensFallback order: Gemini → Groq → OpenRouter :free → Hugging Face. See docs/LLM_MODEL_SELECTION.md.
CMS_SPACE_ID=
CMS_ENVIRONMENT=master
CMS_DELIVERY_TOKEN=
CMS_PREVIEW_TOKEN=From Contentful → Settings → API keys.
RESEND_TOKEN= # https://resend.com/api-keys
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
EMAIL_FROM="EmpowerHub <no-reply@example.com>"
EMAIL_DRY_RUN=false # true = log only, do not send
NOTIFY_APPROVAL_TO= # optional always-notify list (comma-separated)SENTRY_DSN= # Project → Client Keys (DSN)
SENTRY_ORG=
SENTRY_PROJECT=employee-management
SENTRY_AUTH_TOKEN= # CI source maps only — never in the browser bundleSame-origin tunnel: POST /api/monitoring. Details: .env.example and docs/Redis_Sentry_PostHog_INTEGRATION_GUIDE.md.
Set production/preview env for at least: DATABASE_URL, APP_BASE_URL (live URL), then redeploy. Add optional AI/CMS/email/Sentry as needed. After changing env, redeploy so build-time DSN bake and serverless functions pick up values.
| Field | Value |
|---|---|
| Username | admin |
| Password | 112233 |
Seed / refresh the hashed user:
npm run db:seed:authDo not put demo passwords in Vercel as NG_APP_DEMO_PASSWORD. The login form autofill uses public demo constants for learning; production apps should replace this with real identity providers.
Defined in src/app/app.routes.ts:
| Path | Page | Guard |
|---|---|---|
/ |
Redirect → /login |
— |
/login |
Sign in | guestGuard |
/dashboard |
KPIs | authGuard |
/employee |
Employee CRUD | authGuard |
/projects |
Project list | authGuard |
/new-project |
Create project | authGuard |
/update-project/:id |
Edit project | authGuard |
/project-employee |
Assignments | authGuard |
/business-insights |
Analytics | authGuard |
/calendar-timeline |
Calendar / timeline / Gantt | authGuard |
/api-doc |
API documentation UI | authGuard |
/api-status |
Live API health UI | authGuard |
Private pages nest under LayoutComponent (shell nav + outlet).
Base path: /api/employee-management/<Action>
Most actions require an authenticated session cookie. Public-ish actions include login/demo listing (see isPublicAction in auth.mjs / handler).
| Method | Action | Description |
|---|---|---|
| POST | Login |
Authenticate; sets eh_session |
| POST | Logout |
Clears session |
| GET | Session |
Current session |
| GET | GetDemoAccounts |
Demo account hints |
| Method | Action | Description |
|---|---|---|
| GET | GetParentDepartment |
Parent departments |
| GET | GetChildDepartmentByParentId |
Children by parent id |
| Method | Action | Description |
|---|---|---|
| GET | GetAllEmployees |
List |
| POST | CreateEmployee |
Create |
| PUT | UpdateEmployee |
Update |
| DELETE | DeleteEmployee |
Delete |
| Method | Action | Description |
|---|---|---|
| GET | GetAllProjects / GetProject |
List / one |
| POST | CreateProject |
Create |
| PUT | UpdateProject |
Update |
| DELETE | DeleteProject |
Delete |
| POST | RequestApproval / ApproveProject / RejectProject / ResetProjectApproval |
Approval flow |
| POST | AddReviewerComment / ResolveReviewerComment |
Reviewer comments |
| GET | GetProjectResources |
Resource insights |
| GET | GetContentfulBrief |
Optional CMS brief |
| POST | GenerateOverviewDraft |
Optional AI draft |
| Method | Action | Description |
|---|---|---|
| GET | GetAllProjectEmployees |
List |
| POST | CreateProjectEmployee |
Create |
| PUT | UpdateProjectEmployee |
Update |
| DELETE | DeleteProjectEmployee |
Delete |
| Method | Action | Description |
|---|---|---|
| GET | GetDashboard |
Aggregates |
| GET | GetSchedule |
Calendar/Gantt data |
| GET | GetApiStatus |
Monitoring snapshot |
| GET | GetApiDocumentation |
OpenAPI-like doc payload |
| Method | Path | Description |
|---|---|---|
| POST | /api/monitoring |
Forwards Sentry envelopes (DSN allowlisted) |
Example client call pattern (MasterService):
this.http.get(`${environment.api.baseUrl}GetAllEmployees`, {
withCredentials: true,
});- Vercel (or local HTTP server) receives
/api/employee-management/... handler.mjsparses action + method, checks session unless public- Calls
repository.mjs(Prisma) for persistence - May trigger
notifications.mjsorai-providers.mjs - Logs metrics via
monitoring.mjs(in-memory; resets on cold start)
DepartmentParent/DepartmentChildEmployeeProjectProjectEmployee(assignments)AppUser/Session(auth)Counter(id helpers where used)
Schema: prisma/schema.prisma.
Emails fire on many create/update/delete/approval paths. Recipients come from project stakeholders plus optional NOTIFY_APPROVAL_TO. With EMAIL_DRY_RUN=true, the app logs instead of sending.
Each page is a standalone component (.ts + .html + .css). To reuse a page pattern in another Angular app:
- Copy the page folder
- Register a route
- Inject
MasterService/AuthService(or replace with your API) - Keep loading flags + skeletons so lists do not flash empty values
| Piece | Role | Reuse tip |
|---|---|---|
calendar-view |
Month grid + events | Pass events[] with title, dates, description |
timeline-view |
Horizontal timeline | Feed schedule items from GetSchedule |
gantt-view |
Bar chart by project dates | Map projects → start/end |
ui/button |
CVA-based button variants | Import and use btnVariants / component |
ui/toast + ToastService |
Non-blocking feedback | toast.show({ title, description }) |
ui/select-menu |
Accessible dropdown (CDK overlay) | Prefer over native <select> for styled menus |
ui/list-skeleton |
Loading placeholders | Bind while isLoading |
ui/floating-background |
Decorative bg | Drop into auth/marketing shells |
ui/optimized-image |
Image helper | Swap src / alt |
MasterService— Central HTTP API + short in-memory cache with invalidation after mutations. Prefer extending this for new endpoints.AuthService— Login/logout/session; used by guards and interceptor.
authGuard— Redirect unauthenticated users to/loginguestGuard— Keep logged-in users off/loginauthInterceptor—withCredentials: true; handle 401
| Library | What it is | How we use it |
|---|---|---|
| Angular | SPA framework | Routing, forms, DI, standalone components |
| RxJS | Reactive streams | Observable HTTP results, shareReplay cache |
| Prisma | ORM | Type-safe Mongo access from serverless Node |
| bcryptjs | Password hashing | Demo AppUser password storage |
| Tailwind | Utility CSS | Layout, dark glass UI, responsive spacing |
| class-variance-authority (cva) | Variant API | Button size/intent classes |
| Lucide | Icons | Consistent iconography |
| Nodemailer / Resend | Transactional notifications | |
| Sentry | Errors | Client + server + quiet source maps |
| dotenv | Env loader | Local API + tooling |
import { environment } from "../environments/environment";
if (environment.featureToggles.aiSummaryGenerator) {
// show AI draft button
}this.toast.show({
title: "Project created",
description: "A new project is now tracked in the system.",
});export const authGuard: CanActivateFn = () => {
const auth = inject(AuthService);
const router = inject(Router);
return auth.ensureSession().pipe(map((ok) => (ok ? true : router.createUrlTree(["/login"]))));
};// api/employee-management/ai-providers.mjs
// Tries Gemini → Groq → OpenRouter (:free) → Hugging Face
const completion = await completeChatWithFallback(prompt);| Script | Purpose |
|---|---|
npm start |
API + Angular concurrently |
npm run start:frontend |
ng serve + proxy |
npm run api:dev |
Local API on API_PORT |
npm run build |
Generate prod env → ng build → quiet Sentry map upload |
npm run lint / lint:fix |
ESLint via Angular |
npm test |
Karma / Jasmine |
npm run db:seed |
Domain seed from repo dataset/ |
npm run db:seed:auth |
Demo admin user |
npm run db:wipe:local |
Clear domain collections (requires ALLOW_DB_WIPE=1; localhost only unless override) |
npm run db:reseed:local |
Wipe → db:seed → db:seed:auth (local gate as above) |
- Import the GitHub repo into Vercel
- Set env vars (see above);
APP_BASE_URL= production URL - Build command uses
npm run build(Angular output:dist/, detected by Vercel’s Angular preset) - Redeploy after any env change
Headers in vercel.json discourage caching of API responses and set basic security headers.
- Client SDK posts to
/api/monitoring(not directly toingest.sentry.io) so ad blockers are less likely to drop events - Noise filters drop extension / benign browser noise
- Source maps upload only when
SENTRY_ORG+SENTRY_PROJECT+SENTRY_AUTH_TOKENare set; maps are deleted fromdist/afterward
| Doc | Topic |
|---|---|
.env.example |
Full env template |
SECURITY.md |
Private vulnerability reporting |
docs/LLM_MODEL_SELECTION.md |
Free-tier model choices |
docs/Redis_Sentry_PostHog_INTEGRATION_GUIDE.md |
Sentry tunnel / quiet CI patterns |
docs/UI_STYLING_GUIDE.md |
UI conventions |
docs/VERCEL_PRODUCTION_GUARDRAILS.md |
Production tips |
docs/PROJECT_ENGINEERING_PLAYBOOK.md |
Engineering playbook |
docs/AGILE_V_PROTOCOL.md |
Agile V agent workflow |
Technologies: Angular 20, TypeScript, RxJS, Tailwind CSS, Shadcn-style UI, Prisma, MongoDB, Vercel Serverless, Node.js, bcrypt, Sentry, Resend, Nodemailer, Contentful, Gemini, Groq, OpenRouter, Hugging Face
Concepts: CRUD, REST-style action routes, HttpOnly sessions, route guards, HTTP interceptors, serverless cold starts, SPA SEO (index.html meta + sitemap), feature flags, multi-provider AI fallback, approval workflows
Features: Dashboard KPIs, employee/project CRUD, assignments, calendar, timeline, Gantt, business insights, API docs, API status monitoring, email notifications, AI overview drafting
Learning: Standalone components, signals, Observables, reusable UI primitives, repository pattern in serverless handlers, environment hygiene (server vs NG_APP_*)
EmpowerHub is a portfolio-ready, educational full-stack application that connects an Angular SPA to a serverless MongoDB-backed API. Use it to study:
- Modern Angular 20 patterns (standalone, guards, interceptors, signals)
- Serverless request handling and Prisma data access
- Practical auth, CRUD, dashboards, and optional AI / CMS / email / Sentry integrations
Clone it, seed the demo user, explore the live demo, then extend MasterService and repository.mjs for your own domain.
This project is licensed under the MIT License. Feel free to use, modify, and distribute the code as per the terms of the license.
This is an open-source project — feel free to use, enhance, and extend this project further!
If you have any questions or want to share your work, reach out via GitHub or my portfolio at https://www.arnobmahmud.com.
Private security reports: SECURITY.md · contact@arnobmahmud.com






















