# senseofhumor/restless architecture

> Architecture diagram of the GitHub repository senseofhumor/restless, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-30). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/senseofhumor/restless
- Repository: https://github.com/senseofhumor/restless

## Overview

RESTLESS is a resume and job-application assistant: users upload or enter resume information, have it parsed and saved, tailor it to jobs, and format or download the result. The repository combines a Next.js interface and API, Firebase-backed records and files, and a Python service for parsing and document conversion. The README describes broader LLM screening and matching ambitions; the sampled source confirms parsing and rendering paths but does not establish every model or screening integration. Some API and UI wiring is unsampled, so uncertain links are omitted.

Main entry points: [`src/app/api/resumes/upload/route.js`](https://github.com/senseofhumor/restless/blob/main/src/app/api/resumes/upload/route.js) (Resume upload API), [`python/conversions.py`](https://github.com/senseofhumor/restless/blob/main/python/conversions.py) (Format rendering), [`python/main.py`](https://github.com/senseofhumor/restless/blob/main/python/main.py) (Python API), [`src/db_lib/resumeDB.js`](https://github.com/senseofhumor/restless/blob/main/src/db_lib/resumeDB.js) (Resume records)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_experience["Web experience"]
  node_webui["Next.js UI"]
end

subgraph group_resume["Resume processing"]
  node_resume_upload["Resume upload API<br/>[route.js]"]
  node_section_api["Resume sections API<br/>[route.js]"]
  node_resume_status["Resume status API<br/>[route.js]"]
  node_resume_generate["Resume generation API<br/>[route.js]"]
  node_resume_format["Resume format API<br/>[route.js]"]
  node_resume_download["Resume download API<br/>[route.js]"]
  node_processing_state["Processing state<br/>[resumeStore.js]"]
  node_python_api["Python API<br/>[main.py]"]
  node_llm_parse["Resume parsing<br/>[llm_library.py]"]
  node_doc_conversion["Document conversion<br/>[docxtopdf.py]"]
  node_format_conversion["Format rendering<br/>[conversions.py]"]
  node_render_default["Default renderer<br/>[render_default.py]"]
  node_render_academic["Academic renderer<br/>[render_academic.py]"]
  node_render_two_col["Two-column renderer<br/>[render_two_col.py]"]
  node_render_cover["Cover-letter renderer"]
end

subgraph group_jobs["Job tools"]
  node_jobs_api["Job APIs"]
  node_advice_api["Job advice API<br/>[route.js]"]
end

subgraph group_data["Persistence"]
  node_firebase["Firebase setup<br/>[firebase_config.js]"]
  node_resume_db[("Resume records<br/>[resumeDB.js]")]
  node_file_db[("Resume files<br/>[fileDB.js]")]
  node_job_db[("Job records<br/>[jobInfoDB.js]")]
  node_advice_db[("Advice records<br/>[adviceDB.js]")]
end

node_user(("User"))
node_clerk["Clerk auth"]

node_user -->|"uses"| node_webui
node_webui -.->|"uploads resume"| node_resume_upload
node_resume_upload -->|"authenticates"| node_clerk
node_section_api -->|"authenticates"| node_clerk
node_resume_upload -->|"stores file"| node_file_db
node_resume_upload -->|"reads and saves"| node_resume_db
node_resume_upload -->|"tracks processing"| node_processing_state
node_resume_upload -->|"sends file"| node_python_api
node_section_api -->|"reads resume"| node_resume_db
node_section_api -->|"sends text"| node_python_api
node_resume_status -->|"checks status"| node_processing_state
node_python_api -->|"parses resume"| node_llm_parse
node_python_api -->|"converts DOCX"| node_doc_conversion
node_python_api -->|"formats resume"| node_format_conversion
node_format_conversion -->|"renders"| node_render_default
node_format_conversion -->|"renders"| node_render_academic
node_format_conversion -->|"renders"| node_render_two_col
node_format_conversion -->|"renders"| node_render_cover
node_resume_generate -->|"loads job resume"| node_job_db
node_resume_generate -->|"loads resume"| node_resume_db
node_resume_format -->|"loads generated resume"| node_job_db
node_resume_format -->|"tracks formatting"| node_processing_state
node_resume_download -->|"checks formatted file"| node_processing_state
node_advice_api -->|"loads job context"| node_job_db
node_advice_api -->|"loads resume"| node_resume_db
node_advice_api -->|"saves advice"| node_advice_db
node_resume_db -->|"uses Firestore"| node_firebase
node_file_db -->|"uses storage"| node_firebase
node_job_db -->|"uses Firestore"| node_firebase
node_advice_db -->|"uses Firestore"| node_firebase
node_jobs_api -.->|"manages job data"| node_job_db

click node_webui "https://github.com/senseofhumor/restless/tree/main/src/app"
click node_resume_upload "https://github.com/senseofhumor/restless/blob/main/src/app/api/resumes/upload/route.js"
click node_section_api "https://github.com/senseofhumor/restless/blob/main/src/app/api/resumes/%5Bsection%5D/route.js"
click node_resume_status "https://github.com/senseofhumor/restless/blob/main/src/app/api/resumeParsingStatus/%5BresumeId%5D/route.js"
click node_resume_generate "https://github.com/senseofhumor/restless/blob/main/src/app/api/resumes/generate/route.js"
click node_resume_format "https://github.com/senseofhumor/restless/blob/main/src/app/api/resumes/format/route.js"
click node_resume_download "https://github.com/senseofhumor/restless/blob/main/src/app/api/resumes/download/%5BformattedResumeId%5D/route.js"
click node_processing_state "https://github.com/senseofhumor/restless/blob/main/src/lib/resumeStore.js"
click node_python_api "https://github.com/senseofhumor/restless/blob/main/python/main.py"
click node_llm_parse "https://github.com/senseofhumor/restless/blob/main/python/llm_library.py"
click node_doc_conversion "https://github.com/senseofhumor/restless/blob/main/python/docxtopdf.py"
click node_format_conversion "https://github.com/senseofhumor/restless/blob/main/python/conversions.py"
click node_render_default "https://github.com/senseofhumor/restless/blob/main/python/render_default.py"
click node_render_academic "https://github.com/senseofhumor/restless/blob/main/python/render_academic.py"
click node_render_two_col "https://github.com/senseofhumor/restless/blob/main/python/render_two_col.py"
click node_render_cover "https://github.com/senseofhumor/restless/blob/main/python/render_coverletter.py"
click node_jobs_api "https://github.com/senseofhumor/restless/tree/main/src/app/api/jobs"
click node_advice_api "https://github.com/senseofhumor/restless/blob/main/src/app/api/jobs/advice/route.js"
click node_firebase "https://github.com/senseofhumor/restless/blob/main/src/db_lib/firebase_config.js"
click node_resume_db "https://github.com/senseofhumor/restless/blob/main/src/db_lib/resumeDB.js"
click node_file_db "https://github.com/senseofhumor/restless/blob/main/src/db_lib/fileDB.js"
click node_job_db "https://github.com/senseofhumor/restless/blob/main/src/db_lib/jobInfoDB.js"
click node_advice_db "https://github.com/senseofhumor/restless/blob/main/src/db_lib/adviceDB.js"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_webui,node_user toneBlue
class node_resume_upload,node_section_api,node_resume_status,node_resume_generate,node_resume_format,node_resume_download,node_processing_state,node_python_api,node_llm_parse,node_doc_conversion,node_format_conversion,node_render_default,node_render_academic,node_render_two_col,node_render_cover toneAmber
class node_jobs_api,node_advice_api toneMint
class node_firebase,node_resume_db,node_file_db,node_job_db,node_advice_db toneRose
class node_clerk toneIndigo
```

## Components

### Web experience

- [Next.js UI](https://github.com/senseofhumor/restless/tree/main/src/app): `src/app`

### Resume processing

- [Resume upload API](https://github.com/senseofhumor/restless/blob/main/src/app/api/resumes/upload/route.js): `src/app/api/resumes/upload/route.js`
- [Resume sections API](https://github.com/senseofhumor/restless/blob/main/src/app/api/resumes/%5Bsection%5D/route.js): `src/app/api/resumes/[section]/route.js`
- [Resume status API](https://github.com/senseofhumor/restless/blob/main/src/app/api/resumeParsingStatus/%5BresumeId%5D/route.js): `src/app/api/resumeParsingStatus/[resumeId]/route.js`
- [Resume generation API](https://github.com/senseofhumor/restless/blob/main/src/app/api/resumes/generate/route.js): `src/app/api/resumes/generate/route.js`
- [Resume format API](https://github.com/senseofhumor/restless/blob/main/src/app/api/resumes/format/route.js): `src/app/api/resumes/format/route.js`
- [Resume download API](https://github.com/senseofhumor/restless/blob/main/src/app/api/resumes/download/%5BformattedResumeId%5D/route.js): `src/app/api/resumes/download/[formattedResumeId]/route.js`
- [Processing state](https://github.com/senseofhumor/restless/blob/main/src/lib/resumeStore.js): `src/lib/resumeStore.js`
- [Python API](https://github.com/senseofhumor/restless/blob/main/python/main.py): `python/main.py`
- [Resume parsing](https://github.com/senseofhumor/restless/blob/main/python/llm_library.py): `python/llm_library.py`
- [Document conversion](https://github.com/senseofhumor/restless/blob/main/python/docxtopdf.py): `python/docxtopdf.py`
- [Format rendering](https://github.com/senseofhumor/restless/blob/main/python/conversions.py): `python/conversions.py`
- [Default renderer](https://github.com/senseofhumor/restless/blob/main/python/render_default.py): `python/render_default.py`
- [Academic renderer](https://github.com/senseofhumor/restless/blob/main/python/render_academic.py): `python/render_academic.py`
- [Two-column renderer](https://github.com/senseofhumor/restless/blob/main/python/render_two_col.py): `python/render_two_col.py`
- [Cover-letter renderer](https://github.com/senseofhumor/restless/blob/main/python/render_coverletter.py): `python/render_coverletter.py`

### Job tools

- [Job APIs](https://github.com/senseofhumor/restless/tree/main/src/app/api/jobs): `src/app/api/jobs`
- [Job advice API](https://github.com/senseofhumor/restless/blob/main/src/app/api/jobs/advice/route.js): `src/app/api/jobs/advice/route.js`

### Persistence

- [Firebase setup](https://github.com/senseofhumor/restless/blob/main/src/db_lib/firebase_config.js): `src/db_lib/firebase_config.js`
- [Resume records](https://github.com/senseofhumor/restless/blob/main/src/db_lib/resumeDB.js): `src/db_lib/resumeDB.js`
- [Resume files](https://github.com/senseofhumor/restless/blob/main/src/db_lib/fileDB.js): `src/db_lib/fileDB.js`
- [Job records](https://github.com/senseofhumor/restless/blob/main/src/db_lib/jobInfoDB.js): `src/db_lib/jobInfoDB.js`
- [Advice records](https://github.com/senseofhumor/restless/blob/main/src/db_lib/adviceDB.js): `src/db_lib/adviceDB.js`

### Other components

- **User**
- **Clerk auth**

## Connections

- User → Next.js UI: uses
- Next.js UI → Resume upload API: uploads resume
- Resume upload API → Clerk auth: authenticates (evidence: `src/app/api/resumes/upload/route.js`)
- Resume sections API → Clerk auth: authenticates (evidence: `src/app/api/resumes/[section]/route.js`)
- Resume upload API → Resume files: stores file (evidence: `src/app/api/resumes/upload/route.js`)
- Resume upload API → Resume records: reads and saves (evidence: `src/app/api/resumes/upload/route.js`)
- Resume upload API → Processing state: tracks processing (evidence: `src/app/api/resumes/upload/route.js`)
- Resume upload API → Python API: sends file (evidence: `src/app/api/resumes/upload/route.js`)
- Resume sections API → Resume records: reads resume (evidence: `src/app/api/resumes/[section]/route.js`)
- Resume sections API → Python API: sends text (evidence: `src/app/api/resumes/[section]/route.js`)
- Resume status API → Processing state: checks status (evidence: `src/app/api/resumeParsingStatus/[resumeId]/route.js`)
- Python API → Resume parsing: parses resume (evidence: `python/main.py`)
- Python API → Document conversion: converts DOCX (evidence: `python/main.py`)
- Python API → Format rendering: formats resume (evidence: `python/main.py`)
- Format rendering → Default renderer: renders (evidence: `python/conversions.py`)
- Format rendering → Academic renderer: renders (evidence: `python/conversions.py`)
- Format rendering → Two-column renderer: renders (evidence: `python/conversions.py`)
- Format rendering → Cover-letter renderer: renders (evidence: `python/conversions.py`)
- Resume generation API → Job records: loads job resume (evidence: `src/app/api/resumes/generate/route.js`)
- Resume generation API → Resume records: loads resume (evidence: `src/app/api/resumes/generate/route.js`)
- Resume format API → Job records: loads generated resume (evidence: `src/app/api/resumes/format/route.js`)
- Resume format API → Processing state: tracks formatting (evidence: `src/app/api/resumes/format/route.js`)
- Resume download API → Processing state: checks formatted file (evidence: `src/app/api/resumes/download/[formattedResumeId]/route.js`)
- Job advice API → Job records: loads job context (evidence: `src/app/api/jobs/advice/route.js`)
- Job advice API → Resume records: loads resume (evidence: `src/app/api/jobs/advice/route.js`)
- Job advice API → Advice records: saves advice (evidence: `src/app/api/jobs/advice/route.js`)
- Resume records → Firebase setup: uses Firestore (evidence: `src/db_lib/resumeDB.js`)
- Resume files → Firebase setup: uses storage (evidence: `src/db_lib/fileDB.js`)
- Job records → Firebase setup: uses Firestore (evidence: `src/db_lib/jobInfoDB.js`)
- Advice records → Firebase setup: uses Firestore (evidence: `src/db_lib/adviceDB.js`)
- Job APIs → Job records: manages job data (evidence: `src/app/api/jobs/submit/route.js`)
