mirror of
https://github.com/velocitatem/cvfs.git
synced 2026-05-31 16:53:38 +00:00
docs: rewrite readme for resume branches
This commit is contained in:
256
README.md
256
README.md
@@ -1,166 +1,124 @@
|
|||||||
# Ultiplate
|
# Resume Branches
|
||||||
|
CV control plane that treats your resume like a git tree: preserve one canonical ATS-safe DOCX, branch it into role/company variants, review AI-suggested patches, and publish stable public links without losing structure.
|
||||||
|
|
||||||
Template for any project: SaaS webapp, API server, ML pipeline, scraper, CLI, or background worker. AI-native, platform-agnostic, managed via Makefile + Nx.
|

|
||||||
|
|
||||||
## Quick Start
|
## Why Resume Branches exists
|
||||||
|
- **Preserve canonical formatting.** We never regenerate the DOCX wholesale; edits are stored as targeted patches on parsed blocks so ATS cues stay intact.
|
||||||
|
- **Branch with intent.** Root CV ➝ specializations ➝ submission leaves mirrors how people actually tailor resumes.
|
||||||
|
- **Controlled AI.** The worker produces constrained patch suggestions (max delta, no new claims) so you approve meaningful wording tweaks instead of rewriting history.
|
||||||
|
- **Publish safely.** Only frozen artifacts become public URLs; editing your working tree never breaks the links you already shared.
|
||||||
|
|
||||||
|
## Core capabilities
|
||||||
|
- Upload one ATS-safe DOCX, parse it into stable block paths, and keep the original artifact in object storage.
|
||||||
|
- Create specialization branches with manual or AI-assisted patches while tracking provenance.
|
||||||
|
- Tailor for each application: attach metadata, capture job descriptions, and log accepted suggestions.
|
||||||
|
- Publish any branch/submission as an immutable DOCX/PDF with a slugged URL plus analytics.
|
||||||
|
- Back everything with FastAPI + Postgres + MinIO + Redis + Celery so heavier jobs stay off the web tier.
|
||||||
|
|
||||||
|
## Quick start
|
||||||
```bash
|
```bash
|
||||||
cp .env.example .env # fill in NAME and any keys you need
|
cp .env.example .env # fill in MINIO_*, AUTH_*, etc.
|
||||||
make init # uv venv + sync + env linking
|
make init # uv venv + deps + Bun installs + env linking
|
||||||
make dev # Next.js webapp at http://localhost:3000
|
make lift.minio # optional: start local MinIO bucket
|
||||||
make nx.projects # list Nx projects in the monorepo
|
make run.backend # FastAPI API on http://localhost:8080
|
||||||
|
make dev # Next.js webapp on http://localhost:3000
|
||||||
```
|
```
|
||||||
|
|
||||||
For Docker services (redis, ml inference, worker):
|
Need Redis/Postgres locally? `make lift.database` (Postgres) and `make up` (Redis + worker). For full stack via Docker Compose use `docker compose up backend webapp worker redis postgres minio`.
|
||||||
```bash
|
|
||||||
make up
|
## System architecture
|
||||||
|
| Surface | Stack | Responsibilities |
|
||||||
|
|---------|-------|------------------|
|
||||||
|
| Webapp (`apps/webapp`) | Next.js 15 + React 19 + Tailwind 4 (Bun) | CV tree UI, inline editing, diff viewer, submissions dashboard, publish flows, public CV routes |
|
||||||
|
| Backend (`apps/backend/fastapi`) | FastAPI + SQLAlchemy + uvicorn | Auth/OIDC validation, DOCX ingestion, structured patch engine, branch CRUD, submissions API, publish service |
|
||||||
|
| Worker (`apps/worker`) | Celery + Redis | DOCX parsing, preview rendering, AI tailoring jobs, PDF export, artifact publication |
|
||||||
|
| Shared lib (`dlib`) | Python package | DOCX parser, block schema, patch application/validation, AI prompt helpers, storage adapters |
|
||||||
|
| Data plane | Postgres + MinIO + Redis | Metadata (documents/versions/patches/submissions), artifact storage (DOCX/PDF/HTML), queues + locks |
|
||||||
|
|
||||||
|
```
|
||||||
|
┌────────┐ GraphQL-like REST ┌────────────┐ Object storage
|
||||||
|
│ Webapp │ ─────────────────────────▶ │ FastAPI API│ ───▶ (MinIO/S3)
|
||||||
|
└────────┘ Auth cookie / JWT └──────┬─────┘ ┌────────┐
|
||||||
|
▲ │ │ Worker │
|
||||||
|
│ Webhooks / SSE └────┬─────▶ └────────┘
|
||||||
|
│ │
|
||||||
|
│ Redis queue / locks
|
||||||
|
│ │
|
||||||
|
│ Postgres metadata
|
||||||
```
|
```
|
||||||
|
|
||||||
## Directory
|
## Data model snapshot
|
||||||
|
| Table | Purpose |
|
||||||
|
|-------|---------|
|
||||||
|
| `cv_documents` | Canonical resume root (owner, title, `root_version_id`). |
|
||||||
|
| `cv_versions` | Each branch node; references parent, artifact keys, structured blocks, metadata. |
|
||||||
|
| `cv_patches` | Stored diffs relative to parent version (`target_path`, operation, values, metadata). |
|
||||||
|
| `specializations` | Named reusable branch templates. |
|
||||||
|
| `submissions` | Role/company tailoring instances with status + AI suggestions. |
|
||||||
|
| `public_assets` | Immutable published artifacts (slug, version/submission, storage key, analytics). |
|
||||||
|
| `ai_suggestions` | Pending/accepted/rejected AI patch proposals tied to submissions. |
|
||||||
|
|
||||||
|
## Primary workflows
|
||||||
|
1. **Upload root CV.** Webapp calls `/documents` with a DOCX. Backend persists the original artifact to MinIO, parses structured blocks via `dlib.cv`, stores the first version, and returns the tree.
|
||||||
|
2. **Branch for a specialization.** Create `ml-engineer` from `root`. Backend clones structured blocks, applies staged patches, and records them in `cv_patches`.
|
||||||
|
3. **Tailor for a submission.** Attach job description, request AI suggestions, accept/reject patches, and either extend the branch in place or apply them to a leaf version.
|
||||||
|
4. **Publish.** `/public/publish` copies the artifact to a public bucket path, locks it, emits a slug URL, and tracks views via `public_asset_views`.
|
||||||
|
|
||||||
|
## Configuration essentials
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `API_BASE_URL` | Backend host consumed by the webapp build + runtime. | `http://cvfs-backend:8080` in Docker |
|
||||||
|
| `NEXT_PUBLIC_BASE_URL` | Public origin for web routes. | `https://cv.alves.world` |
|
||||||
|
| `AUTHENTIK_*` / `AUTH_OIDC_*` | OIDC issuer, audience, and client credentials. | required |
|
||||||
|
| `MINIO_ENDPOINT` / `MINIO_BUCKET` | Object storage endpoint + bucket for artifacts. | `https://storage.cv.alves.world` / `resume-branches` |
|
||||||
|
| `REDIS_URL` | Celery broker/result backend. | `redis://cvfs-redis:6379/0` |
|
||||||
|
| `DATABASE_URL` | SQLAlchemy DSN for Postgres. | `postgresql+asyncpg://postgres:postgres@cvfs-postgres:5432/resume_branches` |
|
||||||
|
| `ANTHROPIC_API_KEY` | Enables AI tailoring jobs. | unset |
|
||||||
|
|
||||||
|
`.env.example` documents every supported variable. `make envlink` symlinks root `.env` into all app directories.
|
||||||
|
|
||||||
|
## Repository layout
|
||||||
```
|
```
|
||||||
apps/
|
apps/
|
||||||
webapp/ Next.js 15 + React 19 + Tailwind 4 + Supabase auth (Bun, Turbopack)
|
webapp/ # Next.js dashboard + public routes
|
||||||
webapp-minimal/ Streamlit quick prototype
|
webapp-minimal/ # Streamlit prototype (optional)
|
||||||
backend/
|
backend/fastapi/ # FastAPI service with routers, schemas, services
|
||||||
fastapi/ FastAPI server (set BACKEND_MODE=fastapi)
|
backend/flask/ # Alternative API (mostly unused)
|
||||||
flask/ Flask server (set BACKEND_MODE=flask)
|
worker/ # Celery worker + job modules
|
||||||
worker/ Celery background worker backed by Redis
|
alveslib/ # Shared logging/agent utilities
|
||||||
ml/
|
dlib/ # CV parser + patch engine + storage helpers
|
||||||
configs/ YAML config for data + training hyperparameters
|
docs/ # Architecture notes, deployment playbooks, diagrams
|
||||||
models/ arch.py (architecture) + train.py (training loop)
|
ml/ # Optional ML experiments (etl/train/infer)
|
||||||
data/ etl.py + processed artifacts
|
src/ # Small scripts / CLI helpers
|
||||||
inference.py FastAPI inference server
|
docker/ # Dockerfiles for backend/webapp/worker
|
||||||
notebooks/ Jupyter notebooks
|
Makefile # Developer entrypoints
|
||||||
alveslib/ Shared Python utilities (logger, scraper, agent)
|
|
||||||
src/ Simple scripts / CLI entry points
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Make Targets
|
## Development routines
|
||||||
|
| Command | Purpose |
|
||||||
|
|---------|---------|
|
||||||
|
| `make init` | Bootstrap uv venv, install Python deps, run Bun installs, symlink `.env`. |
|
||||||
|
| `make dev` | Start the Next.js app (`bun x nx run webapp:dev`). |
|
||||||
|
| `make run.backend` | Launch FastAPI (switchable `BACKEND_MODE`). |
|
||||||
|
| `make run.worker` | Start Celery worker (requires Redis & MinIO). |
|
||||||
|
| `make lift.minio` | Local MinIO server + console for artifact testing. |
|
||||||
|
| `make lift.database` | Start Postgres (compose profile). |
|
||||||
|
| `make up` | Bring up redis + worker for background jobs. |
|
||||||
|
| `make nx.projects` | Inspect Nx workspace graph. |
|
||||||
|
| `make test` | Run pytest (unit/integration suites). |
|
||||||
|
|
||||||
| Target | Description |
|
Use `bun x nx affected -t lint,test,build` before PRs to run fine-grained checks.
|
||||||
|--------|-------------|
|
|
||||||
| `make init` | First-time setup |
|
|
||||||
| `make dev` | Start Next.js webapp |
|
|
||||||
| `make up` | Start Docker core services |
|
|
||||||
| `make run.backend` | Start API backend |
|
|
||||||
| `make run.worker` | Start Celery worker |
|
|
||||||
| `make nx.graph` | Open Nx project graph |
|
|
||||||
| `make nx.affected` | Run lint/test/build for affected projects |
|
|
||||||
| `make lift.minio` | Start MinIO object storage |
|
|
||||||
| `make lift.logging` | Start Loki + Grafana |
|
|
||||||
| `make lift.mlflow` | Start optional MLflow server |
|
|
||||||
| `make lift.database` | Start Postgres / MongoDB |
|
|
||||||
| `make doctor` | Verify toolchain |
|
|
||||||
|
|
||||||
Run `make help` for the full list.
|
## Deployment notes
|
||||||
|
- **Docker images:** `docker/backend-fastapi.Dockerfile`, `docker/webapp.Dockerfile`, and `docker/worker.Dockerfile` bake env args for Dokploy. The web build now receives `API_BASE_URL` so rewrites point at the deployed backend.
|
||||||
|
- **Dokploy:** see `docs/resume-branches/dokploy.md` for the API payload that provisions `cvfs-backend`, `cvfs-webapp`, Redis, Postgres, and MinIO on `cv.alves.world` / `api.cv.alves.world`.
|
||||||
|
- **Storage:** `make lift.minio` mirrors the production bucket layout. Set `MINIO_ROOT_USER/MINIO_ROOT_PASSWORD` for parity. Public artifacts should only be published via the API to guarantee immutability + audit logging.
|
||||||
|
|
||||||
## Nx Workspace
|
## Limitations & next steps
|
||||||
|
- AI tailoring currently operates synchronously per submission; multi-edit batching and historical rollbacks are in progress.
|
||||||
|
- Auth is wired to generic OIDC (Authentik-ready) but does not yet expose roles beyond owner/admin.
|
||||||
|
- The worker queue is Redis-backed; scale-out deployments should move to a managed Redis + add observability (Prometheus, structured tracing).
|
||||||
|
|
||||||
This template now ships with Nx project definitions for:
|
## License
|
||||||
|
MIT — see `LICENSE` for details.
|
||||||
- `webapp` (`apps/webapp`)
|
|
||||||
- `webapp-minimal` (`apps/webapp-minimal`)
|
|
||||||
- `backend-fastapi` (`apps/backend/fastapi`)
|
|
||||||
- `backend-flask` (`apps/backend/flask`)
|
|
||||||
- `worker` (`apps/worker`)
|
|
||||||
- `ml` (`ml`)
|
|
||||||
- `alveslib` (`alveslib`)
|
|
||||||
|
|
||||||
Common commands:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bun x nx show projects
|
|
||||||
bun x nx graph
|
|
||||||
bun x nx run webapp:dev
|
|
||||||
bun x nx affected -t lint,test,build
|
|
||||||
```
|
|
||||||
|
|
||||||
## AI Agent Capacity
|
|
||||||
|
|
||||||
Set `ANTHROPIC_API_KEY` in `.env`. Then use:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from alveslib import ask, stream, Agent
|
|
||||||
|
|
||||||
# One-shot
|
|
||||||
print(ask("Summarize this data: ..."))
|
|
||||||
|
|
||||||
# Streaming
|
|
||||||
for chunk in stream("Write a Celery task that ..."):
|
|
||||||
print(chunk, end="", flush=True)
|
|
||||||
|
|
||||||
# Multi-turn
|
|
||||||
agent = Agent(system="You are a senior Python developer.")
|
|
||||||
agent.chat("Scaffold a FastAPI endpoint for user profiles")
|
|
||||||
agent.chat("Add input validation and error handling")
|
|
||||||
```
|
|
||||||
|
|
||||||
Claude Code slash commands (type `/` in a Claude Code session):
|
|
||||||
- `/plan` - implementation plan for an idea within this boilerplate
|
|
||||||
- `/build` - implement a feature end-to-end
|
|
||||||
- `/api` - scaffold a new backend endpoint
|
|
||||||
- `/page` - scaffold a new Next.js page
|
|
||||||
- `/review` - code review of recent changes
|
|
||||||
- `/ship` - stage and commit changes
|
|
||||||
|
|
||||||
## Logging
|
|
||||||
|
|
||||||
```python
|
|
||||||
from alveslib import get_logger
|
|
||||||
logger = get_logger("service")
|
|
||||||
```
|
|
||||||
|
|
||||||
Outputs structured JSON to console + `./logs/`. Optional Loki push when `LOKI_PORT` is set and `make lift.logging` is running. View in Grafana at `http://localhost:$GRAFANA_PORT` (add Loki data source: `http://loki:3100`).
|
|
||||||
|
|
||||||
## Python Packaging
|
|
||||||
|
|
||||||
Python dependencies are managed with `pyproject.toml` and `uv`.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make deps # uv sync
|
|
||||||
make lock # refresh uv.lock
|
|
||||||
uv run pytest -v
|
|
||||||
```
|
|
||||||
|
|
||||||
## ML Workflow
|
|
||||||
|
|
||||||
High-level ML hyperparameters live in YAML configs:
|
|
||||||
|
|
||||||
- `ml/configs/data/default.yaml`
|
|
||||||
- `ml/configs/train/default.yaml`
|
|
||||||
|
|
||||||
Run with Nx targets (cacheable with explicit inputs/outputs):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bun x nx run ml:etl
|
|
||||||
bun x nx run ml:train
|
|
||||||
```
|
|
||||||
|
|
||||||
`ml:train` depends on `ml:etl`, and both targets cache artifacts in `ml/data/processed`, `ml/models/weights`, and `ml/tensorboard`.
|
|
||||||
|
|
||||||
## Services (docker compose profiles)
|
|
||||||
|
|
||||||
| Profile | Services | Command |
|
|
||||||
|---------|----------|---------|
|
|
||||||
| _(default)_ | redis, ml-inference, worker | `make up` |
|
|
||||||
| `minio` | + MinIO object storage | `make lift.minio` |
|
|
||||||
| `tensorboard` | + TensorBoard | `make lift.tensorboard` |
|
|
||||||
| `mlflow` | + MLflow tracking server (optional) | `make lift.mlflow` |
|
|
||||||
| `logging` | + Loki + Grafana | `make lift.logging` |
|
|
||||||
| `database` | + Postgres + MongoDB | `make lift.database` |
|
|
||||||
|
|
||||||
## Webapp Auth
|
|
||||||
|
|
||||||
Auth is off by default (`NEXT_PUBLIC_REQUIRE_AUTH=false`). Set it to `true` and configure Supabase keys to enable session-based auth gating across all routes.
|
|
||||||
|
|
||||||
## Resume Branches MVP
|
|
||||||
|
|
||||||
This repo now powers “Resume Branches”, a CV control plane built on the dstack layout.
|
|
||||||
|
|
||||||
- **Backend** (`apps/backend/fastapi`): FastAPI API that ingests ATS-safe DOCX files, stores structured blocks, supports branching and submissions, and exposes publish endpoints. Configure MinIO via `MINIO_*` env vars. Build image via `docker/backend-fastapi.Dockerfile`.
|
|
||||||
- **Webapp** (`apps/webapp`): Next.js dashboard featuring the CV tree, upload workflow, and publish tooling. It targets the FastAPI host set in `NEXT_PUBLIC_API_BASE_URL` and builds with `docker/webapp.Dockerfile`.
|
|
||||||
- **Worker** (`apps/worker`): Celery worker handling heavy DOCX parsing and AI tailoring suggestions using Redis and MinIO.
|
|
||||||
- **Docs**: `docs/resume-branches/architecture.md` (system design) and `docs/resume-branches/dokploy.md` (Dokploy API payloads for deploying backend to `api.cv.alves.world` and webapp to `cv.alves.world`).
|
|
||||||
|
|
||||||
Local storage uses MinIO via `make lift.minio`; publish-ready artifacts live under the configured bucket.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user