Skip to content

ofcRS/ullgetthejob-core

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

31 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ”₯ UllGetTheJob Core

Phoenix-powered orchestrator for intelligent job applications
The single source of truth for database schema, HH.ru integration, and real-time job orchestration

Elixir Phoenix PostgreSQL


πŸ“– Overview

UllGetTheJob Core is the backend orchestrator that powers the entire job application automation system. Built with Phoenix and Elixir, it provides:

  • πŸ—„οΈ Database Schema Management - Ecto migrations and PostgreSQL integration
  • πŸ” HH.ru OAuth Flow - Complete authentication with token management
  • πŸ”„ Job Fetching Orchestrator - Periodic job search with rate limiting
  • πŸ“‘ WebSocket Broadcasting - Real-time job updates to connected clients
  • 🎯 Application Submission - HH.ru API integration for resume operations
  • ⚑ Rate Limiting - Token bucket algorithm for API quota management

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Phoenix Core                          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  HH.ru API   β”‚  β”‚ Rate Limiter β”‚  β”‚ Job Fetcher  β”‚ β”‚
β”‚  β”‚   Client     β”‚  β”‚  (GenServer) β”‚  β”‚(Orchestrator)β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚         β”‚                  β”‚                  β”‚         β”‚
β”‚         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β”‚
β”‚                            β”‚                            β”‚
β”‚                   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”                   β”‚
β”‚                   β”‚  Ecto + Postgres β”‚                  β”‚
β”‚                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                β”‚                       β”‚
         REST API (Node BFF)    WebSocket (Broadcast)

πŸš€ Quick Start

Prerequisites

  • Elixir ~> 1.15
  • Erlang ~> 26
  • PostgreSQL 14+
  • Mix (comes with Elixir)

Installation

# Clone the repository
git clone <repo-url>
cd ullgetthejob-core

# Install dependencies
mix deps.get

# Setup database (create, migrate, seed)
mix setup

# Start Phoenix server
mix phx.server

Server runs at http://localhost:4000 πŸŽ‰

Development with IEx

# Start with interactive shell
iex -S mix phx.server

# Useful IEx commands:
iex> Core.HH.Client.fetch_vacancies(%{text: "Elixir"})
iex> Core.Jobs.Orchestrator.fetch_jobs_now("user_id")
iex> Core.RateLimiter.get_status("user_id")

πŸ”§ Configuration

Environment Variables

Create a .env file or set these in your environment:

# Database
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/ullget_dev"

# HH.ru API
HH_ACCESS_TOKEN="your_hh_api_token"
HH_CLIENT_ID="your_oauth_client_id"
HH_CLIENT_SECRET="your_oauth_client_secret"
HH_REDIRECT_URI="http://localhost:5173/auth/callback"

# Security
ORCHESTRATOR_SECRET="shared_secret_between_core_and_api"
SECRET_KEY_BASE="generate_with_mix_phx_gen_secret"

# External Services
API_BASE_URL="http://localhost:3000"  # Node BFF URL

Generate Secrets

# Generate SECRET_KEY_BASE
mix phx.gen.secret

# Generate ORCHESTRATOR_SECRET
mix phx.gen.secret 32

πŸ“‘ API Endpoints

Public API (for Node BFF)

Job Search

POST /api/jobs/search
Content-Type: application/json
X-Core-Secret: <orchestrator_secret>

{
  "text": "JavaScript Developer",
  "area": "1",
  "experience": "between1And3",
  "employment": "full",
  "schedule": "remote"
}

Application Submission

POST /api/applications/submit
Content-Type: application/json
X-Core-Secret: <orchestrator_secret>

{
  "user_id": "uuid",
  "job_external_id": "hh_vacancy_id",
  "customized_cv": { /* parsed CV object */ },
  "cover_letter": "Dear Hiring Manager..."
}

OAuth Flow (HH.ru)

1. Initiate OAuth

GET /auth/hh/redirect

Response:
{
  "url": "https://hh.ru/oauth/authorize?...",
  "state": "random_state_token"
}

2. Handle Callback

GET /auth/hh/callback?code=AUTH_CODE

Response:
{
  "success": true,
  "tokens": {
    "access_token": "...",
    "refresh_token": "...",
    "expires_at": "2025-10-15T12:00:00Z"
  }
}

3. Refresh Token

POST /auth/hh/refresh
Content-Type: application/json

{
  "refresh_token": "existing_refresh_token"
}

HH.ru Resume Operations

# List user's resumes
GET /api/hh/resumes

# Get resume details
GET /api/hh/resumes/:resume_id

Health Check

GET /api/v1/system/health

Response:
{
  "status": "ok",
  "db": "up"
}

πŸ’Ύ Database Schema

Core Tables

-- HH.ru OAuth tokens (MVP: plaintext, add encryption later)
hh_tokens (
  id uuid PRIMARY KEY,
  user_id uuid,
  access_token text NOT NULL,
  refresh_token text,
  expires_at timestamp NOT NULL
)

-- Jobs fetched from HH.ru
jobs (
  id uuid PRIMARY KEY,
  external_id varchar UNIQUE NOT NULL,
  title varchar NOT NULL,
  company varchar,
  salary varchar,
  area varchar,
  url text,
  description text,
  hh_vacancy_id varchar,
  has_test boolean DEFAULT false,
  skills varchar[]
)

-- Parsed CVs (managed by API service)
parsed_cvs (
  id uuid PRIMARY KEY,
  user_id uuid,
  first_name varchar,
  last_name varchar,
  email varchar,
  phone varchar,
  title varchar,
  summary text,
  experience text,
  education text,
  skills varchar[],
  ...
)

Migrations

# Create new migration
mix ecto.gen.migration add_new_table

# Run migrations
mix ecto.migrate

# Rollback last migration
mix ecto.rollback

# Reset database
mix ecto.reset

πŸ”„ Background Jobs

Job Orchestrator

Automatically fetches jobs from HH.ru based on scheduled searches:

# Schedule periodic job fetching for a user
Core.Jobs.Orchestrator.schedule_job_fetch(
  "user_id",
  %{text: "Elixir Developer", area: "1"},
  1_800_000  # 30 minutes
)

# Manually trigger fetch
Core.Jobs.Orchestrator.fetch_jobs_now("user_id")

# View active schedules
Core.Jobs.Orchestrator.get_schedules()

Rate Limiter

Token bucket implementation for HH.ru API compliance:

# Check if action is allowed
Core.RateLimiter.check_rate_limit("user_id", :application)
# => {:ok, 19} | {:error, :rate_limited, next_refill_time}

# Get current status
Core.RateLimiter.get_status("user_id")
# => %{tokens: 20, capacity: 20, refill_rate: 8, last_refill: ...}

# Reset limit (admin only)
Core.RateLimiter.reset_limit("user_id")

Configuration:

  • Capacity: 20 tokens
  • Refill rate: 8 tokens/hour
  • HH.ru limit: ~200 applications/day

πŸ“Š Monitoring

LiveDashboard

Access Phoenix LiveDashboard (development only):

http://localhost:4000/dev/dashboard

Features:

  • Real-time metrics
  • Process inspection
  • Ecto query analysis
  • Request logging

Telemetry Metrics

Core emits telemetry events for:

  • phoenix.router_dispatch.* - Request handling
  • core.repo.query.* - Database operations
  • Custom job orchestrator events

πŸ§ͺ Testing

# Run all tests
mix test

# Run with coverage
mix test --cover

# Run specific test file
mix test test/core/hh/client_test.exs

# Run tests matching pattern
mix test --only hh_api

πŸ”’ Security Considerations

Current Implementation (MVP)

⚠️ Not production-ready:

  • OAuth tokens stored as plaintext
  • No user authentication/authorization
  • Rate limiting per user_id without validation

Production Checklist

  • Encrypt sensitive fields (tokens, secrets)
  • Implement proper authentication (Guardian, Pow)
  • Add request signing for API endpoints
  • Enable HTTPS/TLS
  • Implement CSRF protection
  • Add audit logging
  • Set up monitoring/alerting

πŸ“š Project Structure

lib/
β”œβ”€β”€ core/
β”‚   β”œβ”€β”€ application.ex          # OTP Application
β”‚   β”œβ”€β”€ repo.ex                  # Ecto Repository
β”‚   β”œβ”€β”€ hh/
β”‚   β”‚   β”œβ”€β”€ client.ex           # HH.ru API client
β”‚   β”‚   β”œβ”€β”€ oauth.ex            # Token management
β”‚   β”‚   └── token.ex            # Token schema
β”‚   β”œβ”€β”€ jobs/
β”‚   β”‚   └── orchestrator.ex     # Job fetching orchestrator
β”‚   β”œβ”€β”€ rate_limiter.ex         # Rate limiting GenServer
β”‚   └── broadcaster.ex          # WebSocket broadcast helper
β”œβ”€β”€ core_web/
β”‚   β”œβ”€β”€ endpoint.ex             # Phoenix Endpoint
β”‚   β”œβ”€β”€ router.ex               # Route definitions
β”‚   β”œβ”€β”€ controllers/
β”‚   β”‚   β”œβ”€β”€ auth_controller.ex  # OAuth endpoints
β”‚   β”‚   β”œβ”€β”€ hh_controller.ex    # Resume operations
β”‚   β”‚   └── api/
β”‚   β”‚       β”œβ”€β”€ job_controller.ex
β”‚   β”‚       └── application_controller.ex
β”‚   └── telemetry.ex            # Metrics
priv/
└── repo/
    └── migrations/             # Database migrations

🀝 Integration with Other Services

Node BFF (API Service)

Core acts as the data layer and HH.ru proxy for the Node BFF:

Node BFF β†’ [X-Core-Secret] β†’ Core β†’ HH.ru API
                              ↓
                         PostgreSQL

Frontend (SvelteKit)

Frontend connects to Node BFF, which proxies to Core:

Frontend β†’ Node BFF β†’ Core β†’ HH.ru
                  ↓      ↓
              WebSocket  DB

πŸ“– Additional Resources


πŸ“„ License

MIT License Β© 2025 Aleksandr Sakhatskiy


Built with πŸ’œ and Elixir
Because job hunting should be automated

About

🎯 Phoenix-powered job application platform backend with LiveView real-time features

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages