Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CVForge

A CV builder that writes to DynamoDB, renders a PDF in memory, and stores it in S3 — deployed on AWS Elastic Beanstalk. It also tailors an existing CV to a specific job posting through the Gemini API.

Flask 3 · Python 3.11 · DynamoDB · S3 · Elastic Beanstalk · fpdf2

The Elastic Beanstalk environment was part of an AWS Academy lab account and has since been torn down, so the old public URL no longer resolves. Everything below runs locally against your own AWS resources using the setup at the bottom.


What it does

Build — a multi-section form (personal details, summary, education, experience, skills) that produces a formatted A4 PDF in one of two templates: Modern Tech with an indigo accent, or Minimal ATS in black and white.

Score — every saved CV gets an ATS score. This is a keyword heuristic, not a simulation of any real applicant tracking system: the summary, skills and experience fields are lowercased and matched against a fixed list of 24 industry terms, and the score is min(100, found / 10 × 100). Ten matches is full marks. It is useful as a nudge to include concrete technology names, and it is deliberately simple.

Tailor — paste a job description and the CV is rewritten to align with it. The prompt is explicit that the model may rephrase but may not invent:

Keep it truthful — don't invent skills or experience I don't have, but rephrase what I have to align with the job.

The rewritten CV is re-scored, so you can see whether the tailoring actually moved the number.

Dashboard — lists every CV with its score and a download link.


How it's built

PDF generation

fpdf2, rendered into a memory buffer and uploaded straight to S3 — nothing touches local disk, which matters on Elastic Beanstalk where the instance filesystem is ephemeral.

Font handling is the part worth reading. fpdf2's built-in fonts are Latin-1 only, which breaks on Turkish and Polish characters, so the app loads a TrueType font instead — and which font it can find depends on where it runs:

win_reg = 'C:/Windows/Fonts/calibri.ttf'
lin_reg = '/usr/share/fonts/liberation/LiberationSans-Regular.ttf'

Calibri in development on Windows, Liberation Sans on Amazon Linux, and a fall back to core fonts if neither exists. An earlier deploy failed because the EB config tried to install msttcore-fonts, which is not available on Amazon Linux 2023; moving to the Liberation family fixed it.

Gemini integration

Called over plain urllib.request against the Generative Language REST endpoint rather than through the SDK — one fewer dependency in the deployment bundle, and the request is a single JSON POST.

The model returns JSON, but often wrapped in a markdown code fence, so the response is unwrapped before parsing and a JSONDecodeError is caught rather than allowed to 500:

if response.startswith('```'):
    response = response.split('```')[1]

If GEMINI_API_KEY is unset the tailor endpoint degrades instead of crashing, and the rest of the app keeps working.

Storage

DynamoDB One item per CV, cv_id as partition key. put_item on create, get_item / scan for the dashboard.
S3 PDFs written with put_object. Downloads go through a pre-signed URL, so the bucket itself stays private.

Deployment

Elastic Beanstalk, Python 3.11 on Amazon Linux 2023, Gunicorn started from a one-line Procfile. Configuration is passed as environment variables, and the IAM instance profile carries the S3 and DynamoDB permissions so no credentials ship with the application.


Routes

Route Method Purpose
/ GET Landing page with a live template preview
/create GET, POST CV form → DynamoDB + PDF to S3
/tailor GET, POST Job description → Gemini rewrite → re-score
/dashboard GET All CVs, scores, download links

Running it locally

git clone https://github.com/Tunaycel/cvforge
cd cvforge
pip install -r requirements.txt

Create a .env:

SECRET_KEY=<python -c "import secrets; print(secrets.token_hex(32))">
S3_BUCKET=<your bucket>
AWS_REGION=us-east-1
DYNAMO_TABLE=<your table>
GEMINI_API_KEY=<optional; the tailor page is disabled without it>

You need an S3 bucket and a DynamoDB table with cv_id as the partition key, plus credentials in your environment or ~/.aws/credentials.

python app.py

Deploying

eb init cvforge-app --platform python-3.11 --region us-east-1
eb create cvforge-env --single
eb setenv SECRET_KEY=... GEMINI_API_KEY=...
eb deploy

Set secrets with eb setenv, never in .ebextensions — anything in that directory is committed to the repository.


Known limitations

  • Delete is not implemented; a new submission overwrites the previous PDF for that CV.
  • There is no authentication. The dashboard scans the whole table, so it is single-user by assumption rather than by enforcement.
  • scan does not paginate, so it stops being the right call past a few hundred items.
  • The ATS score is a keyword count, and should be read as one.

About

CV builder on Flask + DynamoDB + S3, with Gemini-based tailoring to a job description (Elastic Beanstalk lab env, now torn down)

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages