MyCVPath — AI-Native CV Intelligence Platform
Achievement Log
Overview
A production-deployed, polyglot microservices platform that automates the full CV-to-job-application lifecycle using a 6-agent LLM orchestration pipeline, a dedicated ATS-optimized PDF rendering service, a Rust-based fire-and-forget telemetry sink, and a real-time admin control plane. Built across five independently deployable services (Go, Python, Rust, Node.js, Next.js) sharing a single PostgreSQL backend with dual-schema architecture (business logic + analytics). Implements a tiered billing engine with BYOK API key encryption, an atomic guest-to-user migration pipeline, and job-scoped immutable CV snapshots that preserve a reproducible per-application evidence trail. Live at mycvpath.com.
Core Technologies
Implementation & Architecture
Agentic LLM Orchestration Engine (Go-LLMs)
Six-agent sequential pipeline in Go that transforms a raw CV + job description into a fully tailored, scored application package. Each agent is independently configurable with its own provider chain, schema, and retry policy.
Execution Protocol
- Defined 6 specialized agents in pipeline order: CV_PARSER (raw text → structured CV JSON), CV_VALIDATOR (enrichment + gap filling), JOB_PARSER (JD text → structured requirements), JOB_ANALYZER (gap analysis + match scoring), CV_TAILOR (CV rewrite targeting specific JD), COMPARATIVE_SCORER (tailored CV vs JD quality score)
- Implemented PromptBuilder abstraction that assembles system prompt + per-agent JSON schema + TOON-serialized user context — schema is dynamically injected into the prompt body to force structured output without relying on provider-specific JSON mode features
- Built TOON Serialization Layer converting complex nested Go structs (CV data, job requirements, analysis) into flattened LLM-optimized prompt encoding — avoids token-expensive JSON nesting while preserving all semantic relationships
- Designed provider chain resolution from JSONB config (stored in user_model_profiles or default_model_config): sequential failover tries each provider/model in order with exponential backoff — if OpenAI fails, falls back to Anthropic, then Gemini, then OpenRouter
- Implemented multi-provider client factory supporting OpenAI-compatible API format, Anthropic Messages API, and Google Gemini API — single orchestrator interface with provider-specific serialization per client
- Built BYOK key resolution path: for BYOK-tier users, AES-256-GCM encrypted key is fetched from user_model_profiles, decrypted in memory at request time, injected into provider client — key never written to logs
- Governance middleware checks request eligibility before agent execution: verifies daily quota (free tier), checks monthly spend cap (paid tier), validates BYOK subscription status — rejects with structured error if any limit exceeded
- Persisted every LLM request to analytics_monitoring.llm_generation_logs with full request/response JSONB, token counts, estimated_cost_usd, duration_ms, provider, model, agent_type, and status (success/error/timeout)
- Admin handlers expose /api/admin/llm-analytics endpoint aggregating logs by provider/model over configurable date windows — used by admin-service dashboard for cost visibility
- Global free mode toggle in platform_settings.global_free_mode bypasses all quota and billing checks when enabled — allows platform-wide open access during promotions or testing without per-user config changes
- CLI tooling (cmd/cli.go) enables local agent testing without HTTP round-trip — same orchestrator code path, different transport layer — verified agent outputs against expected JSON schemas before deployment
CV Document Rendering Pipeline (Python/Flask)
Stateless PDF generation microservice that produces ATS-friendly CV output from structured JSON, with dual rendering engines supporting both legacy and dynamic layouts.
Execution Protocol
- Built modular section element system in ReportLab: each CV section (Summary, Experience, Education, Skills, Projects, Certifications, Languages) implemented as an independent class with controlled spacing, font weights, and bullet formatting — assembled via section-level flow objects
- Implemented V1 Legacy Engine with fixed schema: section ordering hardcoded, deterministic layout guarantees exact pixel-level repeatability for the same input — used for regression testing and backwards compatibility
- Implemented V2 Dynamic Engine with flexible section ordering: sections defined as ordered list in input JSON — CV_TAILOR agent output controls which sections appear and in what order for maximum relevance to the target job
- Loaded EB Garamond font family (Regular, Medium, Bold, ExtraBold, Italic, BoldItalic, MediumItalic, ExtraBoldItalic) as custom ReportLab fonts — editorial serif typography for professional ATS-parseable output that passes both human and automated screening
- ATS optimization constraints enforced in layout: no multi-column text flows, no text boxes over images, no decorative lines interrupting paragraph flows, all section headers as plain bold text — ensures standard PDF text extraction by ATS parsers
- PDF text extraction endpoint /extract-text: PyPDF2 reads uploaded binary PDF, extracts raw text preserving paragraph breaks, returns as string to go-llms for CV_PARSER agent input — initial ingestion step of the full pipeline
- Cover letter generation support: /generate-pdf accepts cover_letter field alongside CV JSON — generates combined PDF or separate DOCX cover letter depending on output_mode flag
- ThreadedConnectionPool manages concurrent PDF generation requests without blocking — each thread handles one generation job independently with isolated ReportLab canvas state
- Error forwarding to analytics service: any generation failure POST-fires to analytics-monitoring /track/error endpoint asynchronously — caller receives error response immediately, error is logged in background
- Health check endpoints /health (liveness) and /health/db (PostgreSQL connectivity) used by Docker Compose dependency management and production monitoring
Rust Axum Fire-and-Forget Telemetry Sink (analytics-monitoring)
High-throughput, minimal-footprint microservice built in Rust/Axum to ingest behavioral telemetry, LLM logs, and error events from all platform services without impacting caller latency.
Execution Protocol
- Axum HTTP router with Tower middleware stack: CORS for cross-service requests, request tracing via Tower Trace for structured log output, error handling middleware converting Rust errors to HTTP 500 responses
- All write operations wrapped in tokio::spawn: every POST to /track/* immediately returns 202 Accepted, then executes the database write on a spawned async task — caller experiences <1ms handler overhead regardless of database load
- Page view tracking (/track/page-view): captures path, referrer, duration_ms, session_id, user_id/guest_id, device_type, browser — persisted to analytics_monitoring.page_views
- User action tracking (/track/action): captures interaction metadata (action_type, element_id, metadata JSONB) — enables behavioral funnel analysis for UX optimization
- LLM request monitoring (/track/llm-request): receives token counts, cost, latency, provider, model, agent_type, status from go-llms after each generation — persisted to llm_generation_logs with full request/response JSONB when debug mode enabled
- Error ingestion (/track/error): centralizes errors from all 5 microservices — captures microservice origin, file_path, line_number, function_name, error_type, severity (error/warning), stack_trace, request_context JSONB, resolution status (new/investigating/resolved/ignored)
- Hourly aggregation into user_model_usage: Tokio background task computes sum(prompt_tokens), sum(completion_tokens), sum(estimated_cost_usd) per user+model+provider+hour — admin dashboard queries this table for cost reporting
- Session fingerprinting in visitor_sessions: correlates authenticated user_id, guest_id, and anonymous visitor across page views — enables conversion funnel analysis from first visit through registration
- Statistics endpoints (/stats/overview, /stats/llm-usage, /stats/user-activity) perform aggregated SQL queries with configurable time windows — consumed by admin-service Node.js dashboard
- pattern_insights table receives ML-driven pattern updates via stored procedure: job types, company categories, and success correlations learned over time from comparative_scorer outputs
PostgreSQL Dual-Schema Data Architecture
Unified PostgreSQL 16 instance serving all platform services via two isolated schemas: public for business logic and analytics_monitoring for observability, established via 17 sequential migration files.
Execution Protocol
- Schema separation enforced at migration level: 01_init.sql creates both schemas and installs pgcrypto extension — all subsequent migrations target specific schema with fully-qualified table names (public.users, analytics_monitoring.visitor_sessions)
- Identity layer (02_identity.sql): users table with email verification state, guest_users with migration_status and migrated_at tracking, sessions with device_info/ip_address/is_revoked, user_model_profiles with provider_chain JSONB and AES-encrypted api_key_encrypted bytea field
- CV and jobs layer (03_cv_and_jobs.sql): master_cvs with version_number, content_hash (MD5/SHA256 dedup), growth_history JSONB, and created_for_job_id foreign key — each job_applications row captures full workflow funnel state (workflow_step, reached_import/job/tailor/complete booleans, abandonment_reason, timing metrics in milliseconds)
- Pipeline state layer (04_workflow_and_drafts.sql): import_data/job_data/tailor_data as 1:1 companions to job_applications — tailor_data stores immutable input snapshots (master_cv_snapshot JSONB, job_data_snapshot JSONB, analysis_snapshot JSONB) enabling full reproducibility of any tailoring run
- Analytics schema (05_analytics_and_monitoring.sql): full telemetry infrastructure including llm_generation_logs with model parameters JSONB, full_request/full_response JSONB debug fields, token counts, estimated_cost_usd, duration_ms, started_at/completed_at timestamps
- Logic layer (06_logic.sql): stored procedure migrate_guest_to_user() executes full account conversion — copies CVs, job applications, sessions from guest namespace to user namespace, handles singleton table collisions (app_sessions, builder_states, user_preferences) by keeping newer timestamp, merges user_model_usage by summing tokens/cost for matching hour+model+provider windows, all in single ACID transaction
- Migrations 07–17 add: billing tables (user_accounts with balance/spending/currency), platform_settings (global_free_mode toggle, service fees, minimum balances), default_model_config JSONB for system-wide provider chains, interview_steps tracking, generation_requests queue with pending/processing/completed states
- Connection pooling per service: application (Next.js pg pool), go-llms (Go database/sql pool), cv-manipulation (Python ThreadedConnectionPool), analytics-monitoring (Rust deadpool-postgres), admin-service (Node.js pg pool) — each service sized independently
- Query optimization via targeted indexes: job_applications indexed on (user_id, workflow_step), llm_generation_logs indexed on (user_id, created_at), user_model_usage indexed on (user_id, model, hour_bucket) — covers all dashboard aggregation patterns
- JSONB provider chains enable zero-migration provider config updates: changing a user's provider chain requires only an UPDATE to user_model_profiles.provider_chain — no schema migration, no service restart
Hybrid State Architecture (Next.js Application Layer)
Resilient three-layer state management system ensuring zero data loss across the CV tailoring workflow — hot React Context for UI responsiveness, LocalStorage for browser-crash recovery, and PostgreSQL for durable server-side persistence.
Execution Protocol
- React Context maintains workflow state in memory: currentJob, importData (parsed CV JSON), jobData (analyzed job requirements), tailorData (tailored CV + cover letter) — each state slice matches the corresponding database table schema exactly
- LocalStorage sync layer serializes Context state to localStorage after every agent response completion — if browser crashes mid-session, page reload restores from localStorage before initiating database fetch
- Dual-trigger synchronization: (1) after each agent pipeline step completes, application POSTs the step result to its corresponding API route (import_data, job_data, tailor_data) for DB persistence; (2) on Next.js router navigation events, a sync effect flushes any pending context state to DB
- API routes proxy agent calls to go-llms: /api/agent/[agentname] receives the pipeline step payload, forwards to go-llms service with internal network address, streams response back to client — Next.js acts as BFF (Backend-for-Frontend) isolating the client from internal service addresses
- Guest session flow: unauthenticated users assigned guest_id stored in cookie — all workflow state persisted under guest_users and guest-namespaced pipeline tables — full session preserved across browser sessions until registration or expiry
- Guest-to-user migration triggered on registration: application calls /api/auth/register which invokes migrate_guest_to_user() in a single database transaction — all guest CVs, job applications, and pipeline state transferred atomically to new user account
- Singleton table collision logic in migration: if both guest and new user have an app_sessions row, the one with the newer updated_at timestamp wins — prevents data loss in edge case where user had used the platform previously under a different guest session
- Job application workflow funnel tracking: each transition between workflow steps (import → job → tailor → complete) updates reached_* boolean flags and records timing in milliseconds — abandonment detection fires on navigation away from incomplete workflow
- Versioned Master CV model: master_cvs table stores the user's canonical CV with version_number increment on each update — job applications reference the master CV version at time of creation via created_for_job_id — ensures the tailored output can always be traced back to the exact input state
- Builder state persistence: cv-builder UI state (section visibility, ordering preferences, custom entries) persisted in builder_states table — survives page reloads and multi-device access
Tiered BYOK Billing and Governance Engine
Three-tier billing architecture enforcing distinct quota, cost, and key management policies per user type — FREE, PAID (managed keys), and BYOK (user-supplied keys) — with per-request cost tracking and admin override capabilities.
Execution Protocol
- FREE tier: default provider chain from platform_settings applied to all requests — default_model_config stores system-wide agent configurations in JSONB — daily request quota enforced (default: 5/day) via counter in user_model_profiles.daily_requests_used, reset at midnight UTC
- PAID tier: user pre-loads balance via payment flow — go-llms deducts estimated_cost_usd from user_accounts.balance after each successful generation — service fee (default: 20% margin) added to raw provider cost — minimum balance gate checked before agent execution
- BYOK tier: user pastes their own OpenAI/Anthropic/Gemini API key in platform UI — application encrypts key with AES-256-GCM before PostgreSQL write — encryption key stored in environment variable, never in database — decryption occurs in go-llms memory at request time only
- AES-256-GCM implementation: random 12-byte nonce generated per key, prepended to ciphertext in api_key_encrypted bytea field — decryption verifies authentication tag before use — encrypted key never appears in logs even at DEBUG level
- Rate limiting enforcement: per-user daily_limit and hourly_limit fields in user_model_profiles — go-llms checks both limits before agent execution — limits configurable per user by admin without code deploy
- Monthly spend cap: user_model_profiles.monthly_spend_limit and spending_reset_date enable per-user spending guardrails — aggregated from user_model_usage table which accumulates hourly — go-llms checks current_month_spend < monthly_spend_limit before execution
- Global free mode: platform_settings.global_free_mode boolean bypasses ALL quota and billing checks when true — enables full platform access during promotional periods or incident recovery — toggled via admin-service API without service restart
- Cost tracking accuracy: estimated_cost_usd calculated from token counts × published provider pricing rates hardcoded per model in go-llms config — actual vs estimated reconciliation exposed in admin dashboard
- BYOK subscription lifecycle: subscription_status field (active/inactive/cancelled/expired) in user_model_profiles — inactive/expired subscriptions fall back to FREE tier defaults instead of failing — prevents hard breakage when BYOK key expires
- Audit trail: every LLM generation creates an immutable llm_generation_logs row — admin can reconstruct exact cost history per user per provider — used for dispute resolution and cost modeling
Polyglot Docker Compose Service Orchestration
Unified deployment topology for 5 heterogeneous microservices sharing a single PostgreSQL database, with strict startup ordering, health-gated dependencies, and production-hardened network isolation.
Execution Protocol
- postgres service starts first with no dependencies — configured with persistent volume mount for data durability across container restarts — health check waits for pg_isready before declaring healthy
- migrations service starts as a one-shot container after postgres is healthy — runs all 17 SQL files sequentially via a shell script — exits with code 0 on success, fails the entire compose stack on any migration error — prevents partial schema state
- analytics-monitoring (Rust) starts after migrations complete — chosen as first application service because all other services fire telemetry events to it — being up early ensures no telemetry is dropped during service startup
- application (Next.js), go-llms (Go), cv-manipulation (Python), admin-service (Node.js) all start in parallel after analytics-monitoring is healthy — no startup ordering between them (each handles the case where a dependency is temporarily unavailable)
- Internal app-network: all services communicate via Docker internal DNS (e.g. http://go-llms:7689) — no port exposure to host for internal services — Next.js API routes use internal addresses when proxying to go-llms and cv-manipulation
- External gateway-public network: only application service connected — Nginx reverse proxy on the host terminates HTTPS and routes to localhost:7687 — single external ingress point
- All host port bindings use 127.0.0.1 prefix (e.g. 127.0.0.1:7687:7687) — prevents accidental external exposure in cloud environments where all interfaces are reachable — security-first default
- Memory limits prevent runaway processes: Application 2GB/512MB reservation, Go-LLMs 1GB/256MB, CV-Manipulation 1GB/256MB (ReportLab rendering is CPU/memory intensive for complex CVs), Analytics-Monitoring 512MB/128MB
- Health check probes per service: Application uses curl /api/health, Go-LLMs and Analytics use wget /health — probes tuned with start_period to avoid false failures during JVM/Go/Rust cold start
- .env file separation: DATABASE_URL, LLM API keys, admin codes, JWT secrets loaded from environment — no secrets in docker-compose.yml or image layers
Technical Skills
- Multi-Agent Orchestration
- Agentic AI Orchestration
- Prompt Engineering
- Multi-LLM Integration
- Prompt Template Design
- Docker
- Python
- TypeScript
- Go
- Rust
- Next.js
- React
- Flask
- TailwindCSS
- RESTful API Design
- Concurrency (Threading/Async)
- OAuth 2.0 Integration
- PostgreSQL
- Schema Migration
- JWT (JSON Web Tokens)
- JSON Schema & Structured Data Extraction
- Microservices Architecture
- Multi-Provider LLM Failover Orchestration
- Schema-Injected LLM Output Validation
- AES-256-GCM API Key Vault Encryption
- Rust Axum Async Telemetry Sink
- Atomic Guest-to-User Data Migration
- Job-Scoped Immutable Snapshot Persistence
- ReportLab ATS-Optimized PDF Composition
- Tiered BYOK Billing Rate-Limit Architecture
Engineering Challenges
- →Multi-Service Startup Race Conditions — During first cloud deployment, go-llms and cv-manipulation started before the migrations container had finished applying all 17 SQL files, causing table-not-found errors on first requests. Root cause: Docker Compose `depends_on: condition: service_healthy` was not set on the migrations service (which exits on completion, not running). Resolved by configuring migrations as a `service_completed_successfully` dependency — all application services now wait for migrations exit code 0 before starting. Zero table-not-found errors since.
- →LLM Agent Schema Mismatch Cascades — CV_PARSER output keys used camelCase while JOB_ANALYZER expected snake_case input fields, causing silent null values in the analysis stage. Root cause: each agent's JSON schema was designed independently without a shared canonical CV data model. Resolved by defining a single shared CV struct in Go with explicit JSON tags, used as the schema source for both output (parser) and input (analyzer) agents — schema injection ensures both sides speak the same field names.
- →Prompt Numerical Hallucination in Job Analysis — JOB_ANALYZER was inventing match percentages and skill counts not derivable from the input documents. Root cause: the prompt's instruction to 'quantify the match' was too open-ended — the model fabricated plausible-sounding numbers when it lacked evidence. Resolved by rewriting the prompt to explicitly forbid numerical assertions not directly supported by input text, and by adding a COMPARATIVE_SCORER agent as a separate validation pass that produces scores only from structured comparison, not narrative inference.
- →Next.js Hydration Mismatch in Auth IdentityContext — Production auth entered an infinite re-render loop when the server-side identity state differed from the client-side cookie state during SSR hydration. Root cause: IdentityContext subscription was registered before the Supabase client was fully initialized on the server render pass, causing a null subscription that triggered the cleanup path, which then re-triggered setup. Resolved by adding hydration guards (isHydrated boolean flag) that defer subscription registration until after client-side mount confirms auth state from cookie.
- →AES-256-GCM Key Decryption Timing — BYOK key decryption happening at every agent invocation added measurable latency for multi-step pipelines (6 agents × decryption overhead). Root cause: decrypt-on-demand was correct for security but not cached for the request lifetime. Resolved by decrypting the key once per HTTP request into a Go-local context variable, passing it through the agent pipeline without re-decrypting — key lives only in memory for the duration of the request, never serialized.
- →Guest Data Collision on Registration — When a user who had previously used the platform as a guest registered a new account, the guest-to-user migration occasionally failed with a unique constraint violation on singleton tables (app_sessions, builder_states). Root cause: the migration function attempted INSERT rather than UPSERT for singleton tables where the new user account (created earlier in the same session) already had a row. Resolved by rewriting the migration to use INSERT ... ON CONFLICT DO UPDATE SET ... WHERE excluded.updated_at > target.updated_at — keeps the more recent state, never loses data.
- →ReportLab Font Loading in Docker Container — The EB Garamond font family failed to load in the Docker container despite being present in the res/fonts/ directory. Root cause: ReportLab's font registration requires absolute paths; the Dockerfile changed the working directory, making the relative path used in development invalid in production. Resolved by using Python's pathlib.Path(__file__).parent to construct absolute paths to font files at registration time — font loading verified in both local and container environments.
Project Outcomes
- ✓Delivered a production-deployed, 5-service polyglot microservices platform (Go, Python, Rust, Node.js, Next.js) from first commit to live deployment in 10 days (2025-12-10 to 2025-12-19), with the complete 6-agent LLM pipeline, ATS-optimized PDF generation, and real-time telemetry operational on first production deployment.
- ✓Six-agent LLM pipeline (CV_PARSER → CV_VALIDATOR → JOB_PARSER → JOB_ANALYZER → CV_TAILOR → COMPARATIVE_SCORER) processes a complete CV-tailoring job in a single automated workflow — reducing manual CV adaptation from 2–4 hours to under 5 minutes of user interaction.
- ✓Schema-injected LLM output validation achieved near-100% structured output reliability across all six agents, eliminating the ~15% agent response parse failure rate observed with free-form prompts — zero downstream pipeline failures from malformed LLM output since migration to schema-driven architecture.
- ✓Multi-provider failover chain (OpenAI → Anthropic → Gemini → OpenRouter) with BYOK encrypted key tier eliminates single-provider outage risk and removes platform billing as an adoption barrier — BYOK users operate with unlimited requests against their own API keys.
- ✓Rust analytics-monitoring service processes telemetry at <1ms handler overhead per event via Tokio fire-and-forget architecture — zero measurable latency impact on user-facing LLM generation requests, all behavioral and cost analytics available in real-time in admin dashboard.
- ✓Atomic guest-to-user migration pipeline preserves 100% of workflow state across 10+ tables in a single ACID transaction — users who complete partial workflows as guests lose zero data on registration, with collision management ensuring the most recent state wins on singleton table conflicts.
- ✓17-migration PostgreSQL schema evolution strategy enables zero-downtime schema changes — each migration is self-contained and idempotent, applied by a one-shot Docker container that gates all application service startup, preventing partial-schema production incidents.
- ✓AES-256-GCM API key vault with per-key random nonce and authentication tag verification ensures BYOK user API keys are cryptographically inaccessible to the platform operator — keys decrypted only in Go process memory for the duration of a single HTTP request.