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

22 KiB
Raw Blame History

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

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

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)

-- 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

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

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)

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

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

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

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

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

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

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)

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

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

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

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

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

-- 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

# 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.