From 4e2116aa1c6800451d909f6f7017a81aa3d7f136 Mon Sep 17 00:00:00 2001
From: shibinsp
Date: Sat, 14 Mar 2026 20:26:18 +0530
Subject: [PATCH] docs: update README and add project overview Excel report
- Rewrite README with professional structure: badges, live demo, feature
categories, tech stack, architecture diagram, getting started guide,
E2E test results, CI/CD pipeline, project structure, API endpoints,
security measures, and RBAC matrix
- Create docs/reports/TaskPulse_Project_Overview.xlsx with 6 sheets:
Features (46), E2E Test Results (113), Security (19), Tech Stack (45),
API Endpoints (80), Architecture (23)
- Update Playwright config for deployed app testing via E2E_BASE_URL
- Add test:e2e:deployed npm script
Fixes #17
Co-Authored-By: Beeax
---
Frontend/e2e/helpers.ts | 6 +-
Frontend/package.json | 3 +-
Frontend/playwright.config.ts | 4 +-
README.md | 671 +++++++++----------
docs/reports/TaskPulse_Project_Overview.xlsx | Bin 0 -> 24661 bytes
5 files changed, 336 insertions(+), 348 deletions(-)
create mode 100644 docs/reports/TaskPulse_Project_Overview.xlsx
diff --git a/Frontend/e2e/helpers.ts b/Frontend/e2e/helpers.ts
index f86640f..22800f0 100644
--- a/Frontend/e2e/helpers.ts
+++ b/Frontend/e2e/helpers.ts
@@ -1,9 +1,9 @@
import { type Page, expect } from '@playwright/test';
-/** Demo credentials from seed data */
+/** Demo credentials — use deployed Supabase credentials when E2E_BASE_URL is set */
export const DEMO_USER = {
- email: 'admin@acme.com',
- password: 'demo123',
+ email: process.env.E2E_BASE_URL ? 'admin@taskpulse.demo' : 'admin@acme.com',
+ password: process.env.E2E_BASE_URL ? 'TaskPulse2024' : 'demo123',
name: 'Admin',
};
diff --git a/Frontend/package.json b/Frontend/package.json
index d7e6ab6..f5f59a4 100644
--- a/Frontend/package.json
+++ b/Frontend/package.json
@@ -10,7 +10,8 @@
"preview": "vite preview",
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui",
- "test:e2e:headed": "playwright test --headed"
+ "test:e2e:headed": "playwright test --headed",
+ "test:e2e:deployed": "E2E_BASE_URL=https://relaxed-gates.vercel.app playwright test"
},
"dependencies": {
"@gsap/react": "^2.1.2",
diff --git a/Frontend/playwright.config.ts b/Frontend/playwright.config.ts
index f2cf9f7..8c18e69 100644
--- a/Frontend/playwright.config.ts
+++ b/Frontend/playwright.config.ts
@@ -11,7 +11,7 @@ export default defineConfig({
expect: { timeout: 10_000 },
use: {
- baseURL: 'http://localhost:5173',
+ baseURL: process.env.E2E_BASE_URL || 'http://localhost:5173',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
@@ -47,7 +47,7 @@ export default defineConfig({
},
],
- webServer: {
+ webServer: process.env.E2E_BASE_URL ? undefined : {
command: 'npm run dev',
url: 'http://localhost:5173',
reuseExistingServer: true,
diff --git a/README.md b/README.md
index 78a7abf..811bcaa 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-
+
TaskPulse AI
@@ -15,457 +15,444 @@
- Features •
- Quick Start •
- Architecture •
- API Docs •
- Contributing
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+ Live Demo •
+ Features •
+ Tech Stack •
+ Getting Started •
+ API Docs •
+ Contributing
---
-## The Problem
-
-Traditional task management tools are **passive observers**. They track what's happening but don't actively help employees complete their work. When someone gets stuck:
-
-- ❌ They waste hours before asking for help
-- ❌ Managers only find out during weekly standups
-- ❌ Projects slip without early warning
-- ❌ Valuable knowledge stays siloed in individuals
+## Live Demo
-## The Solution
+**Production**: [https://relaxed-gates.vercel.app](https://relaxed-gates.vercel.app)
-**TaskPulse AI** is an **active task completion engine** that:
-
-- ✅ Proactively checks in with employees every 3 hours
-- ✅ Uses AI to unblock stuck workers instantly
-- ✅ Predicts delivery risks before they become problems
-- ✅ Builds organizational knowledge that helps everyone
+| Email | Password | Role |
+|-------|----------|------|
+| `admin@taskpulse.demo` | `TaskPulse2024` | Super Admin |
+| `orgadmin@taskpulse.demo` | `TaskPulse2024` | Org Admin |
+| `manager@taskpulse.demo` | `TaskPulse2024` | Manager |
+| `lead@taskpulse.demo` | `TaskPulse2024` | Team Lead |
+| `dev@taskpulse.demo` | `TaskPulse2024` | Employee |
+| `viewer@taskpulse.demo` | `TaskPulse2024` | Viewer |
---
## Features
-### 🔄 Smart Check-In Engine
-
-Intelligent, proactive engagement that catches blockers early.
-
-| Feature | Description |
-|---------|-------------|
-| **3-Hour Loops** | Configurable check-in intervals per team or task type |
-| **Friction Detection** | AI identifies when progress is slower than expected |
-| **Auto-Escalation** | Missed check-ins trigger manager notifications |
-| **Silent Mode** | No interruptions when everything's on track |
-
-### 🧠 AI Unblock Engine
-
-RAG-powered assistance with **zero hallucination** guarantee.
-
-```
-Employee: "I'm stuck on the OAuth integration with our legacy system"
+### Task Management
+- **Full CRUD** with priority, status, assignments, due dates, and subtasks
+- **Kanban Board** / **List** / **Grid** views with drag-and-drop
+- **AI Task Decomposition** - break complex tasks into subtasks automatically
+- **Bulk Operations** - update multiple tasks at once
+- **Task Dependencies** - link related tasks together
+- **Comments & History** - full audit trail on every task
+
+### Smart Check-In Engine
+- **3-Hour Loops** - configurable proactive check-in intervals
+- **Friction Detection** - AI identifies when progress stalls
+- **Auto-Escalation** - missed check-ins notify managers
+- **Manager Feed** - centralized view of team responses
+
+### AI Command Center
+- **AI Unblock Engine** - RAG-powered help with blockers
+- **Knowledge Base** - upload and search internal docs
+- **Conversational Task Creation** - create tasks via natural language
+- **Multi-Provider** - OpenAI, Anthropic, Mistral, Kimi, Ollama support
+
+### Prediction & Analytics
+- **Delivery Forecasts** - P25/P50/P90 completion estimates
+- **Velocity Trends** - team performance over time
+- **Productivity Heatmap** - hourly productivity patterns
+- **Dashboard Metrics** - real-time task statistics
+
+### Skill Graph
+- **Skill Tracking** - catalog and rate team skills
+- **Gap Analysis** - identify missing skills for roles
+- **Learning Paths** - personalized development plans
+- **Team Composition** - visualize collective strengths
+
+### Workforce Intelligence
+- **Performance Scoring** - multi-factor employee metrics
+- **Manager Rankings** - leadership effectiveness comparison
+- **Org Health Index** - company-wide health dashboard
+- **Attrition Risk** - identify at-risk employees
+- **Restructuring Simulator** - model team changes before committing
+
+### Automation Detection
+- **Pattern Recognition** - AI finds repetitive workflows
+- **Agent Creation** - one-click automation for common tasks
+- **Shadow Mode** - test automations safely before activation
+- **ROI Dashboard** - track hours saved and cost reduction
+
+### Integrations
+- **OAuth Flows** - connect Slack, Jira, and other tools
+- **Webhooks** - real-time event notifications
+- **API Keys** - programmatic access management
-TaskPulse AI: Based on your codebase and past solutions:
-├── Similar issue solved by @john (PR #234) - 3 weeks ago
-├── Internal wiki: "Legacy OAuth Migration Guide"
-├── Suggested teammate: @sarah (95% skill match)
-└── Estimated unblock time: 45 minutes with pairing
-```
-
-- **Knowledge Base Integration** - Upload docs, wikis, and past solutions
-- **Skill-Adaptive Responses** - Adjusts explanation complexity to user level
-- **Smart Teammate Matching** - Suggests the right person to help
-
-### 📊 Prediction Engine
+---
-Machine learning-powered forecasting that sees problems coming.
+## Tech Stack
-| Prediction Type | What It Does |
-|----------------|--------------|
-| **Delivery Forecast** | P25, P50, P90 completion estimates |
-| **Risk Cascade** | Shows how one delay affects downstream tasks |
-| **Velocity Trends** | Team performance over time |
-| **Hiring Forecast** | Predicts when you'll need more capacity |
+| Layer | Technology |
+|-------|------------|
+| **Frontend** | React 19, TypeScript 5.9, Vite 7, Tailwind CSS, Radix UI/shadcn |
+| **State** | Zustand 5, TanStack React Query |
+| **Backend** | FastAPI, Python 3.11+, SQLAlchemy 2.0 (async) |
+| **Database** | SQLite (dev) / PostgreSQL + Supabase (prod) |
+| **Auth** | JWT + bcrypt + Google OAuth 2.0 + Supabase Auth |
+| **AI** | OpenAI, Anthropic, Mistral, Kimi, Ollama, Mock |
+| **Testing** | Playwright (E2E), pytest (unit) |
+| **CI/CD** | GitHub Actions + Vercel |
+| **Infra** | Docker, Docker Compose |
-### 🎯 Skill Graph
+---
-Automatic skill inference that grows with your organization.
+## Architecture
```
-┌─────────────────────────────────────────────────┐
-│ Developer: Sarah Chen │
-├─────────────────────────────────────────────────┤
-│ ████████████████████░░░░ React (85%) │
-│ ██████████████░░░░░░░░░░ TypeScript (70%) │
-│ ████████████████████████ Python (95%) │
-│ ████████░░░░░░░░░░░░░░░░ DevOps (40%) │
-├─────────────────────────────────────────────────┤
-│ 📈 Learning Velocity: +15% this quarter │
-│ 🎯 Recommended: "Advanced Kubernetes" course │
-└─────────────────────────────────────────────────┘
+ ┌──────────────────────────────┐
+ │ Vercel (Production) │
+ │ relaxed-gates.vercel.app │
+ └──────────────┬───────────────┘
+ │
+ ┌───────────────────────────┼───────────────────────────┐
+ │ │ │
+ ┌──────────▼──────────┐ ┌──────────▼──────────┐ ┌──────────▼──────────┐
+ │ Frontend (Vite) │ │ API (Serverless) │ │ Supabase Auth │
+ │ React 19 + TS │───▶│ FastAPI + Python │ │ OAuth + JWT │
+ │ Port: 5173 │ │ Port: 8000 │ │ │
+ └─────────────────────┘ └──────────┬───────────┘ └─────────────────────┘
+ │
+ ┌─────────────────────┼─────────────────────┐
+ │ │ │
+ ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
+ │ PostgreSQL │ │ AI Providers │ │ Supabase │
+ │ (Supabase) │ │ OpenAI/etc │ │ Storage │
+ └─────────────┘ └─────────────┘ └─────────────┘
```
-### 👥 Workforce Intelligence
-
-Data-driven insights for better organizational decisions.
-
-- **Performance Scoring** - Objective, multi-factor employee metrics
-- **Manager Effectiveness** - How well leaders enable their teams
-- **Org Health Index** - Company-wide productivity dashboard
-- **Restructuring Simulator** - Model team changes before making them
-
-### 🤖 Automation Detection
-
-Find and eliminate repetitive work automatically.
-
-1. **Pattern Recognition** - AI identifies repetitive task sequences
-2. **Agent Creation** - One-click automation for common workflows
-3. **Shadow Mode** - Test automations safely before deployment
-4. **ROI Dashboard** - Track hours saved and cost reduction
-
---
-## Quick Start
+## Getting Started
### Prerequisites
- Python 3.11+
- Node.js 18+
-- npm or yarn
+- npm
-### Local Development
-
-**1. Clone the repository**
+### 1. Clone
```bash
-git clone https://github.com/shibinsp/taskpulse-ai.git
-cd taskpulse-ai
+git clone https://github.com/shibinsp/task_assistant_AI.git
+cd task_assistant_AI
```
-**2. Backend Setup**
+### 2. Backend Setup
```bash
cd backend
-
-# Install dependencies
+python3 -m venv venv
+source venv/bin/activate
pip install -r requirements.txt
-# Or install core dependencies
-pip install fastapi uvicorn sqlalchemy aiosqlite pydantic-settings python-jose[cryptography] passlib bcrypt python-multipart greenlet
-
-# Configure environment (already set up)
-# Edit backend/.env if needed
+# Configure environment
+cp .env.example .env
+# Edit .env with your settings
# Start the server
-python3 -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
+python run.py
+# Or: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
```
-**3. Frontend Setup**
+### 3. Frontend Setup
```bash
-cd frontend
-
-# Install dependencies
+cd Frontend
npm install
-
-# Start development server
npm run dev
```
-**4. Access the Application**
-
-- **Frontend**: http://localhost:3000
-- **Backend API**: http://localhost:8000
-- **API Docs**: http://localhost:8000/docs
-
-### Quick Start Script
+### 4. Seed Demo Data
```bash
-# From project root
-./start.sh
+cd backend
+python scripts/seed_data.py
```
-This will start both backend and frontend services automatically.
+### 5. Access
----
+| Service | URL |
+|---------|-----|
+| Frontend | http://localhost:5173 |
+| Backend API | http://localhost:8000 |
+| API Docs (Swagger) | http://localhost:8000/docs |
+| API Docs (ReDoc) | http://localhost:8000/redoc |
-## Architecture
-
-```
-┌─────────────────────────────────────────────────────────────────┐
-│ Frontend (React) │
-│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────────┐ │
-│ │Dashboard │ │ Tasks │ │ Check-ins│ │ Skills & Reports │ │
-│ └──────────┘ └──────────┘ └──────────┘ └──────────────────────┘ │
-└─────────────────────────────┬───────────────────────────────────┘
- │ REST API (Vite Proxy)
-┌─────────────────────────────▼───────────────────────────────────┐
-│ Backend (FastAPI) │
-│ ┌──────────────────────────────────────────────────────────────┐│
-│ │ API Layer (v1) ││
-│ │ Auth │ Tasks │ Check-ins │ Skills │ Predictions │ Reports ││
-│ └──────────────────────────────────────────────────────────────┘│
-│ ┌──────────────────────────────────────────────────────────────┐│
-│ │ Service Layer ││
-│ │ AI Service │ Prediction │ Skill Graph │ Automation │ Notif ││
-│ └──────────────────────────────────────────────────────────────┘│
-│ ┌──────────────────────────────────────────────────────────────┐│
-│ │ Data Layer ││
-│ │ SQLAlchemy ORM │ Async SQLite/PostgreSQL ││
-│ └──────────────────────────────────────────────────────────────┘│
-└──────────────────────────────────────────────────────────────────┘
- │
- ┌─────────────────────┼─────────────────────┐
- ▼ ▼ ▼
- ┌─────────┐ ┌──────────┐ ┌──────────┐
- │ AI │ │ Database │ │ Cache │
- │ Provider│ │ SQLite │ │ (Future)│
- └─────────┘ └──────────┘ └──────────┘
-```
-
-### Tech Stack
-
-| Layer | Technology |
-|-------|------------|
-| **Frontend** | React 18, TypeScript, Vite, Zustand, Axios |
-| **Backend** | FastAPI, Python 3.11+, SQLAlchemy, Pydantic |
-| **Database** | SQLite (dev) / PostgreSQL (prod) |
-| **AI** | OpenAI / Anthropic Claude / Mock (configurable) |
-| **Deployment** | Docker, Docker Compose (coming soon) |
+**Default login**: `admin@acme.com` / `demo123`
---
-## API Documentation
-
-Interactive API documentation is available at:
-
-- **Swagger UI**: http://localhost:8000/docs
-- **ReDoc**: http://localhost:8000/redoc
-
-### Key Endpoints
-
-
-Authentication
-
-```http
-POST /api/v1/auth/register # Create new account
-POST /api/v1/auth/login # Get access tokens
-POST /api/v1/auth/refresh # Refresh access token
-GET /api/v1/auth/me # Get current user
-```
-
+## E2E Testing
-
-Tasks
+13 Playwright test suites covering 113 test cases.
-```http
-GET /api/v1/tasks # List all tasks
-POST /api/v1/tasks # Create new task
-GET /api/v1/tasks/{id} # Get task details
-PUT /api/v1/tasks/{id} # Update task
-DELETE /api/v1/tasks/{id} # Delete task
-POST /api/v1/tasks/{id}/decompose # AI task breakdown
-```
-
+```bash
+cd Frontend
-
-Check-ins
+# Run against local dev server
+npm run test:e2e
-```http
-GET /api/v1/checkins # List check-ins
-POST /api/v1/checkins # Create check-in
-GET /api/v1/checkins/{id} # Get check-in details
-```
-
+# Run against deployed app
+npm run test:e2e:deployed
-
-AI & Predictions
+# Run with visible browser
+npm run test:e2e:headed
-```http
-POST /api/v1/ai/unblock # Get AI help for blockers
-GET /api/v1/predictions/tasks/{id} # Delivery forecast
-GET /api/v1/predictions/team/{id}/velocity # Velocity trends
-```
-
+# Interactive UI mode
+npm run test:e2e:ui
-
-Workforce & Reports
-
-```http
-GET /api/v1/workforce/scores # Employee performance
-GET /api/v1/workforce/org-health # Organization metrics
-POST /api/v1/workforce/simulate # Restructuring simulation
-GET /api/v1/reports/dashboard # Dashboard data
-POST /api/v1/reports/generate # Generate report
+# View HTML report
+npx playwright show-report
```
-
----
-
-## Role-Based Access Control
-
-| Role | Capabilities |
-|------|--------------|
-| **Super Admin** | Full system access, multi-org management |
-| **Org Admin** | Organization settings, all users |
-| **Manager** | Team oversight, reports, escalations |
-| **Team Lead** | Team task management, check-ins |
-| **Employee** | Personal tasks, respond to check-ins |
-| **Viewer** | Read-only dashboard access |
+### Latest Results (Deployed App)
+
+| Suite | Tests | Status |
+|-------|-------|--------|
+| Landing Page | 7 | Pass |
+| Authentication | 8 | Pass |
+| Dashboard | 9 | 8 Pass / 1 Fail |
+| Task Creation | 6 | Pass |
+| AI Task Creator | 6 | Pass |
+| Task Management | 5 | Pass |
+| Navigation | 7 | Pass |
+| Settings | 3 | Pass |
+| Task Detail | 11 | Pass |
+| Filters & Sort | 12 | Pass |
+| Check-Ins | 13 | Pass |
+| AI Command | 9 | Pass |
+| Settings Logic | 15 | Pass |
+| **Total** | **113** | **110 Pass / 1 Fail / 2 Skip** |
---
-## Configuration
-
-### Environment Variables
+## CI/CD Pipeline
-| Variable | Description | Default |
-|----------|-------------|---------|
-| `ENVIRONMENT` | Environment mode | `development` |
-| `DATABASE_URL` | Database connection | `sqlite+aiosqlite:///./taskpulse.db` |
-| `SECRET_KEY` | JWT signing key | (auto-generated for dev) |
-| `AI_PROVIDER` | AI backend | `mock` |
-| `OPENAI_API_KEY` | OpenAI API key | - |
-| `ANTHROPIC_API_KEY` | Anthropic API key | - |
+Every push to `main` triggers automatic deployment:
-### AI Provider Setup
-
-**Mock (Default)** - No API keys needed, great for development.
-
-**OpenAI:**
-```env
-AI_PROVIDER=openai
-OPENAI_API_KEY=sk-your-key
```
-
-**Anthropic Claude:**
-```env
-AI_PROVIDER=anthropic
-ANTHROPIC_API_KEY=sk-ant-your-key
+Push to main
+ │
+ ├── Detect Changes (frontend/backend)
+ │
+ ├── Frontend: Lint & Build (ESLint + tsc + Vite)
+ │
+ ├── Backend: Unit Tests (pytest)
+ │
+ └── Deploy to Vercel Production
```
+- **Preview deploys** on every PR with auto-comment
+- **Manual trigger** via GitHub Actions UI (`workflow_dispatch`)
+- **Concurrency control** — new pushes cancel in-progress runs
+
---
## Project Structure
```
-taskpulse-ai/
+task_assistant_AI/
+├── Frontend/
+│ ├── src/
+│ │ ├── pages/ # 19 route pages
+│ │ ├── components/ # UI components (shadcn + custom)
+│ │ ├── services/ # 17 API service modules
+│ │ ├── store/ # Zustand stores (auth, theme, ui)
+│ │ ├── types/ # TypeScript types + mappers
+│ │ ├── hooks/ # React Query hooks
+│ │ └── lib/ # API client, Supabase, utils
+│ ├── e2e/ # 13 Playwright spec files
+│ ├── playwright.config.ts
+│ └── package.json
├── backend/
│ ├── app/
-│ │ ├── api/v1/ # REST API endpoints
-│ │ ├── core/ # Security, middleware
-│ │ ├── models/ # Database models
-│ │ ├── schemas/ # Pydantic schemas
-│ │ ├── services/ # Business logic
-│ │ ├── agents/ # AI agents
-│ │ └── utils/ # Helpers
-│ ├── tests/ # Test suite
-│ ├── scripts/ # Seed data, utilities
-│ ├── .env # Environment config
+│ │ ├── api/v1/ # 18 route modules
+│ │ ├── core/ # Security, middleware, permissions
+│ │ ├── models/ # 12 SQLAlchemy models
+│ │ ├── schemas/ # Pydantic request/response schemas
+│ │ ├── services/ # 17 business logic services
+│ │ └── agents/ # 5 AI agents
+│ ├── tests/ # pytest test suite
+│ ├── scripts/ # Seed data scripts
│ └── requirements.txt
-├── frontend/
-│ ├── src/
-│ │ ├── pages/ # Route pages
-│ │ ├── services/ # API clients
-│ │ ├── store/ # State management
-│ │ ├── types/ # TypeScript types
-│ │ └── lib/ # Utilities
-│ ├── package.json
-│ └── vite.config.ts
-├── start.sh # Quick start script
-├── INTEGRATION.md # Integration guide
-└── README.md
+├── api/
+│ └── index.py # Vercel serverless entry point
+├── .github/workflows/
+│ └── ci-cd.yml # CI/CD pipeline
+├── docs/
+│ ├── reports/ # Test & audit reports
+│ └── screenshots/ # UI screenshots
+├── vercel.json # Vercel deploy config
+├── docker-compose.yml # Docker services
+└── CLAUDE.md # Development rules
```
---
-## Development
+## API Endpoints
+
+
+Authentication
-### Running Tests
+| Method | Endpoint | Description |
+|--------|----------|-------------|
+| `POST` | `/api/v1/auth/register` | Create new account |
+| `POST` | `/api/v1/auth/login` | Get access tokens |
+| `GET` | `/api/v1/auth/me` | Get current user |
+| `POST` | `/api/v1/auth/google` | Google OAuth login |
+| `POST` | `/api/v1/auth/refresh` | Refresh access token |
+| `POST` | `/api/v1/auth/logout` | Logout current session |
+| `POST` | `/api/v1/auth/change-password` | Change password |
+| `GET` | `/api/v1/auth/sessions` | List active sessions |
-```bash
-# Backend tests
-cd backend
-pytest
+
-# With coverage
-pytest --cov=app --cov-report=html
-```
+
+Tasks
-### Code Quality
+| Method | Endpoint | Description |
+|--------|----------|-------------|
+| `GET` | `/api/v1/tasks` | List tasks (filterable) |
+| `POST` | `/api/v1/tasks` | Create task |
+| `GET` | `/api/v1/tasks/{id}` | Get task details |
+| `PUT` | `/api/v1/tasks/{id}` | Update task |
+| `DELETE` | `/api/v1/tasks/{id}` | Delete task |
+| `POST` | `/api/v1/tasks/{id}/decompose` | AI decomposition |
+| `POST` | `/api/v1/tasks/{id}/subtasks` | Create subtask |
+| `POST` | `/api/v1/tasks/{id}/comments` | Add comment |
+| `GET` | `/api/v1/tasks/{id}/history` | Task change history |
+| `POST` | `/api/v1/tasks/bulk/update` | Bulk update |
-```bash
-# Backend linting
-cd backend
-flake8 app/
-black app/
+
-# Frontend linting
-cd frontend
-npm run lint
-```
+
+Check-Ins
+
+| Method | Endpoint | Description |
+|--------|----------|-------------|
+| `GET` | `/api/v1/checkins` | List check-ins |
+| `GET` | `/api/v1/checkins/pending` | Pending check-ins |
+| `POST` | `/api/v1/checkins/{id}/respond` | Submit response |
+| `POST` | `/api/v1/checkins/{id}/skip` | Skip check-in |
+| `POST` | `/api/v1/checkins/{id}/escalate` | Escalate blocker |
+| `GET` | `/api/v1/checkins/config` | Get config |
+| `GET` | `/api/v1/checkins/statistics` | Check-in stats |
----
+
-## Roadmap
-
-- [x] **Core Task Management** - CRUD operations, status tracking
-- [x] **Authentication & Authorization** - JWT-based auth, RBAC
-- [x] **Check-in System** - Proactive engagement loops
-- [x] **AI Unblock Engine** - RAG-powered assistance
-- [x] **Skill Graph** - Automatic skill inference
-- [x] **Prediction Engine** - ML-powered forecasting
-- [ ] **Slack/Teams Integration** - Check-ins where your team works
-- [ ] **Mobile App** - iOS and Android native apps
-- [ ] **Advanced Analytics** - Custom report builder
-- [ ] **SSO/SAML** - Enterprise authentication
-- [ ] **Multi-language Support** - i18n for global teams
-- [ ] **API Webhooks** - External integrations
+
+AI & Chat
----
+| Method | Endpoint | Description |
+|--------|----------|-------------|
+| `POST` | `/api/v1/ai/unblock` | AI unblock assistance |
+| `GET` | `/api/v1/ai/documents` | Knowledge base docs |
+| `POST` | `/api/v1/chat` | Send chat message |
+| `GET` | `/api/v1/chat/conversations` | List conversations |
-## Contributing
+
-We welcome contributions! Here's how to get started:
+
+Skills, Predictions, Workforce
+
+| Method | Endpoint | Description |
+|--------|----------|-------------|
+| `GET` | `/api/v1/skills` | Skill catalog |
+| `GET` | `/api/v1/skills/{userId}/graph` | Skill graph |
+| `GET` | `/api/v1/skills/{userId}/gaps` | Skill gaps |
+| `GET` | `/api/v1/predictions/tasks/{id}` | Delivery forecast |
+| `GET` | `/api/v1/predictions/team/{id}/velocity` | Velocity forecast |
+| `GET` | `/api/v1/workforce/scores` | Performance scores |
+| `GET` | `/api/v1/workforce/org-health` | Org health index |
+| `POST` | `/api/v1/workforce/simulations` | Restructuring sim |
-1. **Fork** the repository
-2. **Create** a feature branch (`git checkout -b feature/amazing-feature`)
-3. **Commit** your changes (`git commit -m 'Add amazing feature'`)
-4. **Push** to the branch (`git push origin feature/amazing-feature`)
-5. **Open** a Pull Request
+
+
+
+Automation & Integrations
+
+| Method | Endpoint | Description |
+|--------|----------|-------------|
+| `GET` | `/api/v1/automation/patterns` | Detected patterns |
+| `POST` | `/api/v1/automation/agents` | Create agent |
+| `GET` | `/api/v1/automation/roi` | ROI dashboard |
+| `GET` | `/api/v1/integrations` | List integrations |
+| `POST` | `/api/v1/integrations` | Create integration |
+| `POST` | `/api/v1/integrations/{id}/test` | Test connection |
+| `GET` | `/api/v1/webhooks` | List webhooks |
+
+
+
+---
+
+## Security
+
+- **JWT Authentication** with refresh token rotation
+- **bcrypt Password Hashing** with complexity requirements (8+ chars, uppercase, etc.)
+- **Role-Based Access Control** (6 roles: Super Admin to Viewer)
+- **Permission Guards** on all API endpoints
+- **Secret Redaction** in API responses (SMTP passwords, tokens)
+- **CORS Protection** with configurable origins
+- **Rate Limiting** on authentication endpoints
+- **Input Validation** via Pydantic schemas
+- **SQL Injection Prevention** via SQLAlchemy ORM
+- **XSS Protection** via React's built-in escaping
---
-## License
+## Role-Based Access Control
-This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
+| Role | Tasks | Check-Ins | Team | Reports | Admin |
+|------|-------|-----------|------|---------|-------|
+| **Super Admin** | Full | Full | Full | Full | Full |
+| **Org Admin** | Full | Full | Full | Full | Org Settings |
+| **Manager** | Team | Team | View | Full | - |
+| **Team Lead** | Team | Team | View | Team | - |
+| **Employee** | Own | Own | - | Own | - |
+| **Viewer** | Read | Read | - | Read | - |
---
-## Support
+## Contributing
+
+All changes follow the **Issue -> Branch -> PR** workflow:
-- **Documentation**: See [INTEGRATION.md](INTEGRATION.md) for detailed setup
-- **Issues**: Report bugs on [GitHub Issues](https://github.com/shibinsp/taskpulse-ai/issues)
-- **Discussions**: Join our [GitHub Discussions](https://github.com/shibinsp/taskpulse-ai/discussions)
+1. **Create a GitHub Issue** describing the change
+2. **Create a branch**: `fix/issue-42-description` or `feat/issue-43-feature`
+3. **Implement** the fix/feature
+4. **Create a PR** with `Fixes #` in the body
+5. **CI passes** -> **Merge** to `main` -> **Auto-deploy** to Vercel
---
- Built with passion for productive teams everywhere.
-
-
-
-
-
-
-
-
+ Built by shibinsp • Powered by Beeax
diff --git a/docs/reports/TaskPulse_Project_Overview.xlsx b/docs/reports/TaskPulse_Project_Overview.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..b6587bcc01d4753050f798391e2ffa29ac70af64
GIT binary patch
literal 24661
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%0D6)+z
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
a|LDn7