feat: initialize project structure with SQLite database, crawler framework, and LLM-based JD analysis integration
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hireme/hireme/internal/analyzer"
|
||||
"github.com/hireme/hireme/internal/config"
|
||||
"github.com/hireme/hireme/internal/db"
|
||||
"github.com/hireme/hireme/internal/service"
|
||||
"github.com/hireme/hireme/internal/ui"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var cfg *config.Config
|
||||
|
||||
func newRootCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "hireme",
|
||||
Short: "Hireme (GJCC) - High Performance Job Application Command Center",
|
||||
Long: `Hireme is a high-performance single-binary job application and tracking command center written in Go.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cfg.Normalize()
|
||||
|
||||
log.Println("==========================================================")
|
||||
log.Println("🚀 Starting Hireme (GJCC) Job Application Command Center")
|
||||
log.Println("==========================================================")
|
||||
log.Printf("[Config] Port: %s | DB Path: %s | Target Config: %s | Active LLM: %s",
|
||||
cfg.Port, cfg.DBPath, cfg.TargetConfig, cfg.LLMProvider)
|
||||
|
||||
// Ensure DB directory exists
|
||||
dbDir := filepath.Dir(cfg.DBPath)
|
||||
if dbDir != "." && dbDir != "" {
|
||||
_ = os.MkdirAll(dbDir, 0755)
|
||||
}
|
||||
|
||||
// Initialize Database
|
||||
database, err := db.InitDB(cfg.DBPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fatal DB error: %w", err)
|
||||
}
|
||||
defer database.Close()
|
||||
|
||||
// Initialize LLM Analyzer
|
||||
llmAnalyzer, err := analyzer.NewAnalyzer(cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fatal Analyzer setup error: %w", err)
|
||||
}
|
||||
|
||||
// Initialize Pipeline Service
|
||||
pipeline := service.NewPipelineService(database, llmAnalyzer)
|
||||
|
||||
// Load targets from YAML config if database is empty
|
||||
if err := pipeline.LoadTargetsFromYAML(cfg.TargetConfig); err != nil {
|
||||
log.Printf("[Main] Target YAML loading status: %v", err)
|
||||
}
|
||||
|
||||
// Setup UI Server & Routes
|
||||
server := ui.NewServer(cfg, database, pipeline)
|
||||
mux := http.NewServeMux()
|
||||
server.RegisterRoutes(mux)
|
||||
|
||||
addr := fmt.Sprintf(":%s", cfg.Port)
|
||||
log.Printf("✨ Hireme Command Center is live at http://localhost:%s", cfg.Port)
|
||||
return http.ListenAndServe(addr, mux)
|
||||
},
|
||||
}
|
||||
|
||||
cfg = config.RegisterFlags(cmd.Flags())
|
||||
return cmd
|
||||
}
|
||||
|
||||
func main() {
|
||||
rootCmd := newRootCmd()
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hireme/hireme/internal/analyzer"
|
||||
"github.com/hireme/hireme/internal/config"
|
||||
"github.com/hireme/hireme/internal/db"
|
||||
"github.com/hireme/hireme/internal/service"
|
||||
"github.com/hireme/hireme/internal/ui"
|
||||
)
|
||||
|
||||
func TestFullApplicationIntegration(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
dbPath := filepath.Join(tempDir, "test_hireme.db")
|
||||
yamlPath := filepath.Join(tempDir, "test_targets.yaml")
|
||||
|
||||
yamlContent := `targets:
|
||||
- name: "Google Software Engineer (Seattle)"
|
||||
target_url: "https://www.google.com/about/careers/applications/jobs/results/?employment_type=FULL_TIME&q=%22Software%20Engineer%22&location=Seattle%2C%20WA%2C%20USA&target_level=MID"
|
||||
platform: "google_jobs"
|
||||
is_active: true
|
||||
`
|
||||
if err := os.WriteFile(yamlPath, []byte(yamlContent), 0644); err != nil {
|
||||
t.Fatalf("failed to create test targets.yaml: %v", err)
|
||||
}
|
||||
|
||||
cfg := &config.Config{
|
||||
Port: "8080",
|
||||
DBPath: dbPath,
|
||||
TargetConfig: yamlPath,
|
||||
LLMProvider: "mock",
|
||||
}
|
||||
|
||||
database, err := db.InitDB(cfg.DBPath)
|
||||
if err != nil {
|
||||
t.Fatalf("InitDB failed: %v", err)
|
||||
}
|
||||
defer database.Close()
|
||||
|
||||
llmAnalyzer, err := analyzer.NewAnalyzer(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewAnalyzer failed: %v", err)
|
||||
}
|
||||
|
||||
pipeline := service.NewPipelineService(database, llmAnalyzer)
|
||||
|
||||
// Verify target loading from YAML into SQLite
|
||||
if err := pipeline.LoadTargetsFromYAML(cfg.TargetConfig); err != nil {
|
||||
t.Fatalf("LoadTargetsFromYAML failed: %v", err)
|
||||
}
|
||||
|
||||
targets, err := database.GetAllTargets()
|
||||
if err != nil {
|
||||
t.Fatalf("GetAllTargets failed: %v", err)
|
||||
}
|
||||
if len(targets) != 1 {
|
||||
t.Errorf("expected 1 target from YAML, got %d", len(targets))
|
||||
}
|
||||
|
||||
// Verify jobs start empty on clean SQLite DB startup (0 jobs)
|
||||
jobs, err := database.GetJobsWithAnalysis()
|
||||
if err != nil {
|
||||
t.Fatalf("GetJobsWithAnalysis failed: %v", err)
|
||||
}
|
||||
if len(jobs) != 0 {
|
||||
t.Errorf("expected 0 jobs on clean startup, got %d", len(jobs))
|
||||
}
|
||||
|
||||
// Setup UI Server & routes
|
||||
server := ui.NewServer(cfg, database, pipeline)
|
||||
mux := http.NewServeMux()
|
||||
server.RegisterRoutes(mux)
|
||||
|
||||
// Test GET /
|
||||
reqRoot := httptest.NewRequest("GET", "/", nil)
|
||||
wRoot := httptest.NewRecorder()
|
||||
mux.ServeHTTP(wRoot, reqRoot)
|
||||
|
||||
if wRoot.Code != http.StatusOK {
|
||||
t.Errorf("expected 200 OK for GET /, got %d", wRoot.Code)
|
||||
}
|
||||
if !strings.Contains(wRoot.Body.String(), "Hireme") {
|
||||
t.Errorf("expected homepage HTML to contain 'Hireme'")
|
||||
}
|
||||
|
||||
// Test GET /targets
|
||||
reqTargets := httptest.NewRequest("GET", "/targets", nil)
|
||||
wTargets := httptest.NewRecorder()
|
||||
mux.ServeHTTP(wTargets, reqTargets)
|
||||
|
||||
if wTargets.Code != http.StatusOK {
|
||||
t.Errorf("expected 200 OK for GET /targets, got %d", wTargets.Code)
|
||||
}
|
||||
|
||||
// Test GET /jobs
|
||||
reqJobs := httptest.NewRequest("GET", "/jobs", nil)
|
||||
wJobs := httptest.NewRecorder()
|
||||
mux.ServeHTTP(wJobs, reqJobs)
|
||||
|
||||
if wJobs.Code != http.StatusOK {
|
||||
t.Errorf("expected 200 OK for GET /jobs, got %d", wJobs.Code)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user