A complete Applicant Tracking System that combines resume parsing and scoring with social media intelligence to provide comprehensive, data-driven candidate evaluations.
hiresignal/
├── backend/
│ ├── api/ # FastAPI main application
│ ├── resume/ # Resume parsing & scoring engine
│ ├── social/ # Social media intelligence (LangGraph agents)
│ ├── synthesis/ # Final scoring & conclusion engine
│ ├── models/ # Pydantic v2 schemas
│ ├── core/ # Config, auth, cache, rate limiting
│ └── tests/ # pytest suite (80%+ coverage)
├── frontend/ # React dashboard for parallel candidate testing
├── docker-compose.yml
├── .env.example
└── README.md
| Module | Description | Endpoint |
|---|---|---|
| Resume Scoring | Parse PDF/DOCX resumes, score against job descriptions | POST /api/v1/resume/score |
| Social Intelligence | Analyze GitHub, LinkedIn, Twitter via LangGraph agents | POST /api/v1/social/analyze |
| Candidate Evaluation | Combine scores into final weighted report | POST /api/v1/candidate/evaluate |
| Frontend Dashboard | Upload and evaluate multiple candidates in parallel | http://127.0.0.1:5173 |
- Python 3.12+
- Docker & Docker Compose (optional, recommended)
- OpenAI or OpenRouter API key (optional; enables embeddings and LLM synthesis)
# 1. Clone and navigate
cd hiresignal
# 2. Copy environment config
cp .env.example .env
# Edit .env and configure either OpenAI or OpenRouter
# 3. Start all services
docker-compose up --build
# 4. API is available at http://localhost:8000
# 5. Frontend dashboard at http://localhost:5173
# 6. API docs at http://localhost:8000/docs
# 7. Flower (Celery monitoring) at http://localhost:5555# 1. Create virtual environment
python -m venv venv
source venv/bin/activate # Linux/Mac
# venv\Scripts\activate # Windows
# 2. Install dependencies
cd backend
pip install -r requirements.txt
# 3. Set environment variables
cp ../.env.example ../.env
# Edit .env with your API keys
# 4. Start Redis (required for caching)
# macOS: brew install redis && redis-server
# Linux: sudo apt install redis-server && redis-server
# 5. Run the application
uvicorn backend.api.main:app --reload --port 8000
# 6. Start the frontend dashboard in a second terminal
cd ../frontend
npm install
npm run dev
# 7. Run backend tests
cd ../backend
pytest tests/ -v --tb=shortThe React dashboard lives in frontend/ and gives you an end-to-end candidate testing UI:
- Batch upload PDF/DOCX resumes.
- Configure API URL, API key, job title, and job description.
- Add GitHub usernames manually or paste one username per line for a batch.
- Run multiple candidate pipelines in parallel with a configurable concurrency limit.
- Review per-candidate logs, warnings, scores, final tier, recommendations, and export CSV/JSON results.
Run it locally:
cd frontend
npm install
npm run devOpen http://127.0.0.1:5173 while the API is running on http://127.0.0.1:8000.
Interactive API docs available at http://localhost:8000/docs (Swagger UI) or http://localhost:8000/redoc (ReDoc).
All API endpoints require the X-API-Key header:
X-API-Key: dev-api-key-change-in-production100 requests per minute per API key.
Parse and score a resume against a job description.
Endpoint: POST /api/v1/resume/score
Request:
curl -X POST http://localhost:8000/api/v1/resume/score \
-H "X-API-Key: dev-api-key-change-in-production" \
-F "job_description=We are looking for a Senior Python Backend Engineer with 5+ years of experience in FastAPI, PostgreSQL, Docker, and Kubernetes. AWS certification preferred." \
-F "resume_file=@/path/to/resume.pdf" \
-F "github_username=janesmith"Response:
{
"total_score": 78.5,
"breakdown": {
"skill_match": 32.0,
"experience_depth": 24.5,
"education_certs": 14.0,
"format_completeness": 8.0
},
"extracted_data": {
"name": "Jane Smith",
"email": "[email protected]",
"phone": "+1-555-123-4567",
"skills": ["python", "fastapi", "docker", "kubernetes", "aws", "postgresql"],
"experience": [...],
"education": [...],
"certifications": [...]
},
"tier": "Tier 2",
"processing_time_ms": 2340,
"cached": false,
"warnings": []
}Fetch and analyze GitHub, LinkedIn, and Twitter profiles.
Endpoint: POST /api/v1/social/analyze
Request:
curl -X POST http://localhost:8000/api/v1/social/analyze \
-H "X-API-Key: dev-api-key-change-in-production" \
-H "Content-Type: application/json" \
-d '{
"candidate_email": "[email protected]",
"github_username": "janesmith",
"linkedin_url": "https://linkedin.com/in/janesmith",
"twitter_handle": "@janesmith",
"claimed_skills": ["python", "fastapi", "docker", "kubernetes", "aws"]
}'Response:
{
"social_score": 72.0,
"github": {
"username": "janesmith",
"public_repos": 25,
"followers": 150,
"bio": "Senior Backend Engineer | Python enthusiast",
"repos": [...],
"languages": {"Python": 15, "Go": 5, "TypeScript": 3}
},
"linkedin": {
"retrieved": false
},
"twitter": {
"retrieved": false
},
"findings": {
"technical_depth": "Strong Python ecosystem expertise...",
"contribution_quality": "Well-documented repos...",
"thought_leadership": "Active blog contributor...",
"community_engagement": "150 followers...",
"activity_consistency": "Regular commits..."
},
"tech_verification": {
"verified": ["python", "fastapi", "docker", "kubernetes"],
"unverified": ["aws"],
"discrepancies": [],
"confidence": 0.82
},
"red_flags": [],
"warnings": [
"LinkedIn API key not configured; skipping LinkedIn analysis",
"Twitter Bearer Token not configured; skipping Twitter analysis"
],
"processing_time_ms": 4520,
"cached": false
}Combine resume and social scores into a final evaluation report.
Endpoint: POST /api/v1/candidate/evaluate
Request:
curl -X POST http://localhost:8000/api/v1/candidate/evaluate \
-H "X-API-Key: dev-api-key-change-in-production" \
-H "Content-Type: application/json" \
-d '{
"resume_score": 82.5,
"social_score": 72.0,
"candidate_name": "Jane Smith",
"candidate_email": "[email protected]",
"job_title": "Senior Python Backend Engineer"
}'Response:
{
"report": {
"candidate_name": "Jane Smith",
"candidate_email": "[email protected]",
"job_title": "Senior Python Backend Engineer",
"resume_score": 82.5,
"social_score": 72.0,
"weighted_total": 78.3,
"tier": {
"tier": "Tier 2",
"label": "Strong Candidate",
"recommendation": "Human review required before proceeding",
"confidence": 0.80
},
"conclusion": "Jane Smith presents a strong profile for Senior Python Backend Engineer with a weighted score of 78.3/100. The resume demonstrates solid qualifications across all required skill areas, and the GitHub analysis confirms active development in Python and FastAPI...",
"strengths": [
"Strong resume with relevant skills and experience",
"Excellent skill-to-job match",
"GitHub profile supports technical claims",
"Good overall alignment between stated and demonstrated capabilities"
],
"concerns": [],
"next_steps": "Assign to recruiter for human review. Schedule 15-min screening call. Prepare follow-up questions on experience gaps.",
"processed_at": "2024-06-19T12:00:00+00:00"
},
"processing_time_ms": 850,
"cached": false
}Check system health status.
Endpoint: GET /health
curl http://localhost:8000/health| Category | Max Points | Criteria |
|---|---|---|
| Skill Match | 40 | Exact keyword match (25) + Semantic similarity via embeddings (15) |
| Experience Depth | 30 | Years relevant (15) + Seniority (10) + Industry match (5) |
| Education & Certs | 20 | Degree relevance (10) + Certifications (10) |
| Format & Completeness | 10 | ATS-parseable (5) + Sections complete (5) |
Determined by LLM analysis of GitHub/LinkedIn/Twitter data:
- Technical depth and language diversity
- Open source contribution quality (stars, forks, documentation)
- Thought leadership (blog posts, talks, README quality)
- Community engagement (followers, collaboration)
- Activity consistency over time
- Tech stack verification against resume claims
- Red flag detection
| Score | Tier | Action |
|---|---|---|
| 90-100 | Tier 1 | Auto-advance to interview |
| 75-89 | Tier 2 | Human review required |
| 60-74 | Tier 3 | Conditional - gather more data |
| <60 | Reject | Auto-reject with feedback |
The social media intelligence module uses a sequential LangGraph workflow:
[Start] -> [GitHub Fetch] -> [LinkedIn Fetch] -> [Twitter Fetch] -> [LLM Synthesis] -> [End]
| | | |
Repos, Stars Profile Data Posts, Metrics Score, Findings,
Languages (if API key) (if API key) Verification,
Contributions Red Flags
- LinkedIn and Twitter are gracefully skipped if API keys are not configured
- All LLM calls have fallback heuristics if the API fails
- No raw social media content is stored - only synthesized insights
cd backend
pytest tests/ -v
# With coverage report
pytest tests/ -v --cov=backend --cov-report=term-missing --cov-fail-under=80| Test File | Coverage |
|---|---|
test_resume.py |
Parser helpers, keyword matching, scoring logic, tier assignment |
test_social.py |
GitHub API mocking, LinkedIn/Twitter skip logic, heuristic fallback |
test_synthesis.py |
Weighted totals, tier boundaries, conclusion generation |
test_api.py |
End-to-end endpoint tests with mocked external APIs |
backend/
├── api/
│ ├── main.py # FastAPI app factory
│ ├── health.py # Health check endpoints
│ └── middleware.py # (reserved for future middleware)
├── resume/
│ ├── parser.py # PDF/DOCX text extraction & structured parsing
│ ├── scorer.py # Scoring engine with embeddings
│ └── routes.py # FastAPI routes for resume endpoints
├── social/
│ ├── agents.py # LangGraph workflow + GitHub/LinkedIn/Twitter fetchers
│ └── routes.py # FastAPI routes for social endpoints
├── synthesis/
│ ├── engine.py # Weighted scoring, tier assignment, conclusion generation
│ └── routes.py # FastAPI routes for evaluation endpoints
├── models/
│ └── schemas.py # All Pydantic v2 request/response models
├── core/
│ ├── config.py # Settings management (pydantic-settings)
│ ├── auth.py # API key authentication
│ ├── cache.py # Redis cache utilities
│ ├── rate_limiter.py # Sliding window rate limiting
│ ├── exceptions.py # Custom exception hierarchy
│ └── logging_config.py # Structured logging setup
└── tests/
├── conftest.py # Shared fixtures and test data
├── fixtures/ # Sample resume files
├── test_resume.py
├── test_social.py
├── test_synthesis.py
└── test_api.py
| Variable | Required | Default | Description |
|---|---|---|---|
LLM_PROVIDER |
No | openai |
AI provider: openai or openrouter |
LLM_MODEL |
No | gpt-4o-mini |
Any model ID supported by the selected provider |
EMBEDDING_MODEL |
No | text-embedding-3-small |
Embedding model ID supported by the selected provider |
OPENAI_API_KEY |
Conditional | - | Required when LLM_PROVIDER=openai |
OPENROUTER_API_KEY |
Conditional | - | Required when LLM_PROVIDER=openrouter |
OPENROUTER_BASE_URL |
No | https://openrouter.ai/api/v1 |
OpenRouter OpenAI-compatible API URL |
OPENROUTER_SITE_URL |
No | http://localhost:8000 |
Optional app URL sent to OpenRouter |
OPENROUTER_APP_NAME |
No | HireSignal |
Optional app title sent to OpenRouter |
API_KEY |
Yes | dev-api-key-change-in-production |
Internal API key for endpoint auth |
REDIS_URL |
No | redis://localhost:6379/0 |
Redis connection string |
QDRANT_HOST |
No | localhost |
Qdrant vector DB host |
LINKEDIN_API_KEY |
No | - | LinkedIn API key (optional) |
TWITTER_BEARER_TOKEN |
No | - | Twitter/X Bearer Token (optional) |
RESUME_WEIGHT |
No | 0.60 |
Resume score weight (0-1) |
SOCIAL_WEIGHT |
No | 0.40 |
Social score weight (0-1) |
RATE_LIMIT_REQUESTS_PER_MINUTE |
No | 100 |
Rate limit per API key |
- Python 3.12+ - Core language
- FastAPI + Uvicorn - Web framework
- Pydantic v2 - Data validation
- pdfplumber + python-docx - Resume parsing
- OpenAI-compatible AI APIs - OpenAI or custom OpenRouter chat/embedding models
- LangGraph - Social media agent workflow
- Redis - Caching + rate limiting
- Qdrant - Vector database for skill embeddings
- Celery + Flower - Background tasks + monitoring
- Docker + Docker Compose - Containerization
- pytest + httpx - Testing
MIT License - See LICENSE file for details.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Please ensure tests pass (pytest) and code follows the existing style before submitting.