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
- .gitignore +6 -0
- .gsd/DECISIONS.md +0 -50
- .gsd/JOURNAL.md +0 -21
- .gsd/REQUIREMENTS.md +0 -28
- .gsd/ROADMAP.md +0 -106
- .gsd/SPEC.md +0 -63
- .gsd/STATE.md +0 -21
- .gsd/TODO.md +0 -3
- .gsd/examples/cross-platform.md +0 -99
- .gsd/examples/multi-wave-workflow.md +0 -256
- .gsd/examples/quick-reference.md +0 -73
- .gsd/examples/workflow-example.md +0 -139
- .gsd/phases/1/1-PLAN.md +0 -162
- .gsd/phases/1/1-SUMMARY.md +0 -18
- .gsd/phases/1/2-PLAN.md +0 -129
- .gsd/phases/1/2-SUMMARY.md +0 -16
- .gsd/phases/1/3-PLAN.md +0 -144
- .gsd/phases/1/3-SUMMARY.md +0 -25
- .gsd/phases/10/1-PLAN.md +0 -46
- .gsd/phases/2/1-PLAN.md +0 -170
- .gsd/phases/2/1-SUMMARY.md +0 -11
- .gsd/phases/2/2-PLAN.md +0 -153
- .gsd/phases/2/2-SUMMARY.md +0 -13
- .gsd/phases/2/3-PLAN.md +0 -208
- .gsd/phases/2/3-SUMMARY.md +0 -15
- .gsd/phases/2/RESEARCH.md +0 -70
- .gsd/phases/3/1-PLAN.md +0 -113
- .gsd/phases/3/1-SUMMARY.md +0 -14
- .gsd/phases/3/2-PLAN.md +0 -195
- .gsd/phases/3/2-SUMMARY.md +0 -11
- .gsd/phases/3/3-PLAN.md +0 -169
- .gsd/phases/3/3-SUMMARY.md +0 -14
- .gsd/phases/4/1-PLAN.md +0 -121
- .gsd/phases/4/1-SUMMARY.md +0 -2
- .gsd/phases/4/2-PLAN.md +0 -171
- .gsd/phases/4/2-SUMMARY.md +0 -2
- .gsd/phases/4/3-PLAN.md +0 -118
- .gsd/phases/4/3-SUMMARY.md +0 -2
- .gsd/phases/6/1-PLAN.md +0 -56
- .gsd/phases/6/1-SUMMARY.md +0 -2
- .gsd/phases/6/2-PLAN.md +0 -53
- .gsd/phases/6/2-SUMMARY.md +0 -2
- .gsd/phases/6/3-PLAN.md +0 -56
- .gsd/phases/6/3-SUMMARY.md +0 -2
- .gsd/phases/6/VERIFICATION.md +0 -8
- .gsd/phases/7/1-PLAN.md +0 -54
- .gsd/phases/7/1-SUMMARY.md +0 -2
- .gsd/phases/7/2-PLAN.md +0 -45
- .gsd/phases/7/2-SUMMARY.md +0 -2
- .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).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|