Files
job-forge/docs/jobforge_mvp_architecture.md
2025-08-01 09:31:37 -04:00

714 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# JobForge MVP - Core Job Application Module
**Version:** 1.0.0 MVP
**Status:** Development Phase 1
**Date:** July 2025
**Scope:** Core job application workflow with essential features
**Target:** Personal use for concept validation and testing
---
## 📋 MVP Scope & Objectives
### Core Functionality
- **User Authentication**: Basic login/signup system
- **Job Application Creation**: Add new applications with job description and URL
- **3-Phase AI Workflow**: Research → Resume → Cover Letter generation
- **Document Management**: View and edit generated documents
- **Navigation Interface**: Sidebar + top bar for seamless workflow navigation
### MVP Goals
- Validate core AI workflow effectiveness
- Test user experience with Dash + Mantine interface
- Prove concept with personal job application journey
- Establish foundation for Phase 2 (post-application features)
---
## 🏗️ MVP Architecture
### System Overview
```mermaid
graph TB
subgraph "Frontend (Dash + Mantine)"
UI[Main UI]
SIDEBAR[Application Sidebar]
TOPBAR[Navigation Top Bar]
EDITOR[Document Editor]
end
subgraph "Backend API (FastAPI)"
AUTH[Authentication]
APP[Application Service]
AI[AI Orchestrator]
DOC[Document Service]
end
subgraph "AI Agents"
RESEARCH[Research Agent]
RESUME[Resume Optimizer]
COVER[Cover Letter Generator]
end
subgraph "Data Storage"
PG[(PostgreSQL + pgvector)]
FILES[Document Storage]
end
subgraph "External AI"
CLAUDE[Claude AI]
OPENAI[OpenAI Embeddings]
end
UI --> AUTH
UI --> APP
UI --> DOC
APP --> AI
AI --> RESEARCH
AI --> RESUME
AI --> COVER
APP --> PG
DOC --> FILES
RESEARCH --> CLAUDE
RESUME --> CLAUDE
COVER --> CLAUDE
AI --> OPENAI
```
---
## 🔐 User Authentication (MVP)
### Simple Authentication System
```python
class AuthenticationService:
"""Basic user authentication for MVP"""
async def register_user(self, email: str, password: str, name: str) -> User:
"""Register new user account"""
async def authenticate_user(self, email: str, password: str) -> AuthResult:
"""Login user and return JWT token"""
async def verify_token(self, token: str) -> User:
"""Verify JWT token and return user"""
async def logout_user(self, user_id: str) -> None:
"""Logout user session"""
```
### Database Schema (Users)
```sql
-- Basic user table for MVP
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Enable basic row level security
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
```
---
## 📋 Job Application Module
### Core Application Workflow
```python
class ApplicationService:
"""Core job application management"""
async def create_application(self, user_id: str, job_data: JobApplicationData) -> Application:
"""Create new job application with job description and URL"""
async def get_user_applications(self, user_id: str) -> List[Application]:
"""Get all applications for user"""
async def get_application(self, user_id: str, app_id: str) -> Application:
"""Get specific application with documents"""
async def update_application_status(self, user_id: str, app_id: str, status: str) -> None:
"""Update application status through workflow phases"""
```
### Application Data Model
```python
class JobApplicationData(BaseModel):
"""Input data for creating new application"""
job_url: Optional[str] = None
job_description: str
company_name: str
role_title: str
location: Optional[str] = None
priority_level: str = "medium"
additional_context: Optional[str] = None
class Application(BaseModel):
"""Core application entity"""
id: str
user_id: str
name: str # Auto-generated: company_role_YYYY_MM_DD
company_name: str
role_title: str
job_url: Optional[str]
job_description: str
status: ApplicationStatus # draft, research_complete, resume_ready, cover_letter_ready
# Phase completion tracking
research_completed: bool = False
resume_optimized: bool = False
cover_letter_generated: bool = False
created_at: datetime
updated_at: datetime
```
### Database Schema (Applications)
```sql
CREATE TABLE applications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
company_name VARCHAR(255) NOT NULL,
role_title VARCHAR(255) NOT NULL,
job_url TEXT,
job_description TEXT NOT NULL,
location VARCHAR(255),
priority_level VARCHAR(20) DEFAULT 'medium',
status VARCHAR(50) DEFAULT 'draft',
-- Phase tracking
research_completed BOOLEAN DEFAULT FALSE,
resume_optimized BOOLEAN DEFAULT FALSE,
cover_letter_generated BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
ALTER TABLE applications ENABLE ROW LEVEL SECURITY;
CREATE POLICY user_applications_policy ON applications
FOR ALL TO application_user
USING (user_id = current_setting('app.current_user_id')::UUID);
```
---
## 🤖 AI Processing Workflow
### 3-Phase AI Orchestrator
```python
class AIOrchestrator:
"""Orchestrates the 3-phase AI workflow"""
def __init__(self, research_agent, resume_optimizer, cover_letter_generator):
self.research_agent = research_agent
self.resume_optimizer = resume_optimizer
self.cover_letter_generator = cover_letter_generator
async def execute_research_phase(self, application_id: str) -> ResearchReport:
"""Phase 1: Job analysis and company research"""
async def execute_resume_optimization(self, application_id: str) -> OptimizedResume:
"""Phase 2: Resume optimization based on research"""
async def execute_cover_letter_generation(self, application_id: str, user_context: str) -> CoverLetter:
"""Phase 3: Cover letter generation with user inputs"""
```
### Phase 1: Research Agent
```python
class ResearchAgent:
"""Job description analysis and company research"""
async def analyze_job_description(self, job_desc: str) -> JobAnalysis:
"""Extract requirements, skills, and key information"""
async def research_company_info(self, company_name: str) -> CompanyIntelligence:
"""Basic company research and insights"""
async def generate_strategic_positioning(self, job_analysis: JobAnalysis) -> StrategicPositioning:
"""Determine optimal candidate positioning"""
async def create_research_report(self, job_desc: str, company_name: str) -> ResearchReport:
"""Complete research phase output"""
```
### Phase 2: Resume Optimizer
```python
class ResumeOptimizer:
"""Resume optimization based on job requirements"""
async def analyze_resume_portfolio(self, user_id: str) -> ResumePortfolio:
"""Load and analyze user's resume library"""
async def optimize_resume_for_job(self, portfolio: ResumePortfolio, research: ResearchReport) -> OptimizedResume:
"""Create job-specific optimized resume"""
async def validate_resume_optimization(self, resume: OptimizedResume) -> ValidationReport:
"""Ensure resume meets requirements and constraints"""
```
### Phase 3: Cover Letter Generator
```python
class CoverLetterGenerator:
"""Cover letter generation with user context"""
async def analyze_writing_style(self, user_id: str) -> WritingStyle:
"""Analyze user's writing patterns from reference documents"""
async def generate_cover_letter(self, research: ResearchReport, resume: OptimizedResume,
user_context: str, writing_style: WritingStyle) -> CoverLetter:
"""Generate personalized cover letter"""
async def validate_cover_letter(self, cover_letter: CoverLetter) -> ValidationReport:
"""Ensure cover letter quality and authenticity"""
```
---
## 📄 Document Management
### Document Storage & Retrieval
```python
class DocumentService:
"""Handle document storage and retrieval"""
async def save_document(self, user_id: str, app_id: str, doc_type: str, content: str) -> None:
"""Save generated document (research, resume, cover letter)"""
async def get_document(self, user_id: str, app_id: str, doc_type: str) -> Document:
"""Retrieve document for viewing/editing"""
async def update_document(self, user_id: str, app_id: str, doc_type: str, content: str) -> None:
"""Update document after user editing"""
async def get_all_documents(self, user_id: str, app_id: str) -> ApplicationDocuments:
"""Get all documents for an application"""
```
### Document Models
```python
class Document(BaseModel):
"""Base document model"""
id: str
application_id: str
document_type: str # research_report, optimized_resume, cover_letter
content: str
created_at: datetime
updated_at: datetime
class ApplicationDocuments(BaseModel):
"""All documents for an application"""
research_report: Optional[Document] = None
optimized_resume: Optional[Document] = None
cover_letter: Optional[Document] = None
```
### Database Schema (Documents)
```sql
CREATE TABLE documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
application_id UUID REFERENCES applications(id) ON DELETE CASCADE,
document_type VARCHAR(50) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
CREATE POLICY user_documents_policy ON documents
FOR ALL TO application_user
USING (
application_id IN (
SELECT id FROM applications
WHERE user_id = current_setting('app.current_user_id')::UUID
)
);
```
---
## 🎨 Frontend Interface (Dash + Mantine)
### Main Application Layout
```python
class JobForgeApp:
"""Main Dash application layout"""
def create_layout(self):
return dmc.MantineProvider([
dmc.AppShell([
dmc.Navbar([
ApplicationSidebar()
], width={"base": 300}),
dmc.Main([
ApplicationTopBar(),
MainContent()
])
])
])
```
### Application Sidebar
```python
class ApplicationSidebar:
"""Sidebar with applications list and navigation"""
def render(self, user_id: str):
return dmc.Stack([
# New Application Button
dmc.Button(
" New Application",
id="new-app-btn",
fullWidth=True,
variant="filled"
),
# Applications List
dmc.Title("Applications", order=4),
dmc.ScrollArea([
ApplicationCard(app) for app in self.get_user_applications(user_id)
]),
# Resume Library Section
dmc.Divider(),
dmc.Title("Resume Library", order=4),
ResumeLibrarySection()
])
class ApplicationCard:
"""Individual application card in sidebar"""
def render(self, application: Application):
return dmc.Card([
dmc.Group([
dmc.Text(application.company_name, weight=600),
StatusBadge(application.status)
]),
dmc.Text(application.role_title, size="sm", color="dimmed"),
dmc.Text(application.created_at.strftime("%Y-%m-%d"), size="xs")
], id=f"app-card-{application.id}")
```
### Application Top Bar Navigation
```python
class ApplicationTopBar:
"""Top navigation bar for application phases"""
def render(self, application: Application):
return dmc.Group([
# Phase Navigation Buttons
PhaseButton("Research", "research", application.research_completed),
PhaseButton("Resume", "resume", application.resume_optimized),
PhaseButton("Cover Letter", "cover_letter", application.cover_letter_generated),
# Application Actions
dmc.Spacer(),
dmc.ActionIcon(
DashIconify(icon="tabler:settings"),
id="app-settings-btn"
)
])
class PhaseButton:
"""Navigation button for each phase"""
def render(self, label: str, phase: str, completed: bool):
icon = "tabler:check" if completed else "tabler:clock"
color = "green" if completed else "gray"
return dmc.Button([
DashIconify(icon=icon),
dmc.Text(label, ml="xs")
],
variant="subtle" if not completed else "filled",
color=color,
id=f"phase-{phase}-btn"
)
```
### Document Editor Interface
```python
class DocumentEditor:
"""Markdown document editor with preview"""
def render(self, document: Document):
return dmc.Container([
dmc.Grid([
# Editor Column
dmc.Col([
dmc.Title(f"Edit {document.document_type.replace('_', ' ').title()}", order=3),
dmc.Textarea(
value=document.content,
placeholder="Document content...",
minRows=20,
autosize=True,
id=f"editor-{document.document_type}"
),
dmc.Group([
dmc.Button("Save Changes", id="save-btn"),
dmc.Button("Cancel", variant="outline", id="cancel-btn")
])
], span=6),
# Preview Column
dmc.Col([
dmc.Title("Preview", order=3),
dmc.Container([
dcc.Markdown(document.content, id="preview-content")
], style={"border": "1px solid #e0e0e0", "padding": "1rem", "minHeight": "500px"})
], span=6)
])
])
```
---
## 🗄️ MVP Database Schema
### Complete Database Setup
```sql
-- Enable required extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS vector;
-- Users table
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Applications table
CREATE TABLE applications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
company_name VARCHAR(255) NOT NULL,
role_title VARCHAR(255) NOT NULL,
job_url TEXT,
job_description TEXT NOT NULL,
location VARCHAR(255),
priority_level VARCHAR(20) DEFAULT 'medium',
status VARCHAR(50) DEFAULT 'draft',
research_completed BOOLEAN DEFAULT FALSE,
resume_optimized BOOLEAN DEFAULT FALSE,
cover_letter_generated BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Documents table
CREATE TABLE documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
application_id UUID REFERENCES applications(id) ON DELETE CASCADE,
document_type VARCHAR(50) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
UNIQUE(application_id, document_type)
);
-- Resume library table
CREATE TABLE user_resumes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
focus_area VARCHAR(100),
is_primary BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Basic vector embeddings (for future enhancement)
CREATE TABLE document_embeddings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
document_id UUID REFERENCES documents(id) ON DELETE CASCADE,
embedding vector(1536),
created_at TIMESTAMP DEFAULT NOW()
);
-- Row Level Security
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
ALTER TABLE applications ENABLE ROW LEVEL SECURITY;
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
ALTER TABLE user_resumes ENABLE ROW LEVEL SECURITY;
-- Security policies
CREATE POLICY user_own_data ON applications FOR ALL USING (user_id = current_setting('app.current_user_id')::UUID);
CREATE POLICY user_own_documents ON documents FOR ALL USING (
application_id IN (SELECT id FROM applications WHERE user_id = current_setting('app.current_user_id')::UUID)
);
CREATE POLICY user_own_resumes ON user_resumes FOR ALL USING (user_id = current_setting('app.current_user_id')::UUID);
```
---
## 🚀 MVP Development Plan
### Development Phases
#### **Week 1-2: Foundation Setup**
- Docker development environment
- PostgreSQL database with basic schema
- FastAPI backend with authentication endpoints
- Basic Dash + Mantine frontend structure
#### **Week 3-4: Core Application Module**
- Application creation and listing
- Database integration with user isolation
- Basic sidebar and navigation UI
- Application status tracking
#### **Week 5-6: AI Workflow Implementation**
- Research Agent with Claude integration
- Resume Optimizer with portfolio handling
- Cover Letter Generator with user context
- Document storage and retrieval system
#### **Week 7-8: Frontend Polish & Integration**
- Document editor with markdown support
- Real-time status updates during AI processing
- Phase navigation and progress tracking
- Error handling and user feedback
### MVP Success Criteria
- ✅ User can register/login securely
- ✅ User can create job applications with description/URL
- ✅ AI generates research report automatically
- ✅ AI optimizes resume based on job requirements
- ✅ AI generates cover letter with user context
- ✅ User can view and edit all generated documents
- ✅ Smooth navigation between application phases
- ✅ Data persisted securely with user isolation
---
## 🐳 Docker Development Setup
### Development Environment
```yaml
# docker-compose.yml
version: '3.8'
services:
postgres:
image: pgvector/pgvector:pg16
environment:
POSTGRES_DB: jobforge_mvp
POSTGRES_USER: jobforge_user
POSTGRES_PASSWORD: jobforge_password
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./database/init.sql:/docker-entrypoint-initdb.d/init.sql
backend:
build:
context: .
dockerfile: Dockerfile.backend
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql+asyncpg://jobforge_user:jobforge_password@postgres:5432/jobforge_mvp
- CLAUDE_API_KEY=${CLAUDE_API_KEY}
- OPENAI_API_KEY=${OPENAI_API_KEY}
volumes:
- ./src:/app/src
depends_on:
- postgres
command: uvicorn src.backend.main:app --host 0.0.0.0 --port 8000 --reload
frontend:
build:
context: .
dockerfile: Dockerfile.frontend
ports:
- "8501:8501"
environment:
- BACKEND_URL=http://backend:8000
volumes:
- ./src/frontend:/app/src/frontend
depends_on:
- backend
command: python src/frontend/main.py
volumes:
postgres_data:
```
---
## 📁 MVP Project Structure
```
jobforge-mvp/
├── docker-compose.yml
├── Dockerfile.backend
├── Dockerfile.frontend
├── requirements-backend.txt
├── requirements-frontend.txt
├── .env.example
├── database/
│ └── init.sql
├── src/
│ ├── backend/
│ │ ├── main.py
│ │ ├── api/
│ │ │ ├── auth.py
│ │ │ ├── applications.py
│ │ │ ├── documents.py
│ │ │ └── processing.py
│ │ ├── services/
│ │ │ ├── auth_service.py
│ │ │ ├── application_service.py
│ │ │ ├── document_service.py
│ │ │ └── ai_orchestrator.py
│ │ ├── database/
│ │ │ ├── connection.py
│ │ │ └── models.py
│ │ └── models/
│ │ ├── requests.py
│ │ └── responses.py
│ ├── frontend/
│ │ ├── main.py
│ │ ├── components/
│ │ │ ├── sidebar.py
│ │ │ ├── topbar.py
│ │ │ └── editor.py
│ │ ├── pages/
│ │ │ ├── login.py
│ │ │ ├── dashboard.py
│ │ │ └── application.py
│ │ └── api_client/
│ │ └── client.py
│ ├── agents/
│ │ ├── research_agent.py
│ │ ├── resume_optimizer.py
│ │ ├── cover_letter_generator.py
│ │ └── claude_client.py
│ └── helpers/
│ ├── validators.py
│ └── formatters.py
└── user_data/
└── resumes/
```
---
*This MVP architecture focuses on delivering the core job application workflow with essential features. It establishes the foundation for Phase 2 development while providing immediate value for personal job application management and concept validation.*