Hemish Jain Claude Opus 4.8 commited on
Commit
7dff413
·
1 Parent(s): 4f033eb

chore: untrack .gsd planning workspace and scratch notes

Browse files

- gitignore .gsd/ and "mds hi mds/"
- remove both from tracking (kept on disk)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +6 -0
  2. .gsd/DECISIONS.md +0 -50
  3. .gsd/JOURNAL.md +0 -21
  4. .gsd/REQUIREMENTS.md +0 -28
  5. .gsd/ROADMAP.md +0 -106
  6. .gsd/SPEC.md +0 -63
  7. .gsd/STATE.md +0 -21
  8. .gsd/TODO.md +0 -3
  9. .gsd/examples/cross-platform.md +0 -99
  10. .gsd/examples/multi-wave-workflow.md +0 -256
  11. .gsd/examples/quick-reference.md +0 -73
  12. .gsd/examples/workflow-example.md +0 -139
  13. .gsd/phases/1/1-PLAN.md +0 -162
  14. .gsd/phases/1/1-SUMMARY.md +0 -18
  15. .gsd/phases/1/2-PLAN.md +0 -129
  16. .gsd/phases/1/2-SUMMARY.md +0 -16
  17. .gsd/phases/1/3-PLAN.md +0 -144
  18. .gsd/phases/1/3-SUMMARY.md +0 -25
  19. .gsd/phases/10/1-PLAN.md +0 -46
  20. .gsd/phases/2/1-PLAN.md +0 -170
  21. .gsd/phases/2/1-SUMMARY.md +0 -11
  22. .gsd/phases/2/2-PLAN.md +0 -153
  23. .gsd/phases/2/2-SUMMARY.md +0 -13
  24. .gsd/phases/2/3-PLAN.md +0 -208
  25. .gsd/phases/2/3-SUMMARY.md +0 -15
  26. .gsd/phases/2/RESEARCH.md +0 -70
  27. .gsd/phases/3/1-PLAN.md +0 -113
  28. .gsd/phases/3/1-SUMMARY.md +0 -14
  29. .gsd/phases/3/2-PLAN.md +0 -195
  30. .gsd/phases/3/2-SUMMARY.md +0 -11
  31. .gsd/phases/3/3-PLAN.md +0 -169
  32. .gsd/phases/3/3-SUMMARY.md +0 -14
  33. .gsd/phases/4/1-PLAN.md +0 -121
  34. .gsd/phases/4/1-SUMMARY.md +0 -2
  35. .gsd/phases/4/2-PLAN.md +0 -171
  36. .gsd/phases/4/2-SUMMARY.md +0 -2
  37. .gsd/phases/4/3-PLAN.md +0 -118
  38. .gsd/phases/4/3-SUMMARY.md +0 -2
  39. .gsd/phases/6/1-PLAN.md +0 -56
  40. .gsd/phases/6/1-SUMMARY.md +0 -2
  41. .gsd/phases/6/2-PLAN.md +0 -53
  42. .gsd/phases/6/2-SUMMARY.md +0 -2
  43. .gsd/phases/6/3-PLAN.md +0 -56
  44. .gsd/phases/6/3-SUMMARY.md +0 -2
  45. .gsd/phases/6/VERIFICATION.md +0 -8
  46. .gsd/phases/7/1-PLAN.md +0 -54
  47. .gsd/phases/7/1-SUMMARY.md +0 -2
  48. .gsd/phases/7/2-PLAN.md +0 -45
  49. .gsd/phases/7/2-SUMMARY.md +0 -2
  50. .gsd/phases/7/3-PLAN.md +0 -44
.gitignore CHANGED
@@ -48,3 +48,9 @@ models_cache/
48
  # Generated knowledge graph + local agent instructions
49
  graphify-out/
50
  CLAUDE.md
 
 
 
 
 
 
 
48
  # Generated knowledge graph + local agent instructions
49
  graphify-out/
50
  CLAUDE.md
51
+
52
+ # Scratch notes folder
53
+ mds hi mds/
54
+
55
+ # GSD planning workspace
56
+ .gsd/
.gsd/DECISIONS.md DELETED
@@ -1,50 +0,0 @@
1
- # DECISIONS.md — Architecture Decision Records
2
-
3
- ## ADR-001: FastAPI Backend
4
- **Date**: 2026-03-27
5
- **Status**: Accepted
6
- **Context**: Need a Python backend framework that supports async, has great ML ecosystem interop, and is hackathon-fast to develop.
7
- **Decision**: Use FastAPI with uvicorn.
8
- **Rationale**: Async support, automatic OpenAPI docs, Pydantic validation, seamless Python ML library integration.
9
-
10
- ## ADR-002: Plain HTML/CSS/JS Frontend
11
- **Date**: 2026-03-27
12
- **Status**: Accepted
13
- **Context**: Need a frontend approach that's fast to build, has no build step, and works for a hackathon demo.
14
- **Decision**: Use vanilla HTML, CSS, and JavaScript — no framework.
15
- **Rationale**: Zero setup overhead, instant iteration, no dependency management. Can upgrade to a framework later if needed.
16
-
17
- ## ADR-003: SQLite Database
18
- **Date**: 2026-03-27
19
- **Status**: Accepted
20
- **Context**: Need persistence for analysis results without infrastructure overhead.
21
- **Decision**: Use SQLite via SQLAlchemy.
22
- **Rationale**: Zero-config, file-based, perfect for local-first demo. Trivially swappable for PostgreSQL later.
23
-
24
- ## ADR-004: Local LLM for Internal Team Data
25
- **Date**: 2026-03-27
26
- **Status**: Accepted
27
- **Context**: Internal team skills and project data is confidential — cannot send to external APIs.
28
- **Decision**: Use local LLM (Ollama / LM Studio) for internal team analysis features.
29
- **Rationale**: Keeps company data on-premise. Achieves confidentiality without sacrificing AI capability.
30
-
31
- ## ADR-005: GitHub REST API with PAT
32
- **Date**: 2026-03-27
33
- **Status**: Accepted
34
- **Context**: Need to fetch developer activity data from GitHub.
35
- **Decision**: Use GitHub REST API with a Personal Access Token for higher rate limits.
36
- **Rationale**: Simple, well-documented, sufficient for demo. PAT gives 5000 req/hour vs 60 unauthenticated.
37
-
38
- ## ADR-006: LeetCode GraphQL Endpoint
39
- **Date**: 2026-03-27
40
- **Status**: Accepted
41
- **Context**: LeetCode has no official public API, but community-documented GraphQL endpoints exist.
42
- **Decision**: Use LeetCode's GraphQL endpoint for fetching user problem-solving data.
43
- **Rationale**: Provides structured data (problems by difficulty, submission stats) without scraping HTML.
44
-
45
- ## ADR-007: Public Salary Datasets for Benchmarking
46
- **Date**: 2026-03-27
47
- **Status**: Accepted
48
- **Context**: Need salary estimation without paid API subscriptions.
49
- **Decision**: Use Levels.fyi public dataset and GitHub Jobs archive for salary ranges.
50
- **Rationale**: Free, credible sources. Combined with skill match + experience + location → market-rate estimation.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/JOURNAL.md DELETED
@@ -1,21 +0,0 @@
1
- # JOURNAL.md — Development Journal
2
-
3
- ## 2026-03-27 — Project Initialization
4
-
5
- ### What happened
6
- - Ran `/new-project` workflow
7
- - Deep questioning with comprehensive project brief
8
- - Finalized SPEC.md with 5 goals, clear non-goals, and success criteria
9
- - Created 22 testable requirements in REQUIREMENTS.md
10
- - Designed 5-phase ROADMAP.md
11
- - Documented 7 architecture decisions in DECISIONS.md
12
-
13
- ### Key insights
14
- - The project is a hackathon build but should feel production-grade
15
- - Internal team data requires local LLM for confidentiality
16
- - Resume inflation detection is the "wow factor" demo feature
17
- - Salary benchmarking turns recommendations into business cases
18
-
19
- ### Next steps
20
- - Run `/plan 1` to create Phase 1 execution plan
21
- - Start with project structure, FastAPI skeleton, and SQLite models
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/REQUIREMENTS.md DELETED
@@ -1,28 +0,0 @@
1
- # REQUIREMENTS.md
2
-
3
- ## Format
4
-
5
- | ID | Requirement | Source | Status |
6
- |----|-------------|--------|--------|
7
- | REQ-01 | Parse PDF resumes and extract structured fields (name, skills, projects, experience, links) | SPEC Goal 1 | Pending |
8
- | REQ-02 | Fetch GitHub profile data via REST API: repos, commits, languages, stars, activity timeline | SPEC Goal 1 | Pending |
9
- | REQ-03 | Compute GitHub-derived scores: consistency, project depth, tech breadth, recency | SPEC Goal 1 | Pending |
10
- | REQ-04 | Fetch LeetCode profile data via GraphQL: problems solved by difficulty, streaks | SPEC Goal 1 | Pending |
11
- | REQ-05 | Compute skill similarity between candidate and job description using sentence embeddings | SPEC Goal 1 | Pending |
12
- | REQ-06 | Generate overall match score with matched/missing skill breakdown | SPEC Goal 1 | Pending |
13
- | REQ-07 | Predict learning ability for each missing skill using transfer graph + behavioral modifiers | SPEC Goal 2 | Pending |
14
- | REQ-08 | Classify learning speed (Fast/Medium/Slow) with time estimates per skill | SPEC Goal 2 | Pending |
15
- | REQ-09 | Compare claimed skills (resume) vs verified activity (GitHub/LeetCode) to compute credibility scores | SPEC Goal 3 | Pending |
16
- | REQ-10 | Flag specific resume inflation patterns with human-readable explanations | SPEC Goal 3 | Pending |
17
- | REQ-11 | Accept team skills + project requirements as input for internal analysis | SPEC Goal 4 | Pending |
18
- | REQ-12 | Compute skill coverage score and identify missing capabilities | SPEC Goal 4 | Pending |
19
- | REQ-13 | Cluster skill gaps by domain (DevOps, Frontend, ML, Backend) | SPEC Goal 4 | Pending |
20
- | REQ-14 | Generate hire plan with urgency levels | SPEC Goal 4 | Pending |
21
- | REQ-15 | Auto-generate job descriptions from skill gaps | SPEC Goal 4 | Pending |
22
- | REQ-16 | Estimate salary ranges using public datasets (Levels.fyi, GitHub Jobs archive) | SPEC Goal 5 | Pending |
23
- | REQ-17 | Include budget impact in hire plan recommendations | SPEC Goal 5 | Pending |
24
- | REQ-18 | Every score provides contributing factors and reasoning explanation | SPEC Goal 5 | Pending |
25
- | REQ-19 | Store analysis results in SQLite for retrieval and comparison | SPEC Goal 5 | Pending |
26
- | REQ-20 | Web dashboard with candidate analysis view and team analysis view | SPEC Goal 5 | Pending |
27
- | REQ-21 | Process internal team data using local LLM only (no external API calls) | SPEC Constraint | Pending |
28
- | REQ-22 | Full system runs locally without cloud dependencies | SPEC Constraint | Pending |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/ROADMAP.md DELETED
@@ -1,106 +0,0 @@
1
- # ROADMAP.md
2
-
3
- > **Current Phase**: Not started
4
- > **Milestone**: v1.0 — Hackathon MVP
5
-
6
- ## Must-Haves (from SPEC)
7
- - [ ] Resume parsing → structured candidate profile
8
- - [ ] GitHub analysis → consistency, depth, breadth, recency scores
9
- - [ ] LeetCode analysis → problem-solving metrics
10
- - [ ] Skill similarity matching (semantic)
11
- - [ ] Learning ability prediction with time estimates
12
- - [ ] Resume inflation detection with credibility flags
13
- - [ ] Internal skill gap analyzer → hire plan + JD generation
14
- - [ ] Salary benchmarking integrated into hire plan
15
- - [ ] Explainable scoring (every output has reasoning)
16
- - [ ] Web dashboard (candidate view + team view)
17
- - [ ] SQLite persistence
18
- - [ ] Fully local deployment
19
-
20
- ## Phases
21
-
22
- ### Phase 1: Project Foundation & Backend Skeleton
23
- **Status**: ✅ Complete
24
- **Objective**: Set up the FastAPI project structure, SQLite database, configuration, and API scaffolding. Create the frontend shell with navigation between candidate analysis and team analysis views.
25
- **Requirements**: REQ-19, REQ-20, REQ-22
26
- **Deliverable**: Running FastAPI server with health check, SQLite models, and frontend shell with two-view layout.
27
-
28
- ---
29
-
30
- ### Phase 2: Resume Parser + GitHub & LeetCode Analyzers
31
- **Status**: ✅ Complete
32
- **Objective**: Build the three data ingestion modules — PDF resume parser (structured extraction), GitHub REST API analyzer (4 scores), and LeetCode GraphQL analyzer (difficulty-weighted metrics). Wire them into the API.
33
- **Requirements**: REQ-01, REQ-02, REQ-03, REQ-04
34
- **Deliverable**: Upload a resume → extracted profile with GitHub/LeetCode data fetched and scored.
35
-
36
- ---
37
-
38
- ### Phase 3: ML Engine — Skill Matching, Learning Prediction & Inflation Detection
39
- **Status**: ✅ Complete
40
- **Objective**: Build the core intelligence layer — semantic skill similarity (sentence embeddings), learning ability predictor (transfer graph + speed modifiers), and resume inflation detector (cross-reference claimed vs verified). Every score includes explainability.
41
- **Requirements**: REQ-05, REQ-06, REQ-07, REQ-08, REQ-09, REQ-10, REQ-18
42
- **Deliverable**: Given a candidate profile + job description → full analysis report with match score, learning estimates, credibility flags, and explanations.
43
-
44
- ---
45
-
46
- ### Phase 4: Internal Skill Gap Analyzer + Salary Benchmarking
47
- **Status**: ✅ Complete
48
- **Objective**: Build the team-side analysis — accept team skills + project requirements, compute coverage, identify gaps by domain, generate hire plan with urgency, auto-generate JDs, and integrate salary benchmarking from public datasets. Internal data processed via local LLM.
49
- **Requirements**: REQ-11, REQ-12, REQ-13, REQ-14, REQ-15, REQ-16, REQ-17, REQ-21
50
- **Deliverable**: Input team + project → skill coverage, gap clusters, hire plan with salary estimates, and ready-to-post JDs.
51
-
52
- ---
53
-
54
- ### Phase 5: Dashboard Polish & Demo Integration
55
- **Status**: ⬜ Not Started
56
- **Objective**: Build the complete frontend dashboard — candidate analysis flow (upload → instant report), team analysis flow (input → hire plan), result persistence, comparison views, and demo-ready polish (animations, responsive layout, error states).
57
- **Requirements**: REQ-19, REQ-20
58
- **Deliverable**: End-to-end working demo: upload resume → see full analysis; input team → see hire plan. Production-quality UI.
59
-
60
- ---
61
-
62
- ### Phase 6: Modern React UI Migration (Shadcn + Tailwind)
63
- **Status**: ✅ Complete
64
- **Objective**: Build a visually stunning landing page and migrate the dashboard to React, Tailwind, and Shadcn UI. Implement `BackgroundPaths` and `HeroSection` components. Replace emojis with Phosphor/Lucide icons.
65
- **Depends on**: Phase 5
66
-
67
- ---
68
-
69
- ### Phase 7: Connect Frontend and Backend (Dashboard Migration)
70
- **Status**: ✅ Complete
71
- **Objective**: Build out the Next.js `/dashboard` route, abstract API fetches with React paradigms (connecting to `localhost:8000`), and construct the rich shadcn-based result cards for Candidate and Team Gap analysis, bringing full functional parity to the React rollout.
72
- **Depends on**: Phase 6
73
-
74
- ---
75
-
76
- ### Phase 8: LLM Semantic Mapping & Advanced UI (Radar/Bulk Upload)
77
- **Status**: ✅ Complete
78
- **Objective**: Integrate the Gemini API to intelligently map abstract skill relationships (e.g., NLP vs BERT) by feeding it repo metadata (README/requirements files). Implement Candidate Radar Charts on the frontend for visual capability assessment, and add a Mass PDF Uploader to the Team gap analysis page to parse an entire team simultaneously.
79
- **Depends on**: Phase 7
80
-
81
- ---
82
-
83
- ### Phase 9: Shadcn UI Enhancements (Radar Chart and Verification Badges)
84
- **Status**: ✅ Complete
85
- **Objective**: Replace the current Recharts radar chart with a highly polished Shadcn-based "Radar Chart - Dots". Add a verification badge UI component to clearly display the status of GitHub parsing (tick/dash/cross), LeetCode parsing (tick/dash/cross), and Gemini semantic analysis (tick/cross).
86
- **Depends on**: Phase 8
87
-
88
- **Tasks**:
89
- - [ ] Plan 9.1: Shadcn Chart Integration
90
- - [ ] Plan 9.2: Implement Shadcn Radar Chart and Verification Badges
91
-
92
- **Verification**:
93
- - TBD
94
-
95
- ---
96
- ### Phase 10: Team Gap Analysis UI Overhaul
97
- **Status**: ⬜ Not Started
98
- **Objective**: Redesign the Team Gap Analysis view to match the premium aesthetics of the new Candidate dashboard and Shadcn visual design system.
99
- **Depends on**: Phase 9
100
-
101
- **Tasks**:
102
- - [ ] TBD (run /plan 10 to create)
103
-
104
- **Verification**:
105
- - TBD
106
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/SPEC.md DELETED
@@ -1,63 +0,0 @@
1
- # SPEC.md — Project Specification
2
-
3
- > **Status**: `FINALIZED`
4
- > **Project**: HireSense AI — Intelligent Hiring & Workforce Planning System
5
-
6
- ## Vision
7
-
8
- HireSense AI replaces resume-based hiring with a multi-signal intelligence system that evaluates real coding behavior, verified technical activity, learning ability, and team-level skill gaps. It transforms hiring from guesswork into data-driven decision making — purpose-built for early-stage startups that lack dedicated HR teams.
9
-
10
- ## Goals
11
-
12
- 1. **Multi-Signal Candidate Analysis** — Fuse resume data with GitHub activity, LeetCode performance, and skill similarity to produce a holistic candidate score with full explainability.
13
- 2. **Learning Ability Prediction** — Predict how fast a candidate can acquire missing skills using a transfer graph and behavioral modifiers (GitHub consistency, problem-solving depth, recency).
14
- 3. **Resume Authenticity Detection** — Cross-reference claimed skills against verified external signals to flag inflation and inconsistencies.
15
- 4. **Internal Skill Gap Analysis** — Analyze existing team skills against project requirements to identify gaps, generate hire plans with urgency levels, and auto-generate job descriptions.
16
- 5. **Actionable Hiring Intelligence** — Produce explainable reports with salary benchmarks, turning recommendations into business cases a CTO can act on.
17
-
18
- ## Non-Goals (Out of Scope for v1.0)
19
-
20
- - Candidate Trajectory Score (growth trend analysis over time)
21
- - Team Culture Fit Heuristic (behavioral inference from GitHub)
22
- - AI Interviewer (custom question generation)
23
- - User authentication / multi-tenant access control
24
- - Cloud deployment / CI/CD pipeline
25
- - Mobile application
26
- - Integration with ATS (Applicant Tracking Systems)
27
-
28
- ## Users
29
-
30
- - **Primary**: Technical founders, CTOs, and small hiring teams at early-stage startups
31
- - **Workflow**: Upload a resume + paste a job description → get instant analysis with match score, learning ability, credibility, and explanations
32
- - **Team mode**: Input team skills + project requirements → get coverage analysis, skill gaps, hire plan, and auto-generated JDs
33
-
34
- ## Tech Stack
35
-
36
- | Layer | Choice | Rationale |
37
- | ---------------- | ----------------------------------------------------- | ---------------------------------------------- |
38
- | Backend | **FastAPI** (Python) | Fast async API, Python ML ecosystem |
39
- | Frontend | **Plain HTML/CSS/JS** | Lightweight, hackathon-friendly, no build step |
40
- | Database | **SQLite** | Zero-config, local-first, sufficient for demo |
41
- | ML/NLP | **sentence-transformers**, scikit-learn, spaCy | Semantic similarity, feature engineering |
42
- | Resume Parsing | **pdfplumber** + spaCy + regex | Structured extraction from PDFs |
43
- | GitHub Data | **GitHub REST API** (with PAT) | Rich developer activity signals |
44
- | LeetCode Data | **GraphQL endpoint** | Problem-solving metrics |
45
- | Salary Data | **Public datasets** (Levels.fyi, GitHub Jobs archive) | Market salary estimation |
46
- | Internal Team AI | **Local LLM** (LM Studio / Ollama) | Confidentiality for company data |
47
-
48
- ## Constraints
49
-
50
- - **Local-only deployment** — must run entirely on localhost for hackathon demo
51
- - **No paid API dependencies** — all data sources must be free/public
52
- - **Hackathon timeline** — production-quality code but MVP scope
53
- - **Confidentiality** — internal team data processed by local AI only, never sent to external APIs
54
-
55
- ## Success Criteria
56
-
57
- - [ ] Upload a resume PDF → get structured candidate profile with scores in < 30 seconds
58
- - [ ] Match score accurately reflects skill overlap with job description (semantic, not keyword)
59
- - [ ] Learning ability prediction produces actionable time estimates per missing skill
60
- - [ ] Resume inflation detector flags at least 3 categories of inconsistency
61
- - [ ] Internal skill gap analyzer produces hire plan with budget estimates
62
- - [ ] Every score includes human-readable explanation (no black boxes)
63
- - [ ] Full end-to-end demo runs locally without external service dependencies (except GitHub/LeetCode APIs)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/STATE.md DELETED
@@ -1,21 +0,0 @@
1
- # STATE.md — Project Memory
2
-
3
- > **Last Updated**: 2026-03-29
4
- > **Current Phase**: 10
5
- > **Active Task**: Planning required
6
-
7
- ## Current Position
8
- - **Phase**: 10
9
- - **Task**: Creating plans
10
- - **Status**: TBD
11
-
12
- ## Last Session Summary
13
- Added Phase 10 to overhaul the Team Gap Analysis frontend UI to match Shadcn visual guidelines. Fixed the double score render bug in the candidate executive summary.
14
-
15
- ## Next Steps
16
- 1. /plan 10
17
-
18
- ## Known Issues
19
- _None_
20
-
21
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/TODO.md DELETED
@@ -1,3 +0,0 @@
1
- # TODO.md — Pending Items
2
-
3
- _No pending items yet._
 
 
 
 
.gsd/examples/cross-platform.md DELETED
@@ -1,99 +0,0 @@
1
- # Cross-Platform Commands Reference
2
-
3
- > PowerShell ↔ Bash equivalents for GSD workflows
4
-
5
- ## Common Operations
6
-
7
- | Operation | PowerShell | Bash |
8
- |-----------|------------|------|
9
- | **Test file exists** | `Test-Path "file.md"` | `test -f "file.md"` |
10
- | **Test directory exists** | `Test-Path "dir" -PathType Container` | `test -d "dir"` |
11
- | **Create directory** | `New-Item -ItemType Directory -Path "dir"` | `mkdir -p "dir"` |
12
- | **List files** | `Get-ChildItem "*.md"` | `ls *.md` |
13
- | **List recursively** | `Get-ChildItem -Recurse` | `find . -type f` |
14
- | **Read file** | `Get-Content "file.md"` | `cat "file.md"` |
15
- | **Search in files** | `Select-String -Path "**/*" -Pattern "TODO"` | `grep -r "TODO" .` |
16
- | **Count lines** | `(Get-Content file).Count` | `wc -l < file` |
17
- | **Copy files** | `Copy-Item -Recurse src dest` | `cp -r src dest` |
18
- | **Delete files** | `Remove-Item -Recurse -Force dir` | `rm -rf dir` |
19
-
20
- ## Git Operations (Same on Both)
21
-
22
- ```bash
23
- git add -A
24
- git commit -m "message"
25
- git push
26
- git status --short
27
- ```
28
-
29
- ## Workflow-Specific Examples
30
-
31
- ### /map — Analyze Codebase
32
-
33
- **PowerShell:**
34
- ```powershell
35
- Get-ChildItem -Recurse -Directory |
36
- Where-Object { $_.Name -notmatch "node_modules|\.git" }
37
- ```
38
-
39
- **Bash:**
40
- ```bash
41
- find . -type d ! -path "*/node_modules/*" ! -path "*/.git/*"
42
- ```
43
-
44
- ---
45
-
46
- ### /plan — Check SPEC Status
47
-
48
- **PowerShell:**
49
- ```powershell
50
- $spec = Get-Content ".gsd/SPEC.md" -Raw
51
- if ($spec -match "FINALIZED") { "Ready" }
52
- ```
53
-
54
- **Bash:**
55
- ```bash
56
- if grep -q "FINALIZED" .gsd/SPEC.md; then echo "Ready"; fi
57
- ```
58
-
59
- ---
60
-
61
- ### /execute — Discover Plans
62
-
63
- **PowerShell:**
64
- ```powershell
65
- Get-ChildItem ".gsd/phases/1/*-PLAN.md"
66
- ```
67
-
68
- **Bash:**
69
- ```bash
70
- ls .gsd/phases/1/*-PLAN.md 2>/dev/null
71
- ```
72
-
73
- ---
74
-
75
- ### /verify — Search TODOs
76
-
77
- **PowerShell:**
78
- ```powershell
79
- Select-String -Path "src/**/*" -Pattern "TODO|FIXME"
80
- ```
81
-
82
- **Bash:**
83
- ```bash
84
- grep -rn "TODO\|FIXME" src/
85
- ```
86
-
87
- ---
88
-
89
- ## Environment Detection
90
-
91
- Add this to workflows for cross-platform commands:
92
-
93
- ```markdown
94
- **Note:** Commands shown are PowerShell. For Bash equivalents, see `.gsd/examples/cross-platform.md`
95
- ```
96
-
97
- ---
98
-
99
- *Reference for Linux/Mac users*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/examples/multi-wave-workflow.md DELETED
@@ -1,256 +0,0 @@
1
- # Multi-Wave Workflow Example
2
-
3
- This example demonstrates a complete GSD workflow with:
4
- - Short spec
5
- - Plan breakdown
6
- - 2-wave execution
7
- - Verification with commands
8
- - State snapshots
9
-
10
- ---
11
-
12
- ## Example: Add User Authentication
13
-
14
- ### 1. SPEC.md (Finalized)
15
-
16
- ```markdown
17
- ---
18
- status: FINALIZED
19
- updated: 2026-02-07
20
- ---
21
-
22
- # User Authentication Feature
23
-
24
- ## Overview
25
- Add login/logout functionality with JWT tokens.
26
-
27
- ## Requirements
28
- 1. POST /api/auth/login endpoint
29
- 2. POST /api/auth/logout endpoint
30
- 3. JWT stored in httpOnly cookie
31
- 4. Protected route middleware
32
-
33
- ## Success Criteria
34
- - User can login with email/password
35
- - Invalid credentials return 401
36
- - Protected routes require valid JWT
37
- - Logout clears the cookie
38
- ```
39
-
40
- ---
41
-
42
- ### 2. ROADMAP.md (Phase Entry)
43
-
44
- ```markdown
45
- ## Phase 1: User Authentication
46
-
47
- - [ ] Plan 1.1: Auth endpoints (Wave 1)
48
- - [ ] Plan 1.2: Protected middleware (Wave 2)
49
- ```
50
-
51
- ---
52
-
53
- ### 3. PLAN 1.1 (Wave 1)
54
-
55
- ```xml
56
- ---
57
- phase: 1
58
- plan: 1
59
- type: implementation
60
- wave: 1
61
- ---
62
-
63
- <objective>
64
- Create login and logout endpoints with JWT handling.
65
- </objective>
66
-
67
- <context>
68
- Files to read: src/app/api/ structure, existing auth if any
69
- </context>
70
-
71
- <tasks>
72
- <task type="auto" effort="medium">
73
- <name>Create login endpoint</name>
74
- <files>src/app/api/auth/login/route.ts</files>
75
- <action>
76
- Create POST handler accepting {email, password}.
77
- Query users table, compare password with bcrypt.
78
- On success: generate JWT, set httpOnly cookie, return 200.
79
- On failure: return 401 with generic error.
80
- </action>
81
- <verify>curl -X POST localhost:3000/api/auth/login -d '{"email":"test@example.com","password":"test123"}'</verify>
82
- <done>Valid credentials return 200 + Set-Cookie header</done>
83
- </task>
84
-
85
- <task type="auto" effort="low">
86
- <name>Create logout endpoint</name>
87
- <files>src/app/api/auth/logout/route.ts</files>
88
- <action>
89
- Create POST handler that clears the auth cookie.
90
- Return 200 on success.
91
- </action>
92
- <verify>curl -X POST localhost:3000/api/auth/logout --cookie "token=..."</verify>
93
- <done>Cookie is cleared, response is 200</done>
94
- </task>
95
- </tasks>
96
- ```
97
-
98
- ---
99
-
100
- ### 4. Wave 1 Execution
101
-
102
- **Task 1 Commit:**
103
- ```
104
- git commit -m "feat(phase-1): create login endpoint"
105
- ```
106
-
107
- **Task 2 Commit:**
108
- ```
109
- git commit -m "feat(phase-1): create logout endpoint"
110
- ```
111
-
112
- ---
113
-
114
- ### 5. Wave 1 State Snapshot
115
-
116
- ```markdown
117
- ---
118
- wave: 1
119
- phase: 1
120
- created: 2026-02-07T10:30:00
121
- status: complete
122
- ---
123
-
124
- # Wave 1 State Snapshot
125
-
126
- ## Objective
127
- Create authentication endpoints.
128
-
129
- ## Changes Realized
130
- - Created login endpoint with JWT generation
131
- - Created logout endpoint with cookie clearing
132
- - Added bcrypt password comparison
133
-
134
- ## Files Touched
135
- | File | Change Type | Description |
136
- |------|-------------|-------------|
137
- | src/app/api/auth/login/route.ts | created | Login handler |
138
- | src/app/api/auth/logout/route.ts | created | Logout handler |
139
-
140
- ## Verification Results
141
- | Check | Command | Result |
142
- |-------|---------|--------|
143
- | Login works | `curl -X POST .../login` | ✅ 200 + cookie |
144
- | Logout works | `curl -X POST .../logout` | ✅ 200 + cleared |
145
-
146
- ## Commits in This Wave
147
- | Hash | Message |
148
- |------|---------|
149
- | abc123 | feat(phase-1): create login endpoint |
150
- | def456 | feat(phase-1): create logout endpoint |
151
-
152
- ## TODO for Next Wave
153
- 1. Create auth middleware
154
- 2. Apply to protected routes
155
- ```
156
-
157
- ---
158
-
159
- ### 6. PLAN 1.2 (Wave 2)
160
-
161
- ```xml
162
- ---
163
- phase: 1
164
- plan: 2
165
- type: implementation
166
- wave: 2
167
- depends_on: [1]
168
- ---
169
-
170
- <objective>
171
- Create middleware to protect routes requiring authentication.
172
- </objective>
173
-
174
- <context>
175
- Wave 1 complete: login/logout endpoints exist.
176
- JWT is stored in httpOnly cookie named "token".
177
- </context>
178
-
179
- <tasks>
180
- <task type="auto" effort="high">
181
- <name>Create auth middleware</name>
182
- <files>src/middleware/auth.ts</files>
183
- <action>
184
- Create middleware that:
185
- 1. Reads JWT from cookie
186
- 2. Verifies signature with jose
187
- 3. Attaches user to request
188
- 4. Returns 401 if invalid/missing
189
- </action>
190
- <verify>Import and call middleware with mock request</verify>
191
- <done>Valid JWT passes, invalid/missing returns 401</done>
192
- </task>
193
-
194
- <task type="auto" effort="medium">
195
- <name>Apply middleware to protected route</name>
196
- <files>src/app/api/user/profile/route.ts</files>
197
- <action>
198
- Create example protected route.
199
- Apply auth middleware.
200
- Return user data if authenticated.
201
- </action>
202
- <verify>curl localhost:3000/api/user/profile with and without cookie</verify>
203
- <done>With cookie: 200 + data. Without: 401</done>
204
- </task>
205
- </tasks>
206
- ```
207
-
208
- ---
209
-
210
- ### 7. Wave 2 Execution & Snapshot
211
-
212
- **Commits:**
213
- ```
214
- git commit -m "feat(phase-1): create auth middleware"
215
- git commit -m "feat(phase-1): apply middleware to profile route"
216
- ```
217
-
218
- **State Snapshot:** (similar format to Wave 1)
219
-
220
- ---
221
-
222
- ### 8. Verification
223
-
224
- ```bash
225
- # Full verification sequence
226
- curl -X POST localhost:3000/api/auth/login \
227
- -H "Content-Type: application/json" \
228
- -d '{"email":"user@example.com","password":"secret"}' \
229
- -c cookies.txt
230
-
231
- # Expected: 200 + Set-Cookie: token=...
232
-
233
- curl localhost:3000/api/user/profile -b cookies.txt
234
- # Expected: 200 + user data
235
-
236
- curl localhost:3000/api/user/profile
237
- # Expected: 401
238
-
239
- curl -X POST localhost:3000/api/auth/logout -b cookies.txt
240
- # Expected: 200 + cookie cleared
241
- ```
242
-
243
- ---
244
-
245
- ## Key Takeaways
246
-
247
- 1. **Waves group dependent work** — Wave 2 waited for Wave 1
248
- 2. **State snapshots preserve context** — Each wave ends with documented state
249
- 3. **Atomic commits per task** — Easy to trace and revert
250
- 4. **Verification built into plan** — No "trust me, it works"
251
- 5. **Effort hints model selection** — `high` effort = use reasoning model
252
-
253
- ---
254
-
255
- *See PROJECT_RULES.md for wave execution rules.*
256
- *See templates/state_snapshot.md for snapshot format.*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/examples/quick-reference.md DELETED
@@ -1,73 +0,0 @@
1
- # GSD Quick Reference Card
2
-
3
- ## Workflow Lifecycle
4
-
5
- ```
6
- ┌─────────┐ ┌─────────┐ ┌──────────┐ ┌─────────┐
7
- │ /map │ → │ /plan │ → │ /execute │ → │ /verify │
8
- │ │ │ │ │ │ │ │
9
- │ Analyze │ │ Create │ │ Run │ │ Check │
10
- │codebase │ │ phases │ │ tasks │ │ work │
11
- └─────────┘ └─────────┘ └──────────┘ └─────────┘
12
- ↑ │
13
- └──────────────┘
14
- (if gaps found)
15
- ```
16
-
17
- ## All Commands
18
-
19
- | Command | Args | Purpose |
20
- |---------|------|---------|
21
- | `/map` | - | Analyze codebase → ARCHITECTURE.md |
22
- | `/plan` | `[phase]` | Create PLAN.md files for phase |
23
- | `/execute` | `phase [--gaps-only]` | Run plans with wave execution |
24
- | `/verify` | `phase` | Validate with empirical proof |
25
- | `/debug` | `description` | Systematic debugging |
26
- | `/progress` | - | Show current position |
27
- | `/pause` | - | Save state, end session |
28
- | `/resume` | - | Load state, start session |
29
- | `/add-todo` | `item [--priority]` | Quick capture |
30
- | `/check-todos` | `[--all]` | List pending items |
31
-
32
- ## Core Rules
33
-
34
- | Rule | Enforcement |
35
- |------|-------------|
36
- | 🔒 Planning Lock | No code until SPEC finalized |
37
- | 💾 State Persistence | Update STATE.md after tasks |
38
- | 🧹 Context Hygiene | 3 failures → fresh session |
39
- | ✅ Empirical Validation | Proof required for "done" |
40
-
41
- ## Key Files
42
-
43
- | File | Purpose | Updated By |
44
- |------|---------|------------|
45
- | SPEC.md | Vision (finalize first!) | User |
46
- | ROADMAP.md | Phase definitions | /plan |
47
- | STATE.md | Session memory | All |
48
- | ARCHITECTURE.md | System design | /map |
49
- | TODO.md | Quick capture | /add-todo |
50
-
51
- ## XML Task Structure
52
-
53
- ```xml
54
- <task type="auto">
55
- <name>Clear name</name>
56
- <files>exact/path.ts</files>
57
- <action>Specific instructions</action>
58
- <verify>Executable command</verify>
59
- <done>Measurable criteria</done>
60
- </task>
61
- ```
62
-
63
- ## Priority Indicators
64
-
65
- | Priority | Icon |
66
- |----------|------|
67
- | High | 🔴 |
68
- | Medium | 🟡 |
69
- | Low | 🟢 |
70
-
71
- ---
72
-
73
- *Print this for quick reference!*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/examples/workflow-example.md DELETED
@@ -1,139 +0,0 @@
1
- # GSD Workflow Example
2
-
3
- > A complete walkthrough of using GSD from start to finish.
4
-
5
- ## Scenario: Building a Simple Todo API
6
-
7
- ### Step 1: Define the Spec
8
-
9
- First, fill out `.gsd/SPEC.md`:
10
-
11
- ```markdown
12
- # SPEC.md
13
-
14
- > **Status**: `FINALIZED`
15
-
16
- ## Vision
17
- A simple RESTful API for managing todo items.
18
-
19
- ## Goals
20
- 1. CRUD operations for todos
21
- 2. Persistence to SQLite
22
- 3. Input validation
23
-
24
- ## Success Criteria
25
- - [ ] POST /todos creates a todo
26
- - [ ] GET /todos returns list
27
- - [ ] DELETE /todos/:id removes item
28
- ```
29
-
30
- ---
31
-
32
- ### Step 2: Map the Codebase (if existing)
33
-
34
- ```
35
- /map
36
- ```
37
-
38
- This creates:
39
- - `.gsd/ARCHITECTURE.md` — Current structure
40
- - `.gsd/STACK.md` — Technologies in use
41
-
42
- ---
43
-
44
- ### Step 3: Plan the Phases
45
-
46
- ```
47
- /plan 1
48
- ```
49
-
50
- GSD analyzes the SPEC and creates `.gsd/phases/1/` with PLAN.md files:
51
-
52
- ```markdown
53
- # Plan 1.1: Database Setup
54
-
55
- ## Objective
56
- Create SQLite database with todos table.
57
-
58
- ## Tasks
59
-
60
- <task type="auto">
61
- <name>Initialize SQLite database</name>
62
- <files>src/db.ts</files>
63
- <action>
64
- Create SQLite connection using better-sqlite3.
65
- Create todos table with: id, title, completed, created_at.
66
- </action>
67
- <verify>node -e "require('./src/db')" exits without error</verify>
68
- <done>Database file exists, table created</done>
69
- </task>
70
- ```
71
-
72
- ---
73
-
74
- ### Step 4: Execute the Phase
75
-
76
- ```
77
- /execute 1
78
- ```
79
-
80
- GSD:
81
- 1. Loads Plan 1.1
82
- 2. Executes tasks in order
83
- 3. Runs verify commands
84
- 4. Creates atomic commits
85
- 5. Creates SUMMARY.md
86
- 6. Proceeds to Plan 1.2
87
- 7. Verifies phase goal
88
-
89
- ---
90
-
91
- ### Step 5: Verify the Work
92
-
93
- ```
94
- /verify 1
95
- ```
96
-
97
- GSD:
98
- 1. Extracts must-haves from phase
99
- 2. Runs verification commands
100
- 3. Captures evidence
101
- 4. Creates VERIFICATION.md
102
- 5. Reports pass/fail
103
-
104
- ---
105
-
106
- ### Step 6: Continue or Debug
107
-
108
- **If verified:**
109
- ```
110
- /plan 2 → Plan next phase
111
- /execute 2 → Execute next phase
112
- ```
113
-
114
- **If issues found:**
115
- ```
116
- /execute 1 --gaps-only → Run fix plans
117
- /debug "API returns 500" → Debug the issue
118
- ```
119
-
120
- ---
121
-
122
- ## Quick Commands Reference
123
-
124
- | Command | When to Use |
125
- |---------|-------------|
126
- | `/map` | Analyze existing codebase |
127
- | `/plan [N]` | Create plans for phase N |
128
- | `/execute [N]` | Run all plans in phase N |
129
- | `/verify [N]` | Confirm phase N works |
130
- | `/debug [issue]` | Fix a problem |
131
- | `/progress` | See current status |
132
- | `/pause` | End session, save state |
133
- | `/resume` | Start new session |
134
- | `/add-todo` | Capture quick idea |
135
- | `/check-todos` | See pending items |
136
-
137
- ---
138
-
139
- *This example demonstrates the GSD methodology flow.*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/1/1-PLAN.md DELETED
@@ -1,162 +0,0 @@
1
- ---
2
- phase: 1
3
- plan: 1
4
- wave: 1
5
- ---
6
-
7
- # Plan 1.1: Python Project Structure & FastAPI Skeleton
8
-
9
- ## Objective
10
- Set up the complete Python project structure with FastAPI app, configuration management, dependency specification, and development tooling. This creates the foundation every other module builds on.
11
-
12
- ## Context
13
- - .gsd/SPEC.md — Tech stack decisions (FastAPI, Python, SQLite)
14
- - .gsd/DECISIONS.md — ADR-001 (FastAPI), ADR-003 (SQLite)
15
- - .gsd/ROADMAP.md — Phase 1 scope
16
-
17
- ## Tasks
18
-
19
- <task type="auto">
20
- <name>Create project directory structure</name>
21
- <files>
22
- backend/__init__.py
23
- backend/main.py
24
- backend/config.py
25
- backend/api/__init__.py
26
- backend/api/routes/__init__.py
27
- backend/api/routes/health.py
28
- backend/api/routes/candidates.py
29
- backend/api/routes/teams.py
30
- backend/services/__init__.py
31
- backend/models/__init__.py
32
- backend/utils/__init__.py
33
- requirements.txt
34
- .env.example
35
- .gitignore
36
- README.md
37
- </files>
38
- <action>
39
- Create the following project structure:
40
-
41
- ```
42
- backend/
43
- ├── __init__.py
44
- ├── main.py # FastAPI app factory, CORS, static files, router mounting
45
- ├── config.py # Pydantic Settings: DB path, GitHub PAT, API keys, model paths
46
- ├── api/
47
- │ ├── __init__.py
48
- │ └── routes/
49
- │ ├── __init__.py
50
- │ ├── health.py # GET /api/health — returns status + version
51
- │ ├── candidates.py # Placeholder POST /api/candidates/analyze
52
- │ └── teams.py # Placeholder POST /api/teams/analyze
53
- ├── services/
54
- │ └── __init__.py # Empty — services added in Phase 2+
55
- ├── models/
56
- │ └── __init__.py # Empty — SQLAlchemy models added in Plan 1.2
57
- └── utils/
58
- └── __init__.py # Empty — utilities added later
59
- ```
60
-
61
- **main.py specifics:**
62
- - Create FastAPI app with title="HireSense AI", version="1.0.0"
63
- - Add CORS middleware allowing all origins (hackathon demo)
64
- - Mount static files from `frontend/` directory at `/`
65
- - Include routers from api/routes/ with `/api` prefix
66
- - Add lifespan handler that initializes the database on startup
67
-
68
- **config.py specifics:**
69
- - Use pydantic-settings BaseSettings class
70
- - Fields: DATABASE_URL (default: sqlite:///./hiresense.db), GITHUB_TOKEN (optional), APP_VERSION (default: 1.0.0)
71
- - Load from .env file
72
-
73
- **health.py specifics:**
74
- - Single GET endpoint at /health
75
- - Returns {"status": "healthy", "version": "1.0.0", "service": "HireSense AI"}
76
-
77
- **candidates.py specifics:**
78
- - Placeholder POST /candidates/analyze that returns {"message": "Not implemented yet"}
79
- - This will be wired up in Phase 2
80
-
81
- **teams.py specifics:**
82
- - Placeholder POST /teams/analyze that returns {"message": "Not implemented yet"}
83
- - This will be wired up in Phase 4
84
-
85
- **requirements.txt:**
86
- - fastapi>=0.104.0
87
- - uvicorn[standard]>=0.24.0
88
- - pydantic-settings>=2.1.0
89
- - sqlalchemy>=2.0.23
90
- - python-multipart>=0.0.6
91
- - pdfplumber>=0.10.3
92
- - spacy>=3.7.2
93
- - sentence-transformers>=2.2.2
94
- - scikit-learn>=1.3.2
95
- - requests>=2.31.0
96
- - python-dotenv>=1.0.0
97
- - aiofiles>=23.2.1
98
-
99
- **.env.example:**
100
- - DATABASE_URL=sqlite:///./hiresense.db
101
- - GITHUB_TOKEN=your_github_pat_here
102
-
103
- **.gitignore:**
104
- - Standard Python gitignore + .env, *.db, __pycache__, .venv
105
-
106
- **README.md:**
107
- - Project name, one-line description
108
- - Quick start: install deps, run server
109
- - API docs at /docs
110
-
111
- AVOID:
112
- - Do NOT add authentication — out of scope per SPEC non-goals
113
- - Do NOT create complex middleware — keep it minimal
114
- - Do NOT install dependencies yet — that's a separate step during execution
115
- </action>
116
- <verify>
117
- ls -la backend/ backend/api/ backend/api/routes/ backend/services/ backend/models/ backend/utils/
118
- cat requirements.txt
119
- cat backend/main.py
120
- </verify>
121
- <done>
122
- - All directories and files exist
123
- - main.py creates a FastAPI app with CORS, router includes, and static file mount
124
- - config.py has Pydantic Settings with DATABASE_URL and GITHUB_TOKEN
125
- - health.py has GET /health returning status JSON
126
- - requirements.txt has all Phase 1+ dependencies listed
127
- - .env.example, .gitignore, README.md exist
128
- </done>
129
- </task>
130
-
131
- <task type="auto">
132
- <name>Install dependencies and verify server starts</name>
133
- <files>requirements.txt</files>
134
- <action>
135
- 1. Create Python virtual environment: python3 -m venv .venv
136
- 2. Activate it: source .venv/bin/activate
137
- 3. Install requirements: pip install -r requirements.txt
138
- 4. Start the server: uvicorn backend.main:app --reload --port 8000
139
- 5. Test health endpoint: curl http://localhost:8000/api/health
140
- 6. Verify OpenAPI docs load at http://localhost:8000/docs
141
-
142
- AVOID:
143
- - Do NOT install spaCy model yet (needed in Phase 2, not Phase 1)
144
- - Do NOT try to connect to GitHub/LeetCode APIs yet
145
- </action>
146
- <verify>
147
- curl -s http://localhost:8000/api/health | python3 -m json.tool
148
- </verify>
149
- <done>
150
- - Virtual environment created and activated
151
- - All dependencies installed without errors
152
- - Server starts on port 8000
153
- - GET /api/health returns {"status": "healthy", "version": "1.0.0", "service": "HireSense AI"}
154
- - /docs page loads and shows all routes
155
- </done>
156
- </task>
157
-
158
- ## Success Criteria
159
- - [ ] FastAPI server starts and responds on http://localhost:8000
160
- - [ ] Health endpoint returns valid JSON with status, version, service
161
- - [ ] Project structure matches the specification above
162
- - [ ] All placeholder routes exist and return appropriate responses
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/1/1-SUMMARY.md DELETED
@@ -1,18 +0,0 @@
1
- # Plan 1.1 Summary: Python Project Structure & FastAPI Skeleton
2
-
3
- ## Status: ✅ Complete
4
-
5
- ## What was done
6
- - Created full Python project structure: `backend/` with `main.py`, `config.py`, `api/routes/`, `models/`, `services/`, `utils/`
7
- - FastAPI app with CORS middleware, lifespan handler, router registration, static file serving
8
- - Pydantic Settings config loading from .env (DATABASE_URL, GITHUB_TOKEN)
9
- - Health endpoint: GET /api/health → `{"status": "healthy", "version": "1.0.0", "service": "HireSense AI"}`
10
- - Placeholder candidate and team analysis endpoints
11
- - requirements.txt with all dependencies installed
12
- - README.md, .gitignore, .env.example
13
-
14
- ## Verification
15
- - Server starts on port 8000 ✓
16
- - Health endpoint returns correct JSON ✓
17
- - OpenAPI docs load at /docs ✓
18
- - All dependencies install cleanly ✓
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/1/2-PLAN.md DELETED
@@ -1,129 +0,0 @@
1
- ---
2
- phase: 1
3
- plan: 2
4
- wave: 1
5
- ---
6
-
7
- # Plan 1.2: SQLite Database Models & Initialization
8
-
9
- ## Objective
10
- Define the SQLAlchemy models for persisting candidate analyses and team analyses. Set up database initialization that runs on app startup. This ensures all later phases can store and retrieve results.
11
-
12
- ## Context
13
- - .gsd/SPEC.md — REQ-19: Store analysis results in SQLite
14
- - .gsd/DECISIONS.md — ADR-003 (SQLite via SQLAlchemy)
15
- - backend/config.py — DATABASE_URL setting
16
- - backend/main.py — Lifespan handler for DB init
17
-
18
- ## Tasks
19
-
20
- <task type="auto">
21
- <name>Create SQLAlchemy models and database setup</name>
22
- <files>
23
- backend/models/__init__.py
24
- backend/models/database.py
25
- backend/models/candidate.py
26
- backend/models/team.py
27
- </files>
28
- <action>
29
- **backend/models/database.py:**
30
- - Create SQLAlchemy engine from config DATABASE_URL
31
- - Create SessionLocal factory with sessionmaker
32
- - Create Base declarative base
33
- - Create `init_db()` function that calls Base.metadata.create_all()
34
- - Create `get_db()` dependency that yields a session and closes it after
35
-
36
- **backend/models/candidate.py:**
37
- - CandidateAnalysis model:
38
- - id: Integer, primary key, autoincrement
39
- - candidate_name: String, nullable
40
- - email: String, nullable
41
- - github_username: String, nullable
42
- - leetcode_username: String, nullable
43
- - resume_skills: Text (JSON string of extracted skills)
44
- - job_description: Text
45
- - match_score: Float, nullable
46
- - learning_ability_score: Float, nullable
47
- - credibility_score: Float, nullable
48
- - overall_score: Float, nullable
49
- - analysis_result: Text (full JSON result blob)
50
- - created_at: DateTime, default=utcnow
51
- - updated_at: DateTime, onupdate=utcnow
52
-
53
- **backend/models/team.py:**
54
- - TeamAnalysis model:
55
- - id: Integer, primary key, autoincrement
56
- - team_name: String
57
- - team_skills: Text (JSON string)
58
- - project_requirements: Text (JSON string)
59
- - coverage_score: Float, nullable
60
- - skill_gaps: Text (JSON string)
61
- - hire_plan: Text (JSON string)
62
- - analysis_result: Text (full JSON result blob)
63
- - created_at: DateTime, default=utcnow
64
- - updated_at: DateTime, onupdate=utcnow
65
-
66
- **Update backend/models/__init__.py:**
67
- - Export Base, init_db, get_db, CandidateAnalysis, TeamAnalysis
68
-
69
- **Update backend/main.py lifespan:**
70
- - Call init_db() inside the lifespan async context manager on startup
71
- - Log "Database initialized" on success
72
-
73
- AVOID:
74
- - Do NOT use Alembic migrations — overkill for hackathon, create_all() is sufficient
75
- - Do NOT add relationships between models yet — keep flat
76
- - Do NOT store binary blobs (PDFs) in DB — only analysis results
77
- </action>
78
- <verify>
79
- python3 -c "from backend.models import Base, CandidateAnalysis, TeamAnalysis; print('Models imported OK')"
80
- # Start server and check that hiresense.db is created
81
- ls -la hiresense.db
82
- </verify>
83
- <done>
84
- - All model files exist with correct column definitions
85
- - Models import without errors
86
- - Server startup creates hiresense.db automatically
87
- - Tables candidate_analyses and team_analyses exist in the database
88
- </done>
89
- </task>
90
-
91
- <task type="auto">
92
- <name>Add analysis history endpoints</name>
93
- <files>
94
- backend/api/routes/candidates.py
95
- backend/api/routes/teams.py
96
- </files>
97
- <action>
98
- **candidates.py — add:**
99
- - GET /candidates/history — return list of past analyses (id, name, match_score, created_at)
100
- - GET /candidates/{id} — return full analysis result by ID
101
-
102
- **teams.py — add:**
103
- - GET /teams/history — return list of past team analyses (id, team_name, coverage_score, created_at)
104
- - GET /teams/{id} — return full team analysis result by ID
105
-
106
- Both use the get_db dependency for database sessions.
107
- Return empty lists initially (no analyses exist yet).
108
-
109
- AVOID:
110
- - Do NOT add DELETE endpoints — not needed for hackathon
111
- - Do NOT add pagination — keep simple for now
112
- </action>
113
- <verify>
114
- curl -s http://localhost:8000/api/candidates/history | python3 -m json.tool
115
- curl -s http://localhost:8000/api/teams/history | python3 -m json.tool
116
- </verify>
117
- <done>
118
- - GET /api/candidates/history returns [] (empty list)
119
- - GET /api/teams/history returns [] (empty list)
120
- - GET /api/candidates/999 returns 404
121
- - GET /api/teams/999 returns 404
122
- </done>
123
- </task>
124
-
125
- ## Success Criteria
126
- - [ ] Database file (hiresense.db) is auto-created on server startup
127
- - [ ] candidate_analyses and team_analyses tables exist with correct columns
128
- - [ ] History endpoints return empty lists when no data exists
129
- - [ ] 404 responses for non-existent analysis IDs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/1/2-SUMMARY.md DELETED
@@ -1,16 +0,0 @@
1
- # Plan 1.2 Summary: SQLite Database Models & Initialization
2
-
3
- ## Status: ✅ Complete
4
-
5
- ## What was done
6
- - SQLAlchemy engine + session factory in `backend/models/database.py`
7
- - CandidateAnalysis model: id, name, email, github/leetcode usernames, skills, scores, analysis_result JSON, timestamps
8
- - TeamAnalysis model: id, team_name, team_skills, project_requirements, coverage_score, skill_gaps, hire_plan, timestamps
9
- - Database auto-initializes on server startup via lifespan handler
10
- - History endpoints: GET /api/candidates/history, GET /api/teams/history
11
- - Detail endpoints: GET /api/candidates/{id}, GET /api/teams/{id} (with 404 handling)
12
-
13
- ## Verification
14
- - hiresense.db auto-created on startup ✓
15
- - History endpoints return empty lists ✓
16
- - Non-existent IDs return 404 ✓
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/1/3-PLAN.md DELETED
@@ -1,144 +0,0 @@
1
- ---
2
- phase: 1
3
- plan: 3
4
- wave: 2
5
- ---
6
-
7
- # Plan 1.3: Frontend Shell & Static File Serving
8
-
9
- ## Objective
10
- Create the frontend HTML/CSS/JS shell with a premium, modern dark-themed dashboard. Two views: Candidate Analysis and Team Analysis, switchable via navigation tabs. The UI should feel production-grade from day one — this is what the hackathon judges see first.
11
-
12
- ## Context
13
- - .gsd/SPEC.md — Plain HTML/CSS/JS frontend, two user flows
14
- - .gsd/DECISIONS.md — ADR-002 (vanilla frontend)
15
- - backend/main.py — Static file mount at /
16
-
17
- ## Tasks
18
-
19
- <task type="auto">
20
- <name>Create frontend directory structure and HTML shell</name>
21
- <files>
22
- frontend/index.html
23
- frontend/css/style.css
24
- frontend/js/app.js
25
- frontend/js/api.js
26
- </files>
27
- <action>
28
- **Directory structure:**
29
- ```
30
- frontend/
31
- ├── index.html # Single-page app shell
32
- ├── css/
33
- │ └── style.css # Complete design system
34
- └── js/
35
- ├── app.js # View switching, UI orchestration
36
- └── api.js # API client (fetch wrapper)
37
- ```
38
-
39
- **index.html specifics:**
40
- - Single HTML page with two switchable views
41
- - Header: "HireSense AI" branding with icon/logo area
42
- - Navigation: Two tabs — "🔍 Candidate Analysis" and "🏢 Team Analysis"
43
- - Candidate Analysis view:
44
- - Upload area: drag-and-drop zone for resume PDF
45
- - Text area: paste job description
46
- - "Analyze" button
47
- - Results panel (empty placeholder, will be populated in Phase 5)
48
- - Team Analysis view:
49
- - Form: team name, team skills (textarea/tags), project requirements (textarea)
50
- - "Analyze Team" button
51
- - Results panel (empty placeholder)
52
- - Footer: "HireSense AI v1.0 • Decision Intelligence for Startups"
53
- - Load Google Font: Inter or Outfit
54
- - Meta tags for SEO
55
-
56
- **css/style.css specifics:**
57
- Create a premium dark-themed design system:
58
- - CSS custom properties for the full color palette
59
- - Dark background (#0a0a0f or similar deep navy/black)
60
- - Accent colors: electric blue (#6366f1 indigo) + emerald green (#10b981) for positive signals
61
- - Warning: amber (#f59e0b), Error: red (#ef4444)
62
- - Glassmorphism cards (backdrop-filter: blur, subtle borders)
63
- - Smooth transitions on all interactive elements (0.2-0.3s ease)
64
- - Typography: Inter/Outfit from Google Fonts, proper hierarchy (h1-h3, body text)
65
- - Responsive grid layout (single column on mobile, two-column on desktop)
66
- - Upload zone: dashed border, hover effect, drag-active state
67
- - Tab navigation: pill-style tabs with active indicator animation
68
- - Buttons: gradient backgrounds, hover glow effects
69
- - Input fields: dark background, subtle border, focus glow
70
- - Scrollbar styling for webkit
71
- - Loading spinner/pulse animation (for later use)
72
- - Status badges (success, warning, error, info) with colored dots
73
-
74
- **js/api.js specifics:**
75
- - API base URL constant (http://localhost:8000/api)
76
- - Async functions:
77
- - checkHealth() — GET /api/health
78
- - analyzeCandidateStub(formData) — POST /api/candidates/analyze
79
- - analyzeTeamStub(data) — POST /api/teams/analyze
80
- - getCandidateHistory() — GET /api/candidates/history
81
- - getTeamHistory() — GET /api/teams/history
82
- - Error handling wrapper with user-friendly error messages
83
-
84
- **js/app.js specifics:**
85
- - Tab switching logic (show/hide views, update active tab)
86
- - Drag-and-drop file upload handling (visual feedback, file validation — PDF only)
87
- - Form submission handlers (wired to api.js stubs)
88
- - Health check on page load (show connection status indicator)
89
- - Toast notification system for success/error messages
90
-
91
- AVOID:
92
- - Do NOT use any CSS framework (Tailwind, Bootstrap, etc.)
93
- - Do NOT make it look basic/minimal — this is a hackathon showcase
94
- - Do NOT implement actual analysis logic — just wire up the UI to placeholder API
95
- - Do NOT use generic colors — use a curated, premium palette
96
- </action>
97
- <verify>
98
- # Start backend server and visit http://localhost:8000
99
- # Verify:
100
- # 1. Page loads with dark theme
101
- # 2. Both tabs switch views correctly
102
- # 3. Upload zone accepts drag & drop
103
- # 4. Health indicator shows connected
104
- # 5. Forms submit and show placeholder response
105
- curl -s http://localhost:8000/ | head -20
106
- </verify>
107
- <done>
108
- - index.html loads at http://localhost:8000/
109
- - Dark theme with premium glassmorphism design is visible
110
- - Two tabs (Candidate / Team) switch views
111
- - Drag-and-drop upload zone works (visual feedback on drag)
112
- - Job description text area is present
113
- - Team analysis form has all fields
114
- - Health check runs on load and shows status
115
- - All interactive elements have smooth hover/transition effects
116
- - Responsive layout works on different screen sizes
117
- </done>
118
- </task>
119
-
120
- <task type="checkpoint:human-verify">
121
- <name>Visual verification of frontend shell</name>
122
- <files>frontend/index.html</files>
123
- <action>
124
- Open http://localhost:8000 in a browser and verify:
125
- 1. The design looks premium and hackathon-ready
126
- 2. Dark theme is visually appealing
127
- 3. Tab switching is smooth
128
- 4. Upload drag-and-drop has visual feedback
129
- 5. All text is readable and well-sized
130
- 6. Layout is responsive
131
-
132
- Take a screenshot or use the browser tool for verification.
133
- </action>
134
- <verify>Open browser to http://localhost:8000 and capture screenshot</verify>
135
- <done>User confirms the frontend shell looks premium and functional</done>
136
- </task>
137
-
138
- ## Success Criteria
139
- - [ ] http://localhost:8000 serves the frontend shell
140
- - [ ] Premium dark-themed design with glassmorphism, smooth animations
141
- - [ ] Two-tab navigation (Candidate Analysis / Team Analysis) works
142
- - [ ] Drag-and-drop upload zone shows visual feedback
143
- - [ ] API client successfully calls health endpoint
144
- - [ ] Design quality is hackathon-presentation-ready
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/1/3-SUMMARY.md DELETED
@@ -1,25 +0,0 @@
1
- # Plan 1.3 Summary: Frontend Shell & Static File Serving
2
-
3
- ## Status: ✅ Complete
4
-
5
- ## What was done
6
- - `frontend/index.html`: Single-page shell with header, two-tab nav, two views, toast container, footer
7
- - `frontend/css/style.css`: 600+ line premium dark theme with glassmorphism, CSS custom properties, responsive layout
8
- - `frontend/js/api.js`: Fetch wrapper with error handling, all API endpoint functions
9
- - `frontend/js/app.js`: Tab switching, drag-and-drop upload (PDF validation, size check), form validation, health check, toast notifications
10
-
11
- ## Design highlights
12
- - Deep navy/black background with subtle animated gradient
13
- - Glassmorphism cards with backdrop-filter blur
14
- - Indigo (#6366f1) accent + emerald green for success states
15
- - Inter font from Google Fonts
16
- - Smooth transitions on all interactive elements
17
- - Responsive: 2-column → 1-column on mobile
18
-
19
- ## Verification
20
- - Page loads at http://localhost:8000 ✓
21
- - Premium dark theme with glassmorphism visible ✓
22
- - Tab switching works (Candidate ↔ Team) ✓
23
- - Upload zone shows drag feedback ✓
24
- - Connection status shows green dot + v1.0.0 ✓
25
- - Responsive layout works ✓
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/10/1-PLAN.md DELETED
@@ -1,46 +0,0 @@
1
- ---
2
- phase: 10
3
- plan: 1
4
- wave: 1
5
- ---
6
-
7
- # Plan 10.1: Team Gap Analysis UI Overhaul & Data Mapping Fix
8
-
9
- ## Objective
10
- The Team Gap Analysis pipeline currently suffers from two distinct problems:
11
- 1. **Data Mapping Bug**: The frontend expects `role_title`, `salary_benchmark`, and `job_description` directly inside the `hire_plan` array. However, the FastApi backend returns `"role"`, `"salary": {...}`, and places the JDs into a completely separate `job_descriptions` array. This causes "undefined" or empty states on the UI for Salaries and JDs.
12
- 2. **Aesthetic Debt**: The team gap dashboard feels visually sparse and lacks the premium Shadcn/vibrant aesthetic recently successfully applied to the Candidate Evaluation dashboard.
13
-
14
- ## Context
15
- - .gsd/ROADMAP.md
16
- - frontend/src/components/dashboard/TeamView.tsx
17
- - backend/api/routes/teams.py
18
-
19
- ## Tasks
20
-
21
- <task type="auto">
22
- <name>Fix Frontend Data Mapping in TeamView.tsx</name>
23
- <files>frontend/src/components/dashboard/TeamView.tsx</files>
24
- <action>
25
- - Update `{role.role_title}` to `{role.role}` mapping the API correctly.
26
- - Update `{role.salary_benchmark}` to `{role.salary?.formatted}` or fallback.
27
- - Fetch the job description from the companion array `{result.job_descriptions?.[i]?.description || "Generating JD..."}`.
28
- </action>
29
- <verify>Ensure the mock or test API payload successfully displays JD snippet and Salary on the UI.</verify>
30
- <done>Frontend data binding reflects the `teams.py` response structure.</done>
31
- </task>
32
-
33
- <task type="auto">
34
- <name>Redesign Hiring Plan and Coverge UI</name>
35
- <files>frontend/src/components/dashboard/TeamView.tsx</files>
36
- <action>
37
- - Enhance the "Generated Hiring Plan" cards. Use premium styling (soft colors, CardFooter with copy-clipboard buttons).
38
- - Enhance the "Architectural coverage" ring and Domain Deficits list with clear Shadcn aesthetic markers (distinct borders, better spacing, and dynamic badges for Urgency).
39
- </action>
40
- <verify>Visually verify the new UI components render cleanly on the localhost NextJS server.</verify>
41
- <done>Team Gap side visually aligns with the pristine quality of the Candidate Evaluator.</done>
42
- </task>
43
-
44
- ## Success Criteria
45
- - [ ] Role titles, Salary, and JD Snippets are no longer missing/undefined.
46
- - [ ] Team Gap Analysis UI matches premium styling guidelines.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/2/1-PLAN.md DELETED
@@ -1,170 +0,0 @@
1
- ---
2
- phase: 2
3
- plan: 1
4
- wave: 1
5
- ---
6
-
7
- # Plan 2.1: Resume Parser Service
8
-
9
- ## Objective
10
- Build the resume parser that extracts structured data from PDF resumes — candidate name, email, phone, skills, projects, experience sections, and external profile links (GitHub, LeetCode). This is the entry point of the entire analysis pipeline.
11
-
12
- ## Context
13
- - .gsd/SPEC.md — REQ-01: Parse PDF resumes and extract structured fields
14
- - .gsd/phases/2/RESEARCH.md — Resume parsing approach (pdfplumber + regex + keyword matching)
15
- - backend/config.py — Settings for upload directory
16
- - backend/models/candidate.py — CandidateAnalysis model
17
-
18
- ## Tasks
19
-
20
- <task type="auto">
21
- <name>Create resume parser service</name>
22
- <files>
23
- backend/services/resume_parser.py
24
- backend/services/skill_dictionary.py
25
- </files>
26
- <action>
27
- **backend/services/skill_dictionary.py:**
28
- Create a comprehensive skill dictionary for matching. Structure as a Python dict:
29
- ```python
30
- SKILL_CATEGORIES = {
31
- "languages": ["python", "javascript", "typescript", "java", "c++", "c#", "go", "rust", "ruby", "php", "swift", "kotlin", "scala", "r", "matlab", "sql", "html", "css"],
32
- "frontend": ["react", "angular", "vue", "svelte", "next.js", "nuxt", "tailwind", "bootstrap", "jquery", "redux", "webpack", "vite"],
33
- "backend": ["node.js", "express", "fastapi", "flask", "django", "spring boot", "rails", "laravel", "asp.net", "gin", "fiber"],
34
- "databases": ["postgresql", "mysql", "mongodb", "redis", "sqlite", "elasticsearch", "cassandra", "dynamodb", "firebase", "supabase"],
35
- "devops": ["docker", "kubernetes", "aws", "azure", "gcp", "terraform", "ansible", "jenkins", "github actions", "ci/cd", "nginx", "linux"],
36
- "ml_ai": ["machine learning", "deep learning", "tensorflow", "pytorch", "scikit-learn", "pandas", "numpy", "nlp", "computer vision", "llm", "transformers", "hugging face", "opencv"],
37
- "tools": ["git", "jira", "figma", "postman", "grafana", "prometheus", "kafka", "rabbitmq", "graphql", "rest api", "websocket"],
38
- }
39
- ```
40
- Also create a flattened set `ALL_SKILLS` for fast lookup, and a function `normalize_skill(skill) -> str` that lowercases and strips whitespace.
41
-
42
- **backend/services/resume_parser.py:**
43
- Create a `ResumeParser` class with these methods:
44
-
45
- `parse(pdf_path: str) -> dict`:
46
- Main entry point. Returns structured dict:
47
- ```python
48
- {
49
- "name": str or None,
50
- "email": str or None,
51
- "phone": str or None,
52
- "github_url": str or None,
53
- "github_username": str or None,
54
- "leetcode_url": str or None,
55
- "leetcode_username": str or None,
56
- "linkedin_url": str or None,
57
- "skills": [str], # extracted skills
58
- "experience": [dict], # list of experience entries
59
- "projects": [dict], # list of project entries
60
- "education": [dict], # list of education entries
61
- "raw_text": str, # full extracted text
62
- }
63
- ```
64
-
65
- `_extract_text(pdf_path: str) -> str`:
66
- Use pdfplumber to extract all text from all pages. Handle multi-page PDFs.
67
-
68
- `_extract_contact(text: str) -> dict`:
69
- Use regex to extract:
70
- - Email: r'[\w.-]+@[\w.-]+\.\w+'
71
- - Phone: r'[\+]?[\d\s\-\(\)]{10,}'
72
- - GitHub URL: r'github\.com/([a-zA-Z0-9_-]+)'
73
- - LeetCode URL: r'leetcode\.com/(?:u/)?([a-zA-Z0-9_-]+)'
74
- - LinkedIn URL: r'linkedin\.com/in/([a-zA-Z0-9_-]+)'
75
-
76
- `_extract_name(text: str) -> str`:
77
- Take the first non-empty line of the resume (common convention).
78
- Validate it doesn't look like an email or URL.
79
-
80
- `_extract_skills(text: str) -> list[str]`:
81
- 1. Lowercase the full text
82
- 2. For each skill in ALL_SKILLS, check if it appears in the text
83
- 3. Also check for multi-word skills (e.g., "machine learning")
84
- 4. Return deduplicated, sorted list
85
-
86
- `_extract_sections(text: str) -> dict`:
87
- Use regex to detect section headers like:
88
- - "EXPERIENCE", "WORK EXPERIENCE", "EMPLOYMENT"
89
- - "PROJECTS", "PERSONAL PROJECTS"
90
- - "EDUCATION", "ACADEMIC"
91
- Split text into sections. For each experience/project entry, extract:
92
- - title/role
93
- - organization (if present)
94
- - description text
95
-
96
- AVOID:
97
- - Do NOT use spaCy NER for name extraction — it's unreliable on resumes and adds startup time. Simple first-line heuristic is more reliable.
98
- - Do NOT try to extract dates/durations — too complex for MVP, not needed for scoring.
99
- - Do NOT import sentence_transformers here — that's Phase 3.
100
- </action>
101
- <verify>
102
- python3 -c "
103
- from backend.services.resume_parser import ResumeParser
104
- parser = ResumeParser()
105
- print('ResumeParser imported OK')
106
- print(f'Skill categories: {len(parser.skill_dict)}')
107
- "
108
- </verify>
109
- <done>
110
- - ResumeParser class exists and imports without error
111
- - parse() method accepts a PDF path and returns structured dict
112
- - Regex patterns extract email, phone, GitHub/LeetCode URLs
113
- - Skill dictionary has 7+ categories with 80+ skills
114
- - Section detection splits resumes into experience/projects/education
115
- </done>
116
- </task>
117
-
118
- <task type="auto">
119
- <name>Wire resume upload to API endpoint</name>
120
- <files>
121
- backend/api/routes/candidates.py
122
- </files>
123
- <action>
124
- Update the POST /candidates/analyze endpoint:
125
- 1. Accept `resume: UploadFile` and `job_description: str = Form(...)`
126
- 2. Save uploaded PDF to `{UPLOAD_DIR}/{timestamp}_{filename}`
127
- 3. Run `ResumeParser().parse(saved_path)` on it
128
- 4. Extract GitHub/LeetCode usernames from parsed results
129
- 5. Return the parsed profile as JSON (analysis scoring comes in Phase 3)
130
- 6. Save initial record to database (CandidateAnalysis) with parsed fields
131
-
132
- Response structure (for now):
133
- ```json
134
- {
135
- "id": 1,
136
- "status": "parsed",
137
- "candidate": {
138
- "name": "...",
139
- "email": "...",
140
- "skills": [...],
141
- "github_username": "...",
142
- "leetcode_username": "..."
143
- },
144
- "message": "Resume parsed. GitHub/LeetCode analysis pending."
145
- }
146
- ```
147
-
148
- AVOID:
149
- - Do NOT run GitHub/LeetCode analysis in this task — that's wired in Plan 2.3
150
- - Do NOT compute scores — that's Phase 3
151
- </action>
152
- <verify>
153
- # Create a test PDF and upload it
154
- curl -X POST http://localhost:8000/api/candidates/analyze \
155
- -F "resume=@test_resume.pdf" \
156
- -F "job_description=Looking for a Python developer"
157
- </verify>
158
- <done>
159
- - POST /api/candidates/analyze accepts file upload + job description
160
- - Uploaded PDF is saved to uploads/ directory
161
- - Response contains parsed candidate data (name, email, skills, usernames)
162
- - Record saved to database with parsed fields
163
- </done>
164
- </task>
165
-
166
- ## Success Criteria
167
- - [ ] Resume parser extracts structured data from PDF files
168
- - [ ] Skills matched against skill dictionary (80+ skills)
169
- - [ ] GitHub/LeetCode profile links detected via regex
170
- - [ ] API endpoint accepts file upload and returns parsed profile
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/2/1-SUMMARY.md DELETED
@@ -1,11 +0,0 @@
1
- # Plan 2.1 Summary: Resume Parser Service
2
-
3
- ## Status: ✅ Complete
4
-
5
- ## What was done
6
- - `backend/services/skill_dictionary.py`: 232 skills across 9 categories with matching/normalization
7
- - `backend/services/resume_parser.py`: PDF extraction (pdfplumber), regex contact/link detection (email, phone, GitHub, LeetCode, LinkedIn), name heuristic, section parsing (experience/projects/education), skill matching
8
-
9
- ## Verification
10
- - Imports without error ✓
11
- - Test PDF: extracted "John Doe", email, phone, GitHub/LeetCode usernames, 12 skills ✓
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/2/2-PLAN.md DELETED
@@ -1,153 +0,0 @@
1
- ---
2
- phase: 2
3
- plan: 2
4
- wave: 1
5
- ---
6
-
7
- # Plan 2.2: GitHub Analyzer Service
8
-
9
- ## Objective
10
- Build the GitHub analyzer that fetches developer activity data via the REST API and computes four scores: consistency, project depth, tech breadth, and recency. These scores become key signals in the candidate analysis pipeline.
11
-
12
- ## Context
13
- - .gsd/SPEC.md — REQ-02, REQ-03: Fetch GitHub data and compute scores
14
- - .gsd/phases/2/RESEARCH.md — GitHub REST API endpoints and auth pattern
15
- - backend/config.py — GITHUB_TOKEN setting
16
-
17
- ## Tasks
18
-
19
- <task type="auto">
20
- <name>Create GitHub analyzer service</name>
21
- <files>
22
- backend/services/github_analyzer.py
23
- </files>
24
- <action>
25
- Create a `GitHubAnalyzer` class:
26
-
27
- **__init__(self, token: str = None):**
28
- - Store token for auth header
29
- - Set base_url = "https://api.github.com"
30
- - Set headers with Accept: application/vnd.github.v3+json
31
-
32
- **analyze(self, username: str) -> dict:**
33
- Main entry point. Returns:
34
- ```python
35
- {
36
- "username": str,
37
- "profile": {
38
- "name": str,
39
- "bio": str,
40
- "public_repos": int,
41
- "followers": int,
42
- "following": int,
43
- "created_at": str,
44
- },
45
- "scores": {
46
- "consistency": float, # 0-100
47
- "project_depth": float, # 0-100
48
- "tech_breadth": float, # 0-100
49
- "recency": float, # 0-100
50
- "overall": float, # weighted average
51
- },
52
- "details": {
53
- "total_repos": int,
54
- "total_stars": int,
55
- "total_commits_sampled": int,
56
- "languages": {str: int}, # language -> bytes
57
- "top_repos": [dict], # top 5 repos by stars
58
- "commit_frequency": dict, # monthly commit counts
59
- "active_days": int, # days with commits in last year
60
- },
61
- "explanations": {
62
- "consistency": str,
63
- "project_depth": str,
64
- "tech_breadth": str,
65
- "recency": str,
66
- }
67
- }
68
- ```
69
-
70
- **_fetch_profile(self, username: str) -> dict:**
71
- GET /users/{username} — extract key fields.
72
- Handle 404 (user not found) gracefully.
73
-
74
- **_fetch_repos(self, username: str) -> list:**
75
- GET /users/{username}/repos?per_page=100&sort=pushed
76
- For each repo, capture: name, stars, forks, language, updated_at, fork (bool).
77
- Filter out forks (only count original repos).
78
-
79
- **_fetch_languages(self, username: str, repos: list) -> dict:**
80
- For top 10 repos (by stars), GET /repos/{username}/{repo}/languages.
81
- Aggregate bytes per language across all repos.
82
-
83
- **_fetch_commit_activity(self, username: str, repos: list) -> dict:**
84
- For top 5 repos, GET /repos/{username}/{repo}/commits?per_page=100.
85
- Extract commit dates, bucket by month.
86
- Count unique days with commits.
87
-
88
- **_calculate_consistency_score(self, commit_data: dict) -> tuple[float, str]:**
89
- Measure how evenly distributed commits are across months.
90
- - Calculate coefficient of variation of monthly commit counts
91
- - Low CV = high consistency → score 80-100
92
- - High CV = irregular bursts → score 20-60
93
- - No commits → score 0
94
- Return (score, explanation_string).
95
-
96
- **_calculate_project_depth_score(self, repos: list) -> tuple[float, str]:**
97
- Based on total stars, watchers, and commit count of top repos.
98
- - Weight: stars * 3 + forks * 2 + (commits > 50 bonus)
99
- - Normalize to 0-100 scale
100
- Return (score, explanation_string).
101
-
102
- **_calculate_tech_breadth_score(self, languages: dict) -> tuple[float, str]:**
103
- Count distinct languages used.
104
- - 1-2 languages → 20-40
105
- - 3-5 languages → 50-70
106
- - 6+ languages → 80-100
107
- Bonus for diversity across paradigms (e.g., Python + JS + Go).
108
- Return (score, explanation_string).
109
-
110
- **_calculate_recency_score(self, repos: list, commit_data: dict) -> tuple[float, str]:**
111
- Based on most recent commit/push date.
112
- - Within last week → 100
113
- - Within last month → 85
114
- - Within last 3 months → 65
115
- - Within last year → 40
116
- - Older → 10
117
- Return (score, explanation_string).
118
-
119
- **Error handling:**
120
- - If username not found → return error dict with "user_not_found": True
121
- - If rate limited → return partial results with "rate_limited": True warning
122
- - If no token → still works but with lower rate limit, add warning
123
-
124
- AVOID:
125
- - Do NOT fetch ALL commits for ALL repos — too slow. Sample top 5 repos, 100 commits each.
126
- - Do NOT use GraphQL API — stick to REST for simplicity and our research findings.
127
- - Do NOT cache results — keep stateless for MVP.
128
- </action>
129
- <verify>
130
- python3 -c "
131
- from backend.services.github_analyzer import GitHubAnalyzer
132
- analyzer = GitHubAnalyzer()
133
- print('GitHubAnalyzer imported OK')
134
- # Quick test with a known public user
135
- result = analyzer.analyze('torvalds')
136
- print(f'Profile: {result[\"profile\"][\"name\"]}')
137
- print(f'Scores: {result[\"scores\"]}')
138
- "
139
- </verify>
140
- <done>
141
- - GitHubAnalyzer class exists and imports without error
142
- - analyze() returns profile, 4 scores (0-100), details, and explanations
143
- - Handles user not found gracefully
144
- - Works without token (with rate limit warning)
145
- - Top repos, languages, and commit data extracted correctly
146
- </done>
147
- </task>
148
-
149
- ## Success Criteria
150
- - [ ] GitHub analyzer fetches real data from GitHub API
151
- - [ ] Four scores computed: consistency, project depth, tech breadth, recency
152
- - [ ] Each score has a human-readable explanation
153
- - [ ] Error handling for missing users and rate limits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/2/2-SUMMARY.md DELETED
@@ -1,13 +0,0 @@
1
- # Plan 2.2 Summary: GitHub Analyzer Service
2
-
3
- ## Status: ✅ Complete
4
-
5
- ## What was done
6
- - `backend/services/github_analyzer.py`: REST API integration with optional PAT auth
7
- - Four scored dimensions: consistency (CV of monthly commits), project depth (stars/forks), tech breadth (language diversity), recency (last activity)
8
- - Each score includes a human-readable explanation
9
- - Error handling: user not found, rate limits, missing token
10
-
11
- ## Verification
12
- - Imports without error ✓
13
- - Real user (torvalds): consistency=16, project_depth=100, tech_breadth=30, recency=95, overall=59.5 ✓
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/2/3-PLAN.md DELETED
@@ -1,208 +0,0 @@
1
- ---
2
- phase: 2
3
- plan: 3
4
- wave: 2
5
- ---
6
-
7
- # Plan 2.3: LeetCode Analyzer + Full Pipeline Wiring
8
-
9
- ## Objective
10
- Build the LeetCode analyzer using the GraphQL endpoint, then wire all three services (resume parser, GitHub analyzer, LeetCode analyzer) into the candidate analysis API endpoint to produce a complete candidate profile with all external data fetched and scored.
11
-
12
- ## Context
13
- - .gsd/SPEC.md — REQ-04: Fetch LeetCode data via GraphQL
14
- - .gsd/phases/2/RESEARCH.md — LeetCode GraphQL queries
15
- - backend/services/resume_parser.py — Built in Plan 2.1
16
- - backend/services/github_analyzer.py — Built in Plan 2.2
17
- - backend/api/routes/candidates.py — Endpoint to update
18
-
19
- ## Tasks
20
-
21
- <task type="auto">
22
- <name>Create LeetCode analyzer service</name>
23
- <files>
24
- backend/services/leetcode_analyzer.py
25
- </files>
26
- <action>
27
- Create a `LeetCodeAnalyzer` class:
28
-
29
- **analyze(self, username: str) -> dict:**
30
- Main entry point. Returns:
31
- ```python
32
- {
33
- "username": str,
34
- "profile": {
35
- "ranking": int,
36
- "reputation": int,
37
- },
38
- "problems": {
39
- "total_solved": int,
40
- "easy": int,
41
- "medium": int,
42
- "hard": int,
43
- },
44
- "scores": {
45
- "problem_solving": float, # 0-100
46
- "difficulty_balance": float, # 0-100
47
- "overall": float, # weighted average
48
- },
49
- "details": {
50
- "easy_percentage": float,
51
- "medium_percentage": float,
52
- "hard_percentage": float,
53
- "streak": int,
54
- "total_active_days": int,
55
- },
56
- "explanations": {
57
- "problem_solving": str,
58
- "difficulty_balance": str,
59
- }
60
- }
61
- ```
62
-
63
- **_fetch_user_data(self, username: str) -> dict:**
64
- POST to https://leetcode.com/graphql with query:
65
- ```graphql
66
- query getUserProfile($username: String!) {
67
- matchedUser(username: $username) {
68
- username
69
- submitStatsGlobal {
70
- acSubmissionNum {
71
- difficulty
72
- count
73
- }
74
- }
75
- profile {
76
- ranking
77
- reputation
78
- }
79
- userCalendar {
80
- streak
81
- totalActiveDays
82
- }
83
- }
84
- }
85
- ```
86
- Headers: Content-Type: application/json, Referer: https://leetcode.com
87
- Handle user not found (matchedUser returns null).
88
-
89
- **_calculate_problem_solving_score(self, problems: dict) -> tuple[float, str]:**
90
- Weighted score:
91
- - easy: 1 point each
92
- - medium: 3 points each
93
- - hard: 5 points each
94
- Normalize: 0-50 weighted points → 0-40 score, 50-200 → 40-80, 200+ → 80-100.
95
- Return (score, explanation).
96
-
97
- **_calculate_difficulty_balance_score(self, problems: dict) -> tuple[float, str]:**
98
- Ideal ratio is roughly 40% easy, 40% medium, 20% hard.
99
- - Pure easy → 20
100
- - Good mix → 70-90
101
- - Heavy on hard → 90-100
102
- Return (score, explanation).
103
-
104
- **Error handling:**
105
- - User not found → return error dict with "user_not_found": True
106
- - GraphQL error → return partial results with warning
107
-
108
- AVOID:
109
- - Do NOT scrape HTML — use only the GraphQL endpoint
110
- - Do NOT try to get submission details — just counts by difficulty
111
- </action>
112
- <verify>
113
- python3 -c "
114
- from backend.services.leetcode_analyzer import LeetCodeAnalyzer
115
- analyzer = LeetCodeAnalyzer()
116
- print('LeetCodeAnalyzer imported OK')
117
- result = analyzer.analyze('neal_wu')
118
- print(f'Problems solved: {result[\"problems\"][\"total_solved\"]}')
119
- print(f'Scores: {result[\"scores\"]}')
120
- "
121
- </verify>
122
- <done>
123
- - LeetCodeAnalyzer class exists and imports without error
124
- - analyze() hits the GraphQL endpoint and returns problem stats
125
- - Two scores computed: problem_solving, difficulty_balance
126
- - Each score has explanation
127
- - Handles user not found gracefully
128
- </done>
129
- </task>
130
-
131
- <task type="auto">
132
- <name>Wire full pipeline into candidate analysis endpoint</name>
133
- <files>
134
- backend/api/routes/candidates.py
135
- backend/services/__init__.py
136
- </files>
137
- <action>
138
- **Update backend/api/routes/candidates.py:**
139
- Modify POST /candidates/analyze to run the full pipeline:
140
-
141
- 1. Accept `resume: UploadFile` and `job_description: str = Form(...)`
142
- 2. Save PDF, run ResumeParser
143
- 3. If GitHub username found → run GitHubAnalyzer
144
- 4. If LeetCode username found → run LeetCodeAnalyzer
145
- 5. If usernames NOT found in resume, accept optional form fields:
146
- - `github_username: Optional[str] = Form(None)`
147
- - `leetcode_username: Optional[str] = Form(None)`
148
- 6. Assemble complete candidate profile
149
- 7. Save to database (CandidateAnalysis record)
150
- 8. Return full result
151
-
152
- Response structure:
153
- ```json
154
- {
155
- "id": 1,
156
- "status": "analyzed",
157
- "candidate": {
158
- "name": "John Doe",
159
- "email": "john@email.com",
160
- "skills": ["python", "react", "docker"],
161
- "github_username": "johndoe",
162
- "leetcode_username": "johndoe"
163
- },
164
- "github_analysis": {
165
- "scores": { ... },
166
- "details": { ... },
167
- "explanations": { ... }
168
- },
169
- "leetcode_analysis": {
170
- "problems": { ... },
171
- "scores": { ... },
172
- "explanations": { ... }
173
- },
174
- "job_description": "...",
175
- "message": "Candidate profile analyzed. ML scoring available in Phase 3."
176
- }
177
- ```
178
-
179
- **Update backend/services/__init__.py:**
180
- Export all three services for easy importing.
181
-
182
- AVOID:
183
- - Do NOT run GitHub/LeetCode analysis synchronously if it takes too long — but for MVP, synchronous is fine since it's only 2 API calls
184
- - Do NOT compute match score, learning ability, or credibility — that's Phase 3
185
- </action>
186
- <verify>
187
- # Test with a real resume PDF
188
- curl -X POST http://localhost:8000/api/candidates/analyze \
189
- -F "resume=@test_resume.pdf" \
190
- -F "job_description=Looking for a Python developer with React experience" \
191
- -F "github_username=torvalds" \
192
- -F "leetcode_username=neal_wu" | python3 -m json.tool
193
- </verify>
194
- <done>
195
- - POST /api/candidates/analyze runs full pipeline
196
- - Response includes parsed resume + GitHub scores + LeetCode scores
197
- - Record saved to database with all available data
198
- - Optional github/leetcode username override works
199
- - Missing usernames handled gracefully (partial results returned)
200
- </done>
201
- </task>
202
-
203
- ## Success Criteria
204
- - [ ] LeetCode analyzer fetches real data from GraphQL endpoint
205
- - [ ] Problem-solving and difficulty scores computed with explanations
206
- - [ ] Full pipeline: upload PDF → parse → fetch GitHub → fetch LeetCode → return combined result
207
- - [ ] Database record created with all analysis data
208
- - [ ] Works end-to-end with real GitHub/LeetCode usernames
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/2/3-SUMMARY.md DELETED
@@ -1,15 +0,0 @@
1
- # Plan 2.3 Summary: LeetCode Analyzer + Pipeline Wiring
2
-
3
- ## Status: ✅ Complete
4
-
5
- ## What was done
6
- - `backend/services/leetcode_analyzer.py`: GraphQL API integration, problem-solving + difficulty balance scores
7
- - Updated `POST /api/candidates/analyze` to run full pipeline:
8
- - Accept PDF upload + job description + optional username overrides
9
- - Parse resume → fetch GitHub data → fetch LeetCode data → assemble JSON → save to DB
10
- - Updated `backend/services/__init__.py` to export all services
11
-
12
- ## Verification
13
- - LeetCode real user (neal_wu): 253 problems (60E/141M/52H), problem_solving=92, difficulty_balance=90 ✓
14
- - Full pipeline API call returns combined GitHub + LeetCode + resume data ✓
15
- - DB record saved with id=1 ✓
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/2/RESEARCH.md DELETED
@@ -1,70 +0,0 @@
1
- # Phase 2 Research — External API Integrations
2
-
3
- ## LeetCode GraphQL API
4
-
5
- **Endpoint**: `https://leetcode.com/graphql`
6
- **Auth**: None required (public profiles)
7
-
8
- ### Key Queries
9
-
10
- **User profile + problem stats:**
11
- ```graphql
12
- query getUserProfile($username: String!) {
13
- matchedUser(username: $username) {
14
- username
15
- submitStatsGlobal {
16
- acSubmissionNum {
17
- difficulty
18
- count
19
- }
20
- }
21
- profile {
22
- ranking
23
- reputation
24
- }
25
- userCalendar {
26
- streak
27
- totalActiveDays
28
- }
29
- }
30
- }
31
- ```
32
-
33
- **Headers required**: `Content-Type: application/json`, `Referer: https://leetcode.com`
34
-
35
- **Rate limiting**: Informal — use reasonable delays. No PAT system.
36
-
37
- ---
38
-
39
- ## GitHub REST API
40
-
41
- **Base URL**: `https://api.github.com`
42
- **Auth**: `Authorization: Bearer {PAT}` → 5000 req/hour (vs 60 unauthenticated)
43
-
44
- ### Key Endpoints
45
-
46
- | Data | Endpoint | Notes |
47
- |------|----------|-------|
48
- | User profile | `GET /users/{username}` | public_repos, created_at, followers |
49
- | User repos | `GET /users/{username}/repos?per_page=100&sort=updated` | stars, language, updated_at |
50
- | Repo languages | `GET /repos/{owner}/{repo}/languages` | bytes per language |
51
- | Repo commits | `GET /repos/{owner}/{repo}/commits?per_page=100` | commit dates for consistency |
52
- | User events | `GET /users/{username}/events?per_page=100` | recent activity (last 90 days) |
53
-
54
- ### Python Pattern
55
- ```python
56
- headers = {"Authorization": f"Bearer {token}"} if token else {}
57
- response = requests.get(url, headers=headers)
58
- ```
59
-
60
- ---
61
-
62
- ## Resume Parsing (pdfplumber + spaCy + regex)
63
-
64
- - **pdfplumber**: Extract text from PDF pages
65
- - **Regex**: Extract emails, URLs (GitHub/LeetCode profile links), phone numbers
66
- - **spaCy NER**: Extract person names, organization names
67
- - **Keyword matching**: Skills extraction against a skill dictionary
68
- - **Section detection**: Experience, Education, Projects via heading patterns
69
-
70
- No external API needed — all local processing.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/3/1-PLAN.md DELETED
@@ -1,113 +0,0 @@
1
- ---
2
- phase: 3
3
- plan: 1
4
- wave: 1
5
- ---
6
-
7
- # Plan 3.1: Skill Similarity Matcher
8
-
9
- ## Objective
10
- Build the semantic skill matcher that computes how well a candidate's skills (from resume + GitHub languages) match the requirements in a job description. Uses sentence-transformers embeddings for semantic similarity rather than naive keyword overlap, so "React" matches "frontend development" and "PostgreSQL" matches "relational databases".
11
-
12
- ## Context
13
- - .gsd/SPEC.md — REQ-05: Skill similarity matching using sentence embeddings
14
- - backend/services/skill_dictionary.py — Skill categories and matching
15
- - backend/services/resume_parser.py — How skills are extracted
16
- - backend/services/github_analyzer.py — GitHub languages output
17
-
18
- ## Tasks
19
-
20
- <task type="auto">
21
- <name>Create skill matcher service</name>
22
- <files>
23
- backend/services/skill_matcher.py
24
- </files>
25
- <action>
26
- Create a `SkillMatcher` class:
27
-
28
- **__init__(self):**
29
- - Load a lightweight sentence-transformers model: `all-MiniLM-L6-v2` (fast, 22M params)
30
- - Cache the model as a class attribute to avoid reloading on every call
31
- - Lazy-load: only initialize model on first use
32
-
33
- **match(self, candidate_skills: list[str], job_description: str, github_languages: dict = None) -> dict:**
34
- Main entry point. Returns:
35
- ```python
36
- {
37
- "match_score": float, # 0-100 overall match
38
- "matched_skills": [str], # skills that match JD
39
- "missing_skills": [str], # JD requirements not in candidate skills
40
- "bonus_skills": [str], # candidate skills beyond JD requirements
41
- "category_scores": { # score per category
42
- "languages": float,
43
- "frontend": float,
44
- "backend": float,
45
- ...
46
- },
47
- "explanation": str, # human-readable summary
48
- "details": {
49
- "jd_requirements": [str], # skills extracted from JD
50
- "semantic_matches": [ # detailed match pairs
51
- {"candidate_skill": str, "jd_requirement": str, "similarity": float}
52
- ],
53
- }
54
- }
55
- ```
56
-
57
- **_extract_jd_skills(self, job_description: str) -> list[str]:**
58
- 1. Use `find_skills_in_text()` from skill_dictionary for explicit skill mentions
59
- 2. Also extract key phrases that might be implicit skill requirements
60
- (e.g., "building scalable systems" → infrastructure/devops)
61
-
62
- **_compute_semantic_similarity(self, skills_a: list[str], skills_b: list[str]) -> list[dict]:**
63
- 1. Encode both lists with sentence-transformers
64
- 2. Compute cosine similarity matrix
65
- 3. For each JD skill, find best matching candidate skill
66
- 4. Threshold: similarity >= 0.5 counts as a match
67
- 5. Return list of {candidate_skill, jd_requirement, similarity}
68
-
69
- **_merge_skills(self, resume_skills: list[str], github_languages: dict) -> list[str]:**
70
- Combine resume skills with GitHub language names (lowercased).
71
- Deduplicate using `normalize_skill()`.
72
-
73
- **_calculate_match_score(self, matched: list, total_required: int) -> float:**
74
- Score = (matched_count / total_required) * 100 with diminishing returns.
75
- Cap at 100.
76
-
77
- **_generate_explanation(self, score: float, matched: list, missing: list, bonus: list) -> str:**
78
- Human-readable summary, e.g.:
79
- "Strong match (82/100). Candidate covers 8/10 required skills.
80
- Missing: Kubernetes, Terraform. Bonus skills: Machine Learning, PyTorch."
81
-
82
- AVOID:
83
- - Do NOT use a large model — MiniLM-L6-v2 is sufficient and fast
84
- - Do NOT run the model on GPU — CPU is fine for small skill lists
85
- - Do NOT cache embeddings persistently — in-memory per request is fine for MVP
86
- </action>
87
- <verify>
88
- python3 -c "
89
- from backend.services.skill_matcher import SkillMatcher
90
- matcher = SkillMatcher()
91
- result = matcher.match(
92
- candidate_skills=['python', 'react', 'docker', 'aws', 'postgresql'],
93
- job_description='Looking for a Full Stack Developer with Python, React, Node.js, PostgreSQL, and Kubernetes experience',
94
- )
95
- print(f'Match score: {result[\"match_score\"]}')
96
- print(f'Matched: {result[\"matched_skills\"]}')
97
- print(f'Missing: {result[\"missing_skills\"]}')
98
- print(f'Explanation: {result[\"explanation\"]}')
99
- "
100
- </verify>
101
- <done>
102
- - SkillMatcher class exists and imports without error
103
- - match() returns score, matched/missing/bonus skills, and explanation
104
- - Semantic matching works (React ≈ frontend, PostgreSQL ≈ databases)
105
- - Score is 0-100 and reflects actual skill overlap
106
- </done>
107
- </task>
108
-
109
- ## Success Criteria
110
- - [ ] Sentence-transformers model loads and encodes skills
111
- - [ ] Semantic similarity detects related but not identical skills
112
- - [ ] Match score reflects real skill overlap (not just keyword matching)
113
- - [ ] Human-readable explanation generated for every match
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/3/1-SUMMARY.md DELETED
@@ -1,14 +0,0 @@
1
- # Plan 3.1 Summary: Skill Similarity Matcher
2
-
3
- ## Status: ✅ Complete
4
-
5
- ## What was done
6
- - `backend/services/skill_matcher.py`: Sentence-transformers semantic matching (all-MiniLM-L6-v2, lazy-loaded singleton)
7
- - Cosine similarity matrix between candidate skills and JD requirements
8
- - Category-based scoring, match/missing/bonus skill classification
9
- - Human-readable explanations for every match result
10
-
11
- ## Verification
12
- - Imports without error ✓
13
- - Test: 5 candidate skills vs JD with 5 requirements → match_score=60, 3 matched, 2 missing ✓
14
- - Semantic matching works (React ≈ frontend, PostgreSQL ≈ databases) ✓
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/3/2-PLAN.md DELETED
@@ -1,195 +0,0 @@
1
- ---
2
- phase: 3
3
- plan: 2
4
- wave: 1
5
- ---
6
-
7
- # Plan 3.2: Learning Ability Predictor & Inflation Detector
8
-
9
- ## Objective
10
- Build two complementary scoring services: (1) Learning Ability Predictor — estimates how quickly a candidate can acquire missing skills based on their existing skill graph and activity patterns, and (2) Resume Inflation Detector — cross-references self-reported resume claims against verified GitHub/LeetCode data to flag exaggerations.
11
-
12
- ## Context
13
- - .gsd/SPEC.md — REQ-06, REQ-07: Learning ability prediction; REQ-08, REQ-09: Inflation detection
14
- - backend/services/skill_dictionary.py — SKILL_CATEGORIES for skill relationships
15
- - backend/services/github_analyzer.py — GitHub data structure (scores, languages, repos)
16
- - backend/services/leetcode_analyzer.py — LeetCode data structure (problems, scores)
17
-
18
- ## Tasks
19
-
20
- <task type="auto">
21
- <name>Create learning ability predictor</name>
22
- <files>
23
- backend/services/learning_predictor.py
24
- </files>
25
- <action>
26
- Create a `LearningPredictor` class:
27
-
28
- **predict(self, candidate_skills: list[str], missing_skills: list[str], github_data: dict = None, leetcode_data: dict = None) -> dict:**
29
- Returns:
30
- ```python
31
- {
32
- "learning_score": float, # 0-100 overall
33
- "predictions": [ # per missing skill
34
- {
35
- "skill": str,
36
- "estimated_months": float, # estimated time to learn
37
- "confidence": str, # "high"/"medium"/"low"
38
- "reason": str, # why this estimate
39
- "related_existing": [str], # existing skills in same category
40
- }
41
- ],
42
- "factors": {
43
- "skill_breadth_bonus": float, # 0-20 bonus for diverse skills
44
- "consistency_bonus": float, # 0-15 bonus for consistent GH activity
45
- "problem_solving_bonus": float, # 0-15 bonus for LC score
46
- "base_score": float, # 50 baseline
47
- },
48
- "explanation": str,
49
- }
50
- ```
51
-
52
- **_estimate_learning_time(self, skill: str, existing_skills: list[str]) -> dict:**
53
- Logic:
54
- 1. Find the category of the target skill using `get_skill_category()`
55
- 2. Count how many skills the candidate already has in that category
56
- 3. More existing skills in the same category → faster learning
57
- - 0 related skills → 6+ months (low confidence)
58
- - 1-2 related → 3-4 months (medium)
59
- - 3+ related → 1-2 months (high)
60
- 4. Cross-category transfer: a person with Python + React who needs Vue = fast
61
-
62
- **_calculate_learning_score(self, predictions: list, factors: dict) -> float:**
63
- - Base score = 50
64
- - Add skill_breadth_bonus: breadth_factor = min(20, len(unique_categories) * 4)
65
- - Add consistency_bonus: if github consistency score > 70 → +15
66
- - Add problem_solving_bonus: if leetcode_score > 70 → +15
67
- - Subtract penalty for each skill with > 4 months estimate
68
- - Clamp to 0-100
69
-
70
- AVOID:
71
- - Do NOT attempt to use any ML model here — heuristic scoring is appropriate for this signal
72
- - Do NOT try to predict exact timelines — give ranges and confidence levels
73
- </action>
74
- <verify>
75
- python3 -c "
76
- from backend.services.learning_predictor import LearningPredictor
77
- predictor = LearningPredictor()
78
- result = predictor.predict(
79
- candidate_skills=['python', 'flask', 'postgresql', 'git'],
80
- missing_skills=['docker', 'kubernetes', 'react'],
81
- github_data={'scores': {'consistency': 75, 'tech_breadth': 60}},
82
- leetcode_data={'scores': {'overall': 80}},
83
- )
84
- print(f'Learning score: {result[\"learning_score\"]}')
85
- for p in result['predictions']:
86
- print(f' {p[\"skill\"]}: ~{p[\"estimated_months\"]}mo ({p[\"confidence\"]})')
87
- "
88
- </verify>
89
- <done>
90
- - LearningPredictor class exists and imports without error
91
- - predict() returns learning score + per-skill estimates with confidence
92
- - Related skills reduce estimated learning time
93
- - GitHub consistency and LeetCode scores provide bonuses
94
- </done>
95
- </task>
96
-
97
- <task type="auto">
98
- <name>Create inflation detector</name>
99
- <files>
100
- backend/services/inflation_detector.py
101
- </files>
102
- <action>
103
- Create an `InflationDetector` class:
104
-
105
- **detect(self, resume_skills: list[str], github_data: dict = None, leetcode_data: dict = None) -> dict:**
106
- Returns:
107
- ```python
108
- {
109
- "credibility_score": float, # 0-100 (higher = more credible)
110
- "flags": [ # individual credibility flags
111
- {
112
- "skill": str,
113
- "status": str, # "verified" / "unverified" / "inflated"
114
- "evidence": str, # why this status
115
- "source": str, # "github" / "leetcode" / "none"
116
- }
117
- ],
118
- "summary": {
119
- "verified_count": int,
120
- "unverified_count": int,
121
- "inflated_count": int,
122
- "total_claimed": int,
123
- },
124
- "explanation": str,
125
- }
126
- ```
127
-
128
- **_check_github_skills(self, claimed_skills: list[str], github_data: dict) -> list[dict]:**
129
- For each claimed skill:
130
- 1. Check if a matching language appears in GitHub languages dict
131
- 2. Check repo names/descriptions for framework mentions (optional — can do basic name matching)
132
- 3. If found → "verified" with evidence "Found {bytes} bytes of {language} code across {N} repos"
133
- 4. If language category matches but specific skill not found → "unverified"
134
- 5. If completely absent → check if related to any detected language
135
-
136
- **_check_leetcode_skills(self, claimed_skills: list[str], leetcode_data: dict) -> list[dict]:**
137
- If claimed "data structures", "algorithms", etc.:
138
- - Check if total_solved > threshold (>50 → verified)
139
- - Check difficulty balance for algorithm claims
140
-
141
- For language-agnostic claims like "problem solving" → use LC score.
142
-
143
- **_calculate_credibility_score(self, flags: list) -> float:**
144
- - Start at 100
145
- - Each "verified" skill: +0 (no change, already at max)
146
- - Each "unverified" skill: -3 (slight doubt)
147
- - Each "inflated" skill: -10 (significant penalty)
148
- - Floor at 0, cap at 100
149
-
150
- **Inflation rules:**
151
- - Claims "expert in X" but no GitHub evidence → inflated flag
152
- - Claims more than 5 languages with GitHub only showing 1-2 → warning
153
- - Claims "Machine Learning" but no Python/ML repos → unverified
154
-
155
- AVOID:
156
- - Do NOT be overly aggressive — resume skills may be from work experience not on GitHub
157
- - Do NOT call anything "inflated" without strong evidence — default to "unverified"
158
- - Keep the detector fair: some skills are hard to verify via GitHub (e.g., "teamwork", "communication")
159
- </action>
160
- <verify>
161
- python3 -c "
162
- from backend.services.inflation_detector import InflationDetector
163
- detector = InflationDetector()
164
- result = detector.detect(
165
- resume_skills=['python', 'react', 'machine learning', 'kubernetes', 'blockchain'],
166
- github_data={
167
- 'details': {
168
- 'languages': {'Python': 50000, 'JavaScript': 30000},
169
- 'total_repos': 15,
170
- },
171
- 'scores': {'tech_breadth': 40},
172
- },
173
- leetcode_data={
174
- 'problems': {'total_solved': 100, 'easy': 40, 'medium': 45, 'hard': 15},
175
- },
176
- )
177
- print(f'Credibility: {result[\"credibility_score\"]}')
178
- for f in result['flags']:
179
- print(f' {f[\"skill\"]}: {f[\"status\"]} — {f[\"evidence\"]}')
180
- "
181
- </verify>
182
- <done>
183
- - InflationDetector class exists and imports without error
184
- - detect() cross-references resume claims against GitHub/LeetCode evidence
185
- - Each skill gets verified/unverified/inflated status with evidence
186
- - Credibility score reflects overall claim reliability
187
- - Not overly aggressive — defaults to "unverified" when uncertain
188
- </done>
189
- </task>
190
-
191
- ## Success Criteria
192
- - [ ] Learning predictor estimates time-to-learn per missing skill
193
- - [ ] Inflation detector flags unverified/inflated resume claims
194
- - [ ] Both provide human-readable explanations
195
- - [ ] GitHub languages and LeetCode stats used as evidence sources
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/3/2-SUMMARY.md DELETED
@@ -1,11 +0,0 @@
1
- # Plan 3.2 Summary: Learning Predictor + Inflation Detector
2
-
3
- ## Status: ✅ Complete
4
-
5
- ## What was done
6
- - `backend/services/learning_predictor.py`: Skill graph analysis (category overlap → faster learning), GitHub consistency + LeetCode bonuses, per-skill time estimates with confidence levels
7
- - `backend/services/inflation_detector.py`: Cross-references resume claims against GitHub languages + LeetCode stats. Language ecosystems map for framework validation. Conservative: defaults to "unverified" not "inflated"
8
-
9
- ## Verification
10
- - LearningPredictor: score=90 for well-matched candidate, per-skill estimates working ✓
11
- - InflationDetector: credibility=100 when GitHub confirms 4/4 claimed skills ✓
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/3/3-PLAN.md DELETED
@@ -1,169 +0,0 @@
1
- ---
2
- phase: 3
3
- plan: 3
4
- wave: 2
5
- ---
6
-
7
- # Plan 3.3: Scoring Engine Integration + API Response Update
8
-
9
- ## Objective
10
- Wire all ML scoring services (skill matcher, learning predictor, inflation detector) into the candidate analysis pipeline and update the API response to include full scoring with an overall composite score. Also update the frontend JavaScript to display the results when available.
11
-
12
- ## Context
13
- - backend/api/routes/candidates.py — Current pipeline (Phase 2)
14
- - backend/services/skill_matcher.py — Built in Plan 3.1
15
- - backend/services/learning_predictor.py — Built in Plan 3.2
16
- - backend/services/inflation_detector.py — Built in Plan 3.2
17
-
18
- ## Tasks
19
-
20
- <task type="auto">
21
- <name>Create scoring engine orchestrator and update API</name>
22
- <files>
23
- backend/services/scoring_engine.py
24
- backend/api/routes/candidates.py
25
- backend/services/__init__.py
26
- </files>
27
- <action>
28
- **backend/services/scoring_engine.py:**
29
- Create a `ScoringEngine` class that orchestrates all scoring:
30
-
31
- **score(self, parsed_resume: dict, job_description: str, github_data: dict = None, leetcode_data: dict = None) -> dict:**
32
- 1. Run SkillMatcher.match() → match_score + details
33
- 2. Get missing_skills from match result
34
- 3. Run LearningPredictor.predict() → learning_score + predictions
35
- 4. Run InflationDetector.detect() → credibility_score + flags
36
- 5. Compute overall_score as weighted average:
37
- - match_score: 40%
38
- - github_overall: 20%
39
- - leetcode_overall: 15%
40
- - learning_score: 10%
41
- - credibility_score: 15%
42
- 6. Generate final recommendation: "Strong Hire" / "Hire" / "Maybe" / "Pass"
43
-
44
- Returns:
45
- ```python
46
- {
47
- "overall_score": float, # 0-100
48
- "recommendation": str, # "Strong Hire" etc.
49
- "scores": {
50
- "match_score": float,
51
- "github_score": float,
52
- "leetcode_score": float,
53
- "learning_score": float,
54
- "credibility_score": float,
55
- },
56
- "skill_match": {...}, # full SkillMatcher result
57
- "learning_analysis": {...}, # full LearningPredictor result
58
- "credibility_analysis": {...}, # full InflationDetector result
59
- "explanation": str, # overall narrative
60
- }
61
- ```
62
-
63
- **Recommendation thresholds:**
64
- - overall >= 80 → "Strong Hire"
65
- - overall >= 60 → "Hire"
66
- - overall >= 40 → "Maybe"
67
- - overall < 40 → "Pass"
68
-
69
- **Update backend/api/routes/candidates.py:**
70
- After running GitHub/LeetCode analyzers, call `ScoringEngine().score()` and include all ML scoring in the response. Update the CandidateAnalysis DB record with computed scores (match_score, learning_ability_score, credibility_score, overall_score).
71
-
72
- **Update backend/services/__init__.py:**
73
- Export new services: SkillMatcher, LearningPredictor, InflationDetector, ScoringEngine.
74
-
75
- AVOID:
76
- - Do NOT change the existing pipeline flow — just add scoring after data fetching
77
- - Do NOT break backward compatibility — existing fields must still be present
78
- </action>
79
- <verify>
80
- # Upload test resume and verify full scored response
81
- curl -s -X POST http://localhost:8000/api/candidates/analyze \
82
- -F "resume=@/tmp/test_resume.pdf" \
83
- -F "job_description=Full Stack Python Developer with React, Docker, and AWS" \
84
- -F "github_username=torvalds" \
85
- -F "leetcode_username=neal_wu" \
86
- | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps(d.get('scoring',{}), indent=2))"
87
- </verify>
88
- <done>
89
- - ScoringEngine orchestrates all ML scoring
90
- - API response includes match_score, learning_score, credibility_score, and overall_score
91
- - Recommendation label generated (Strong Hire/Hire/Maybe/Pass)
92
- - Database record updated with all computed scores
93
- - Full pipeline works end-to-end: upload → parse → fetch → score → respond
94
- </done>
95
- </task>
96
-
97
- <task type="auto">
98
- <name>Update frontend to display analysis results</name>
99
- <files>
100
- frontend/js/app.js
101
- frontend/css/style.css
102
- </files>
103
- <action>
104
- **Update frontend/js/app.js:**
105
- In the `handleCandidateAnalysis()` function, after receiving the API response:
106
-
107
- 1. Hide the empty state and show results container
108
- 2. Render score cards:
109
- - Overall score (large, centered, color-coded by recommendation)
110
- - Recommendation badge ("Strong Hire" / "Hire" / "Maybe" / "Pass")
111
- - Individual score cards: Match, GitHub, LeetCode, Learning, Credibility
112
- 3. Render skill tags: matched (green), missing (amber), flagged (red)
113
- 4. Render explanations as collapsible sections
114
-
115
- Create a `renderCandidateResults(data)` function that builds the HTML:
116
- ```javascript
117
- function renderCandidateResults(data) {
118
- const container = document.getElementById('candidate-results');
119
- // Build score overview
120
- // Build skill tags
121
- // Build explanations
122
- container.innerHTML = html;
123
- container.style.display = 'block';
124
- document.getElementById('candidate-empty-state').style.display = 'none';
125
- }
126
- ```
127
-
128
- Score card color rules:
129
- - Score >= 80 → green (--color-success)
130
- - Score >= 60 → accent blue (--accent-primary)
131
- - Score >= 40 → amber (--color-warning)
132
- - Score < 40 → red (--color-error)
133
-
134
- **Update frontend/css/style.css:**
135
- Add styles for:
136
- - `.score-card` — glass card with score number + label
137
- - `.recommendation-badge` — large badge with recommendation text
138
- - `.skill-tags-container` — flex wrap for skill tags
139
- - `.explanation-section` — collapsible with smooth transition
140
-
141
- AVOID:
142
- - Do NOT add a framework — keep vanilla JS
143
- - Do NOT add charting libraries — simple HTML/CSS score displays are fine for MVP
144
- </action>
145
- <verify>
146
- # Visual verification in browser - launch server and check results render after analysis
147
- # Start server: uvicorn backend.main:app --port 8000
148
- # 1. Open http://localhost:8000
149
- # 2. Upload test_resume.pdf
150
- # 3. Enter a job description
151
- # 4. Click Analyze Candidate
152
- # 5. Verify results panel shows scores, recommendation, skill tags
153
- </verify>
154
- <done>
155
- - Results panel renders after successful analysis
156
- - Overall score + recommendation badge visible
157
- - Individual score cards for each dimension
158
- - Skill tags color-coded (matched/missing/flagged)
159
- - Explanations shown for each score
160
- - Empty state hidden when results are displayed
161
- </done>
162
- </task>
163
-
164
- ## Success Criteria
165
- - [ ] Full pipeline: upload → parse → fetch → score → display results
166
- - [ ] Overall score and recommendation computed and shown
167
- - [ ] All 5 score dimensions displayed with color coding
168
- - [ ] Skill tags and explanations rendered in the frontend
169
- - [ ] Database record stores all computed scores
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/3/3-SUMMARY.md DELETED
@@ -1,14 +0,0 @@
1
- # Plan 3.3 Summary: Scoring Engine + API + Frontend Results
2
-
3
- ## Status: ✅ Complete
4
-
5
- ## What was done
6
- - `backend/services/scoring_engine.py`: Orchestrates all ML scoring (40% match + 20% GitHub + 15% LeetCode + 10% learning + 15% credibility), dynamic weight redistribution, recommendation engine
7
- - Updated `backend/api/routes/candidates.py`: Full pipeline with ML scoring, DB stores all computed scores
8
- - Updated `frontend/js/app.js`: Results renderer with score ring, recommendation badge, score cards, skill tags, learning predictions, credibility flags
9
- - Updated `frontend/css/style.css`: Complete results display styles
10
-
11
- ## Verification
12
- - API: overall=77.3, recommendation=Hire for real test data ✓
13
- - Frontend: all components render correctly in browser ✓
14
- - DB: all scores persisted ✓
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/4/1-PLAN.md DELETED
@@ -1,121 +0,0 @@
1
- w---
2
- phase: 4
3
- plan: 1
4
- wave: 1
5
- ---
6
-
7
- # Plan 4.1: Team Skill Gap Analyzer
8
-
9
- ## Objective
10
- Build the core team analysis service that accepts team skills and project requirements, computes coverage score, identifies skill gaps clustered by domain, and generates a prioritized hire plan with urgency levels. This is the analytical backbone of Phase 4.
11
-
12
- ## Context
13
- - .gsd/ROADMAP.md — Phase 4 description
14
- - backend/models/team.py — TeamAnalysis model (coverage_score, skill_gaps, hire_plan columns)
15
- - backend/services/skill_dictionary.py — SKILL_CATEGORIES, get_skill_category for domain clustering
16
- - backend/services/skill_matcher.py — SkillMatcher for semantic matching (reusable pattern)
17
-
18
- ## Tasks
19
-
20
- <task type="auto">
21
- <name>Create team gap analyzer service</name>
22
- <files>
23
- backend/services/team_analyzer.py
24
- </files>
25
- <action>
26
- Create a `TeamAnalyzer` class:
27
-
28
- **analyze(self, team_skills: list[str], project_requirements: list[str], team_name: str = "") -> dict:**
29
- Main entry point. Returns:
30
- ```python
31
- {
32
- "coverage_score": float, # 0-100 how well team covers requirements
33
- "gap_summary": {
34
- "total_required": int,
35
- "covered": int,
36
- "gaps": int,
37
- },
38
- "covered_skills": [str], # requirements the team already has
39
- "gap_clusters": [ # gaps grouped by domain
40
- {
41
- "domain": str, # e.g. "devops", "frontend"
42
- "skills": [str], # missing skills in this domain
43
- "urgency": str, # "critical" / "high" / "medium" / "low"
44
- "reason": str, # why this urgency
45
- }
46
- ],
47
- "hire_plan": [ # recommended hires
48
- {
49
- "role": str, # e.g. "DevOps Engineer"
50
- "priority": int, # 1 = most urgent
51
- "skills_covered": [str], # which gaps this hire fills
52
- "justification": str, # why this hire
53
- }
54
- ],
55
- "explanation": str,
56
- }
57
- ```
58
-
59
- **_compute_coverage(self, team: list[str], required: list[str]) -> tuple[list, list]:**
60
- 1. Use `find_skills_in_text` to normalize both lists
61
- 2. For each requirement, check if the team has it (exact or category match)
62
- 3. Return (covered_list, gap_list)
63
-
64
- **_cluster_gaps(self, gaps: list[str]) -> list[dict]:**
65
- 1. Group gaps by `get_skill_category(skill)` from skill_dictionary
66
- 2. For each cluster, determine urgency:
67
- - 3+ gaps in one domain → "critical"
68
- - 2 gaps → "high"
69
- - 1 gap → "medium"
70
- - Bonus: if domain is "devops" or "security" → bump urgency one level
71
-
72
- **_generate_hire_plan(self, clusters: list[dict]) -> list[dict]:**
73
- 1. Sort clusters by urgency (critical first)
74
- 2. Map each cluster to a suggested role title:
75
- - "devops" gaps → "DevOps Engineer"
76
- - "frontend" gaps → "Frontend Developer"
77
- - "backend" gaps → "Backend Developer"
78
- - "databases" gaps → "Database Engineer"
79
- - "ml_ai" gaps → "ML/AI Engineer"
80
- - "mobile" gaps → "Mobile Developer"
81
- - "tools" gaps → "Platform Engineer"
82
- - "languages" gaps → "Software Engineer"
83
- - "cloud" gaps → "Cloud Engineer"
84
- - Multiple domains → "Full Stack Developer"
85
- 3. Assign priority 1, 2, 3... by urgency order
86
- 4. Generate justification for each hire
87
-
88
- AVOID:
89
- - Do NOT use LLM for this step — pure algorithmic gap analysis
90
- - Do NOT try to merge roles aggressively — keep it clear for the CTO
91
- </action>
92
- <verify>
93
- python3 -c "
94
- from backend.services.team_analyzer import TeamAnalyzer
95
- analyzer = TeamAnalyzer()
96
- result = analyzer.analyze(
97
- team_skills=['python', 'react', 'postgresql', 'git'],
98
- project_requirements=['python', 'react', 'docker', 'kubernetes', 'terraform', 'redis', 'graphql', 'ci/cd'],
99
- team_name='Engineering Alpha',
100
- )
101
- print(f'Coverage: {result[\"coverage_score\"]}%')
102
- print(f'Covered: {result[\"covered_skills\"]}')
103
- print(f'Gaps: {result[\"gap_summary\"][\"gaps\"]}')
104
- for c in result['gap_clusters']:
105
- print(f' {c[\"domain\"]}: {c[\"skills\"]} ({c[\"urgency\"]})')
106
- for h in result['hire_plan']:
107
- print(f' #{h[\"priority\"]} {h[\"role\"]}: {h[\"skills_covered\"]}')
108
- "
109
- </verify>
110
- <done>
111
- - TeamAnalyzer class imports and runs without error
112
- - Coverage score reflects actual skill overlap
113
- - Gaps clustered by domain with urgency levels
114
- - Hire plan generated with roles and priorities
115
- </done>
116
- </task>
117
-
118
- ## Success Criteria
119
- - [ ] Team gap analysis produces coverage score, gap clusters, and hire plan
120
- - [ ] Urgency levels assigned logically (more gaps = higher urgency)
121
- - [ ] Human-readable explanations for every recommendation
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/4/1-SUMMARY.md DELETED
@@ -1,2 +0,0 @@
1
- # Plan 4.1 Summary: Team Skill Gap Analyzer
2
- ## Status: ✅ Complete - Coverage=25%, 6 gaps across 3 clusters, 3 hires recommended
 
 
 
.gsd/phases/4/2-PLAN.md DELETED
@@ -1,171 +0,0 @@
1
- ---
2
- phase: 4
3
- plan: 2
4
- wave: 1
5
- ---
6
-
7
- # Plan 4.2: Salary Benchmarking + JD Generator
8
-
9
- ## Objective
10
- Add salary estimation for hire plan roles using a built-in dataset (inspired by Levels.fyi/public data) and build a JD generator that produces ready-to-post job descriptions from the hire plan. Salary estimates turn recommendations into budgetable business cases ("hiring a DevOps engineer will cost ₹18–26 LPA in Bangalore").
11
-
12
- ## Context
13
- - .gsd/ROADMAP.md — Phase 4: salary benchmarking requirement
14
- - backend/services/team_analyzer.py — Built in Plan 4.1 (hire plan structure)
15
- - backend/services/skill_dictionary.py — Skill categories
16
-
17
- ## Tasks
18
-
19
- <task type="auto">
20
- <name>Create salary benchmarker</name>
21
- <files>
22
- backend/services/salary_benchmarker.py
23
- </files>
24
- <action>
25
- Create a `SalaryBenchmarker` class with a built-in salary dataset.
26
-
27
- **Built-in dataset (dict):**
28
- Store as a Python dict keyed by (role, experience_band, location):
29
- ```python
30
- SALARY_DATA = {
31
- # (role, experience, location) → (min_lpa, max_lpa, currency)
32
- # Indian cities (LPA = Lakhs Per Annum)
33
- ("DevOps Engineer", "junior", "bangalore"): (8, 15, "INR"),
34
- ("DevOps Engineer", "mid", "bangalore"): (15, 26, "INR"),
35
- ("DevOps Engineer", "senior", "bangalore"): (26, 45, "INR"),
36
- ("Frontend Developer", "junior", "bangalore"):(6, 12, "INR"),
37
- ("Frontend Developer", "mid", "bangalore"): (12, 22, "INR"),
38
- ("Frontend Developer", "senior", "bangalore"):(22, 38, "INR"),
39
- ("Backend Developer", "junior", "bangalore"): (8, 14, "INR"),
40
- ("Backend Developer", "mid", "bangalore"): (14, 25, "INR"),
41
- ("Backend Developer", "senior", "bangalore"): (25, 42, "INR"),
42
- ("Full Stack Developer", "junior", "bangalore"):(8, 15, "INR"),
43
- ("Full Stack Developer", "mid", "bangalore"): (15, 28, "INR"),
44
- ("Full Stack Developer", "senior", "bangalore"):(28, 45, "INR"),
45
- ("ML/AI Engineer", "junior", "bangalore"): (10, 18, "INR"),
46
- ("ML/AI Engineer", "mid", "bangalore"): (18, 35, "INR"),
47
- ("ML/AI Engineer", "senior", "bangalore"): (35, 60, "INR"),
48
- ("Cloud Engineer", "mid", "bangalore"): (15, 28, "INR"),
49
- ("Database Engineer", "mid", "bangalore"): (12, 22, "INR"),
50
- ("Mobile Developer", "mid", "bangalore"): (12, 24, "INR"),
51
- ("Platform Engineer", "mid", "bangalore"): (14, 26, "INR"),
52
- ("Software Engineer", "mid", "bangalore"): (12, 22, "INR"),
53
- # ... repeat for "remote_india", "delhi", "hyderabad", "mumbai"
54
- # US cities (K USD)
55
- ("DevOps Engineer", "mid", "us_remote"): (120, 180, "USD"),
56
- ("Frontend Developer", "mid", "us_remote"): (100, 160, "USD"),
57
- ("Backend Developer", "mid", "us_remote"): (110, 170, "USD"),
58
- ("Full Stack Developer", "mid", "us_remote"): (120, 180, "USD"),
59
- ("ML/AI Engineer", "mid", "us_remote"): (140, 220, "USD"),
60
- }
61
- ```
62
-
63
- Add entries for multiple cities and experience bands. At least 100 entries covering India's major cities + US remote.
64
-
65
- **estimate(self, role: str, location: str = "bangalore", experience: str = "mid") -> dict:**
66
- Returns:
67
- ```python
68
- {
69
- "role": str,
70
- "location": str,
71
- "experience": str,
72
- "salary_range": {"min": float, "max": float},
73
- "currency": str,
74
- "formatted": str, # "₹15–26 LPA" or "$120–180K"
75
- }
76
- ```
77
-
78
- **enrich_hire_plan(self, hire_plan: list[dict], location: str = "bangalore", experience: str = "mid") -> list[dict]:**
79
- For each role in the hire plan, add salary estimate.
80
- Also compute total_budget_impact: sum of max salaries across all hires.
81
-
82
- AVOID:
83
- - Do NOT call external APIs — use built-in dataset (the user wants local-first)
84
- - Do NOT over-engineer — a dict-based lookup with fuzzy matching is sufficient
85
- </action>
86
- <verify>
87
- python3 -c "
88
- from backend.services.salary_benchmarker import SalaryBenchmarker
89
- bench = SalaryBenchmarker()
90
- est = bench.estimate('DevOps Engineer', location='bangalore', experience='mid')
91
- print(f'{est[\"role\"]}: {est[\"formatted\"]}')
92
- est2 = bench.estimate('ML/AI Engineer', location='us_remote', experience='mid')
93
- print(f'{est2[\"role\"]}: {est2[\"formatted\"]}')
94
- "
95
- </verify>
96
- <done>
97
- - SalaryBenchmarker class imports and returns salary ranges
98
- - Covers at least 5 Indian cities + US remote
99
- - formatted field shows human-readable salary (₹X–Y LPA or $X–YK)
100
- - enrich_hire_plan adds salary data to each hire recommendation
101
- </done>
102
- </task>
103
-
104
- <task type="auto">
105
- <name>Create JD generator</name>
106
- <files>
107
- backend/services/jd_generator.py
108
- </files>
109
- <action>
110
- Create a `JDGenerator` class that generates ready-to-post job descriptions from hire plan entries.
111
-
112
- **generate(self, role: str, skills: list[str], team_name: str = "", salary_range: dict = None) -> dict:**
113
- Returns:
114
- ```python
115
- {
116
- "title": str, # role title
117
- "description": str, # full JD text (markdown formatted)
118
- "sections": {
119
- "about": str,
120
- "responsibilities": [str],
121
- "requirements": [str],
122
- "nice_to_have": [str],
123
- "compensation": str,
124
- }
125
- }
126
- ```
127
-
128
- Use a template-based approach:
129
- 1. Map role name to a title + about section template
130
- 2. Generate responsibilities from skill list (e.g., "Design and maintain CI/CD pipelines" for docker/kubernetes skills)
131
- 3. Generate requirements from skill list + standard role expectations
132
- 4. Add nice-to-have from related skills in the same category
133
- 5. Add compensation section if salary_range provided
134
-
135
- Have a `RESPONSIBILITY_TEMPLATES` dict mapping skills to responsibility bullet points.
136
- Have a `REQUIREMENT_TEMPLATES` dict mapping skills to requirement bullet points.
137
-
138
- **generate_all(self, hire_plan: list[dict], team_name: str = "") -> list[dict]:**
139
- Generate JDs for all roles in the hire plan.
140
-
141
- AVOID:
142
- - Do NOT use LLM for this — template-based is fine for V1
143
- - Do NOT generate generic JDs — make them specific to the skills needed
144
- </action>
145
- <verify>
146
- python3 -c "
147
- from backend.services.jd_generator import JDGenerator
148
- gen = JDGenerator()
149
- jd = gen.generate(
150
- role='DevOps Engineer',
151
- skills=['docker', 'kubernetes', 'terraform', 'ci/cd'],
152
- team_name='Engineering Alpha',
153
- salary_range={'min': 15, 'max': 26, 'currency': 'INR'},
154
- )
155
- print(f'Title: {jd[\"title\"]}')
156
- print(jd['description'][:500])
157
- "
158
- </verify>
159
- <done>
160
- - JDGenerator class creates role-specific job descriptions
161
- - Responsibilities and requirements match the gap skills
162
- - Compensation section included when salary data available
163
- - Descriptions are formatted in markdown (ready to post)
164
- </done>
165
- </task>
166
-
167
- ## Success Criteria
168
- - [ ] Salary estimates available for all hire plan roles
169
- - [ ] Budget impact computed for the full hire plan
170
- - [ ] JDs generated with skill-specific responsibilities/requirements
171
- - [ ] Human-readable formatting for salary and JDs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/4/2-SUMMARY.md DELETED
@@ -1,2 +0,0 @@
1
- # Plan 4.2 Summary: Salary Benchmarker + JD Generator
2
- ## Status: ✅ Complete - 100+ entries, 7 locations, template-based JDs with 50+ skill mappings
 
 
 
.gsd/phases/4/3-PLAN.md DELETED
@@ -1,118 +0,0 @@
1
- ---
2
- phase: 4
3
- plan: 3
4
- wave: 2
5
- ---
6
-
7
- # Plan 4.3: API Wiring + Frontend Team Results
8
-
9
- ## Objective
10
- Wire the team analyzer, salary benchmarker, and JD generator into the team analysis API endpoint. Update the frontend to display team analysis results — coverage score, gap clusters, hire plan with salary estimates, and generated JDs.
11
-
12
- ## Context
13
- - backend/api/routes/teams.py — Current placeholder endpoint
14
- - backend/services/team_analyzer.py — Built in Plan 4.1
15
- - backend/services/salary_benchmarker.py — Built in Plan 4.2
16
- - backend/services/jd_generator.py — Built in Plan 4.2
17
- - frontend/js/app.js — handleTeamAnalysis is a placeholder
18
- - frontend/css/style.css — Needs team-specific result styles
19
-
20
- ## Tasks
21
-
22
- <task type="auto">
23
- <name>Wire team services into API endpoint</name>
24
- <files>
25
- backend/api/routes/teams.py
26
- backend/services/__init__.py
27
- </files>
28
- <action>
29
- **Update POST /api/teams/analyze:**
30
- Accept JSON body:
31
- ```python
32
- {
33
- "team_name": str,
34
- "team_skills": [str], # comma-separated → list
35
- "project_requirements": [str], # comma-separated → list
36
- "location": str = "bangalore", # optional, for salary lookup
37
- "experience": str = "mid", # optional
38
- }
39
- ```
40
-
41
- Pipeline:
42
- 1. Run TeamAnalyzer.analyze(team_skills, project_requirements, team_name)
43
- 2. Run SalaryBenchmarker.enrich_hire_plan(hire_plan, location, experience)
44
- 3. Run JDGenerator.generate_all(enriched_hire_plan, team_name)
45
- 4. Assemble full result with coverage, gaps, hire plan, salaries, JDs
46
- 5. Save to TeamAnalysis DB record (coverage_score, skill_gaps, hire_plan, analysis_result)
47
- 6. Return JSON response
48
-
49
- **Update services/__init__.py:**
50
- Export TeamAnalyzer, SalaryBenchmarker, JDGenerator.
51
-
52
- AVOID:
53
- - Do NOT change the existing history/detail endpoints — they already work
54
- </action>
55
- <verify>
56
- curl -s -X POST http://localhost:8000/api/teams/analyze \
57
- -H "Content-Type: application/json" \
58
- -d '{"team_name": "Engineering Alpha", "team_skills": ["python", "react", "postgresql"], "project_requirements": ["python", "react", "docker", "kubernetes", "terraform", "redis"]}' \
59
- | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'Coverage: {d[\"coverage_score\"]}'); print(f'Hire plan: {len(d[\"hire_plan\"])} roles')"
60
- </verify>
61
- <done>
62
- - Team analysis endpoint accepts skills + requirements
63
- - Returns coverage score, gap clusters, hire plan, salary estimates, JDs
64
- - Database record saved with all results
65
- </done>
66
- </task>
67
-
68
- <task type="auto">
69
- <name>Update frontend for team results</name>
70
- <files>
71
- frontend/js/app.js
72
- frontend/css/style.css
73
- </files>
74
- <action>
75
- **Update handleTeamAnalysis() in app.js:**
76
- After receiving API response, call `renderTeamResults(data)`.
77
-
78
- **Create renderTeamResults(data) function:**
79
- 1. Coverage score hero (reuse score-ring pattern from candidate results)
80
- 2. Gap clusters section — cards grouped by domain, color-coded by urgency
81
- 3. Hire plan table — role, priority, skills covered, salary range
82
- 4. Budget impact summary — total estimated cost for all hires
83
- 5. JDs section — collapsible cards with full JD text for each role
84
-
85
- **Add CSS styles:**
86
- - `.gap-cluster-card` — urgency-colored border (critical=red, high=amber, medium=blue, low=gray)
87
- - `.hire-plan-table` — dark table with subtle borders
88
- - `.budget-summary` — prominent total budget display
89
- - `.jd-card` — expandable card for job descriptions
90
- - `.jd-toggle` — click-to-expand button
91
-
92
- AVOID:
93
- - Do NOT add frameworks — keep vanilla JS
94
- - Do NOT duplicate the candidate results pattern excessively — team results have a different data shape
95
- </action>
96
- <verify>
97
- # Start server and verify in browser:
98
- # 1. Open http://localhost:8000
99
- # 2. Switch to "Team Analysis" tab
100
- # 3. Enter team name, skills, and requirements
101
- # 4. Click "Analyze Team Gaps"
102
- # 5. Verify results show coverage, gaps, hire plan, salary, JDs
103
- </verify>
104
- <done>
105
- - Team results panel renders after analysis
106
- - Coverage score displayed with ring visualization
107
- - Gap clusters shown with urgency color coding
108
- - Hire plan displayed with salary estimates
109
- - JDs expandable for each role
110
- - Budget impact summary visible
111
- </done>
112
- </task>
113
-
114
- ## Success Criteria
115
- - [ ] Full pipeline: team skills → gaps → hire plan → salary → JDs → display
116
- - [ ] API returns complete team analysis with all sections
117
- - [ ] Frontend renders all team-specific result components
118
- - [ ] Database stores team analysis for history recall
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/4/3-SUMMARY.md DELETED
@@ -1,2 +0,0 @@
1
- # Plan 4.3 Summary: API Wiring + Frontend Team Results
2
- ## Status: ✅ Complete - Full pipeline, coverage ring, gap clusters, hire plan, salary, expandable JDs
 
 
 
.gsd/phases/6/1-PLAN.md DELETED
@@ -1,56 +0,0 @@
1
- ---
2
- phase: 6
3
- plan: 1
4
- wave: 1
5
- ---
6
-
7
- # Plan 6.1: Next.js + Tailwind + Shadcn Initialization
8
-
9
- ## Objective
10
- Initialize the new Next.js frontend to replace the legacy Vanilla JS implementation. This sets up the React, TypeScript, Tailwind CSS, and Shadcn UI foundations for building the advanced landing page required by the prompts.
11
-
12
- ## Context
13
- - .gsd/ROADMAP.md (Phase 6)
14
- - User Prompt containing custom Tailwind `@theme inline` variables.
15
-
16
- ## Tasks
17
-
18
- <task type="auto">
19
- <name>Rename Legacy Frontend</name>
20
- <files>frontend</files>
21
- <action>
22
- - Rename the existing `frontend` directory to `frontend_legacy` to preserve the original vanilla Implementation without losing data.
23
- </action>
24
- <verify>test -d "frontend_legacy"</verify>
25
- <done>Folder is renamed to `frontend_legacy`.</done>
26
- </task>
27
-
28
- <task type="auto">
29
- <name>Initialize Next.js & Dependencies</name>
30
- <files>frontend/package.json</files>
31
- <action>
32
- - Run `npx create-next-app@latest frontend --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"` to create a modern Next.js 14-15 project.
33
- - Change directory to `frontend` and install core animation and icon libraries.
34
- - Run `npm install framer-motion lucide-react @phosphor-icons/react @radix-ui/react-slot class-variance-authority`
35
- </action>
36
- <verify>test -f "frontend/package.json"</verify>
37
- <done>Next.js app initialized with all NPM dependencies successfully installed.</done>
38
- </task>
39
-
40
- <task type="auto">
41
- <name>Configure Shadcn UI & Tailwind Theme</name>
42
- <files>frontend/src/app/globals.css, frontend/components.json</files>
43
- <action>
44
- - Initialize Shadcn via `npx shadcn@latest init -d`.
45
- - Ensure component paths are set to `/src/components/ui`. This is critical because all shadcn defaults target this structure, allowing automatic component installations and maintaining modular UI organization without clutter.
46
- - Create `src/components/ui` if absent.
47
- - Update `frontend/src/app/globals.css` exactly with the color theme variables provided in the user prompt (specifically the `:root`, `.dark` and `@theme inline` blocks).
48
- </action>
49
- <verify>test -d "frontend/src/components/ui"</verify>
50
- <done>Shadcn structural layout configured and global tailored theme variables applied.</done>
51
- </task>
52
-
53
- ## Success Criteria
54
- - [ ] Next.js app running out of `frontend/` directory.
55
- - [ ] `framer-motion`, `lucide-react`, and `@phosphor-icons/react` are listed as dependencies.
56
- - [ ] Theme configuration precisely follows the provided input format in globals.css.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/6/1-SUMMARY.md DELETED
@@ -1,2 +0,0 @@
1
- # Plan 6.1 Summary: Next.js + Tailwind + Shadcn Initialization
2
- ## Status: ✅ Complete - Migrated vanilla to Next.js 14-15 with Tailwind 4. Inherited custom Shadcn inline theme variables.
 
 
 
.gsd/phases/6/2-PLAN.md DELETED
@@ -1,53 +0,0 @@
1
- ---
2
- phase: 6
3
- plan: 2
4
- wave: 1
5
- ---
6
-
7
- # Plan 6.2: Core Animated Components Setup
8
-
9
- ## Objective
10
- Establish the foundational design system components (`Button`, `TextEffect`, `AnimatedGroup`) which will serve as building blocks for the Hero and Background graphics.
11
-
12
- ## Context
13
- - User Prompt containing component code (`button`, `text-effect`, `animated-group`).
14
- - `frontend/src/components/ui/` destination folder.
15
-
16
- ## Tasks
17
-
18
- <task type="auto">
19
- <name>Implement Shadcn Custom Button</name>
20
- <files>frontend/src/components/ui/button.tsx</files>
21
- <action>
22
- - Create the `button.tsx` file inside `src/components/ui/`.
23
- - Copy exactly the Shadcn button code snippet provided by user.
24
- </action>
25
- <verify>test -f "frontend/src/components/ui/button.tsx"</verify>
26
- <done>Button component correctly exposes variants and standard sizes.</done>
27
- </task>
28
-
29
- <task type="auto">
30
- <name>Implement ibelick/text-effect</name>
31
- <files>frontend/src/components/ui/text-effect.tsx</files>
32
- <action>
33
- - Create `text-effect.tsx` in `src/components/ui/`.
34
- - Paste the code provided by the user. Ensure `'use client'` is active at the top.
35
- </action>
36
- <verify>test -f "frontend/src/components/ui/text-effect.tsx"</verify>
37
- <done>TextEffect module handles text staggering and framer motion variations.</done>
38
- </task>
39
-
40
- <task type="auto">
41
- <name>Implement ibelick/animated-group</name>
42
- <files>frontend/src/components/ui/animated-group.tsx</files>
43
- <action>
44
- - Create `animated-group.tsx` in `src/components/ui/`.
45
- - Paste the code provided by the user to handle grouped staggered animations.
46
- </action>
47
- <verify>test -f "frontend/src/components/ui/animated-group.tsx"</verify>
48
- <done>AnimatedGroup component manages staggered container reveals.</done>
49
- </task>
50
-
51
- ## Success Criteria
52
- - [ ] Base foundational components (`Button`, `TextEffect`, `AnimatedGroup`) exist inside `.tsx` files inside `components/ui`.
53
- - [ ] No compilation or missing dependency errors on React imports.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/6/2-SUMMARY.md DELETED
@@ -1,2 +0,0 @@
1
- # Plan 6.2 Summary: Core Animated Components Setup
2
- ## Status: ✅ Complete - Built foundational Shadcn Button, TextEffect, and AnimatedGroup.
 
 
 
.gsd/phases/6/3-PLAN.md DELETED
@@ -1,56 +0,0 @@
1
- ---
2
- phase: 6
3
- plan: 3
4
- wave: 2
5
- ---
6
-
7
- # Plan 6.3: Master Landing Page Assembly
8
-
9
- ## Objective
10
- Combine the UI building blocks into a functional, highly-polished landing page (`BackgroundPaths`, `HeroSection`) matching exactly the requested aesthetic layout.
11
-
12
- ## Context
13
- - User Prompt containing `background-paths.tsx` and `hero-section-1.tsx` implementations.
14
- - Phosphor and Lucide React specifications.
15
-
16
- ## Tasks
17
-
18
- <task type="auto">
19
- <name>Implement BackgroundPaths Graphics</name>
20
- <files>frontend/src/components/ui/background-paths.tsx</files>
21
- <action>
22
- - Create `background-paths.tsx` inside `/src/components/ui/`.
23
- - Paste the user's explicit code for FloatingPaths and BackgroundPaths.
24
- </action>
25
- <verify>test -f "frontend/src/components/ui/background-paths.tsx"</verify>
26
- <done>Animated SVG paths configured to run as a Framer Motion loop.</done>
27
- </task>
28
-
29
- <task type="auto">
30
- <name>Implement HeroSection</name>
31
- <files>frontend/src/components/blocks/hero-section-1.tsx</files>
32
- <action>
33
- - Create `/src/components/blocks/hero-section-1.tsx`.
34
- - Paste the `HeroSection` and `HeroHeader` code from the user prompt.
35
- - **Note:** The user requested "Use lucide-react icons for svgs or logos if component requires them." Ensure imports point to the correct `lucide-react` icons (e.g. `ArrowRight`, `ChevronRight`).
36
- </action>
37
- <verify>test -f "frontend/src/components/blocks/hero-section-1.tsx"</verify>
38
- <done>HeroSection successfully orchestrates structural header, hero title, and customer banner.</done>
39
- </task>
40
-
41
- <task type="auto">
42
- <name>Assemble the Master Landing Page</name>
43
- <files>frontend/src/app/page.tsx</files>
44
- <action>
45
- - Replace `app/page.tsx` base template with the newly built components.
46
- - Stack `<BackgroundPaths />` and `<HeroSection />`. (The prompt implies using both: `HeroSection` offers the header layout while `BackgroundPaths` is a background component. Actually, the BackgroundPaths is its own standalone demo element in the prompt, rendering "Background Paths" text. We will implement both distinctly to show they are working, or blend them dynamically to present the best aesthetic.)
47
- - Remove ANY emojis throughout the UI string blocks.
48
- </action>
49
- <verify>grep -q "HeroSection" "frontend/src/app/page.tsx"</verify>
50
- <done>Full visual landing page dynamically rendered over `/` next route.</done>
51
- </task>
52
-
53
- ## Success Criteria
54
- - [ ] No emojis present in UI templates.
55
- - [ ] Phosphor or Lucide icons successfully handling SVGs.
56
- - [ ] Complete `page.tsx` integrating both Hero and Background features efficiently.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/6/3-SUMMARY.md DELETED
@@ -1,2 +0,0 @@
1
- # Plan 6.3 Summary: Master Landing Page Assembly
2
- ## Status: ✅ Complete - Assembled the landing page leveraging the `BackgroundPaths` graphics overlaid with the animated `HeroSection`. Fixed icon imports and removed emojis.
 
 
 
.gsd/phases/6/VERIFICATION.md DELETED
@@ -1,8 +0,0 @@
1
- ## Phase 6 Verification
2
-
3
- ### Must-Haves
4
- - [x] Must-have 1 — Migrated to React/Next.js and Tailwind - VERIFIED (evidence: scaffolded next.js with global css theming using @theme inline).
5
- - [x] Must-have 2 — Integrated Core Animated Components - VERIFIED (evidence: Button, textual effects and background svg paths imported into component tree successfully).
6
- - [x] Must-have 3 — Assemble Landing Page correctly - VERIFIED (evidence: background paths successfully stacked under the HeroSection inside `page.tsx`).
7
-
8
- ### Verdict: PASS
 
 
 
 
 
 
 
 
 
.gsd/phases/7/1-PLAN.md DELETED
@@ -1,54 +0,0 @@
1
- ---
2
- phase: 7
3
- plan: 1
4
- wave: 1
5
- ---
6
-
7
- # Plan 7.1: Dash Architecture & APIs
8
-
9
- ## Objective
10
- Establish the Next.js `dashboard` route structure, set up the Next.js API proxy to communicate with the FastAPI backend unhindered by CORS/ports, and install the additional Shadcn UI elements required.
11
-
12
- ## Context
13
- - `frontend/next.config.ts`
14
- - FastAPI backend runs on `127.0.0.1:8000/api`
15
- - Next.js dev server runs on `3000`.
16
-
17
- ## Tasks
18
-
19
- <task type="auto">
20
- <name>Configure API Proxy & Utilities</name>
21
- <files>frontend/next.config.ts, frontend/src/lib/api.ts</files>
22
- <action>
23
- - Add an async `rewrites()` rule in `next.config.ts` mapping `/api/:path*` to `http://127.0.0.1:8000/api/:path*`.
24
- - Create `frontend/src/lib/api.ts` with typed Fetch wrappers for `uploadCandidate` and `analyzeTeam` pointing to the `/api/*` routes.
25
- </action>
26
- <verify>grep -q "rewrites" "frontend/next.config.ts"</verify>
27
- <done>Next config correctly forwards `/api/` traffic to local port 8000.</done>
28
- </task>
29
-
30
- <task type="auto">
31
- <name>Install Dashboard Prerequisites</name>
32
- <files>frontend/package.json</files>
33
- <action>
34
- - Use `npx shadcn@latest add card input label tabs textarea progress badge alert scroll-area separator` to install forms and presentation layers.
35
- </action>
36
- <verify>test -f "frontend/src/components/ui/card.tsx"</verify>
37
- <done>Fundamental UI layout primitives installed natively into `components/ui`.</done>
38
- </task>
39
-
40
- <task type="auto">
41
- <name>Create Dashboard Root Layout</name>
42
- <files>frontend/src/app/dashboard/layout.tsx, frontend/src/app/dashboard/page.tsx</files>
43
- <action>
44
- - Scaffold `layout.tsx` with a minimal App header (Link back to `/`).
45
- - Scaffold `page.tsx` utilizing Shadcn generic `<Tabs>` pointing to `Candidate` and `Team` forms.
46
- </action>
47
- <verify>test -f "frontend/src/app/dashboard/page.tsx"</verify>
48
- <done>User can navigate from `/` to `/dashboard` and see a tabbed structural foundation.</done>
49
- </task>
50
-
51
- ## Success Criteria
52
- - [ ] Next.js app seamlessly proxies API calls to FastAPI.
53
- - [ ] Shadcn core view components configured.
54
- - [ ] Dashboard root URL is visually accessible.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/7/1-SUMMARY.md DELETED
@@ -1,2 +0,0 @@
1
- # Plan 7.1 Summary: Dash Architecture & APIs
2
- ## Status: ✅ Complete - Established the main `/dashboard` page framework. Installed Shadcn UI forms elements (Tabs, Inputs, etc.) and created the unified Next.js API generic proxy route wrapper to speak to FastAPI without CORS issues on localhost.
 
 
 
.gsd/phases/7/2-PLAN.md DELETED
@@ -1,45 +0,0 @@
1
- ---
2
- phase: 7
3
- plan: 2
4
- wave: 2
5
- ---
6
-
7
- # Plan 7.2: Candidate Analysis Pipeline
8
-
9
- ## Objective
10
- Rebuild the legacy plain JS candidate resume analysis workflow completely inside a reactive Next.js Client Component, utilizing the sophisticated shadcn form controls.
11
-
12
- ## Context
13
- - `frontend/src/app/dashboard/page.tsx`
14
- - FastAPI backend requires `multipart/form-data` containing `resume` (PDF) and `job_requirements` (string).
15
-
16
- ## Tasks
17
-
18
- <task type="auto">
19
- <name>Build Candidate Form State</name>
20
- <files>frontend/src/components/dashboard/CandidateView.tsx</files>
21
- <action>
22
- - Establish `CandidateView.tsx`.
23
- - Create state using React `useState` for the uploaded `File` and the Job Description textarea string.
24
- - Implement the Fetch call directly hooking into `src/lib/api.ts`.
25
- </action>
26
- <verify>test -f "frontend/src/components/dashboard/CandidateView.tsx"</verify>
27
- <done>Form securely captures PDF objects and posts to backend proxy.</done>
28
- </task>
29
-
30
- <task type="auto">
31
- <name>Build Candidate Result Visualization</name>
32
- <files>frontend/src/components/dashboard/CandidateView.tsx</files>
33
- <action>
34
- - When `data` returns, render the nested JSON.
35
- - Build a circular/progressBar for `match_score`.
36
- - Display Cards for `learning_ability`, speed index, and markdown-rendered rationale.
37
- - List the `skill_gaps` using Shadcn `<Badge>` coloring (red/yellow).
38
- </action>
39
- <verify>grep -q "Card" "frontend/src/components/dashboard/CandidateView.tsx"</verify>
40
- <done>Complete parity with the legacy visualizer mapping the `CandidateResult` schema cleanly.</done>
41
- </task>
42
-
43
- ## Success Criteria
44
- - [ ] Uploading a resume PDF successfully pushes traffic to FastAPI.
45
- - [ ] The dashboard accurately renders the comprehensive breakdown and prevents rendering crashes dynamically.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gsd/phases/7/2-SUMMARY.md DELETED
@@ -1,2 +0,0 @@
1
- # Plan 7.2 Summary: Candidate Analysis Pipeline
2
- ## Status: ✅ Complete - Built the React Candidate Dashboard view inside `CandidateView.tsx`. Successfully mapped state arrays to visually match our backend JSON schema utilizing custom tailwind colors and Shadcn `Progress` bars. Connects seamlessly with FastAPI logic.
 
 
 
.gsd/phases/7/3-PLAN.md DELETED
@@ -1,44 +0,0 @@
1
- ---
2
- phase: 7
3
- plan: 3
4
- wave: 2
5
- ---
6
-
7
- # Plan 7.3: Team Gap Analysis Pipeline
8
-
9
- ## Objective
10
- Rebuild the engineering workforce planning engine. Form input of a team profile yielding a sophisticated multi-component metric view of capability coverage and structural hire requirements.
11
-
12
- ## Context
13
- - FastAPI `teams/analyze` endpoint.
14
-
15
- ## Tasks
16
-
17
- <task type="auto">
18
- <name>Build Team Input Form</name>
19
- <files>frontend/src/components/dashboard/TeamView.tsx</files>
20
- <action>
21
- - Create `TeamView.tsx`.
22
- - Handle state arrays for adding comma-separated current team skills.
23
- - Input standard variables: local currency/market, size, and long-term project requirements string.
24
- </action>
25
- <verify>test -f "frontend/src/components/dashboard/TeamView.tsx"</verify>
26
- <done>Form cleanly validates schema limits before POSTing to proxy.</done>
27
- </task>
28
-
29
- <task type="auto">
30
- <name>Build Gap Results & JD Generator UI</name>
31
- <files>frontend/src/components/dashboard/TeamView.tsx</files>
32
- <action>
33
- - Render `coverage_score` as a master progress ring/bar.
34
- - Loop through `domain_gaps` mapping urgency (HIGH = destructive, MEDIUM = warning) onto Shadcn `<Card>` layouts.
35
- - Display generated `hire_plan` roles with expected `salary_benchmarks`.
36
- - Render the `<ScrollArea>` containing the generated precise Markdown JDs.
37
- </action>
38
- <verify>grep -q "coverage" "frontend/src/components/dashboard/TeamView.tsx"</verify>
39
- <done>The extensive team evaluation gracefully fits in standard grid layouts natively on React.</done>
40
- </task>
41
-
42
- ## Success Criteria
43
- - [ ] Team POST succeeds, generating a robust structural dashboard displaying coverage percentages.
44
- - [ ] Urgency metrics mapped to semantic tailwind tokens (red/yellow/blue).