DeepSeek Harness Remote
DeepSeek Harness Remote 可將手機或另一台電腦與你運行 DeepSeek Harness 的電腦安全連接,隨時隨地繼續你的工作,方便隨時查看進度並繼續工作。
AI 翻譯
尚未收集儲存庫資訊。
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗Upload a CV, pick a target career, and get an explainable Career Readiness Score, a skill-gap breakdown, recommendations, and a shareable, publicly verifiable Career Readiness Certificate.
This is a complete, working, launch-ready Phase 1 codebase. Nothing has been deployed, and no production accounts (Netlify, Supabase, AI API) are required to run it locally.
USER
|
v
+----------------+
| NEXT.JS | frontend/ (TypeScript, Tailwind)
| FRONTEND |
+-------+--------+
| Next.js Route Handlers proxy requests to the
| Python engine. PYTHON_API_URL never reaches
| the browser.
v
+----------------+
| API / SERVER | frontend/app/api/*
| LAYER |
+-------+--------+
|
v
+----------------+
| PYTHON / | python-engine/ (FastAPI)
| FASTAPI ENGINE |
+-------+--------+
|
+------------+------------+
| | |
v v v
CV Parser Skill Engine Scoring
(extractors/) (nlp/) (scoring/)
|
v
Career Assessment
|
v
Certificate (services/)
frontend/) — Next.js 14 (App Router) + TypeScript +
Tailwind. Renders the landing page, analysis form, results, certificate,
and public verification page. Talks to the Python engine only through
its own server-side Route Handlers (frontend/app/api/*), so
PYTHON_API_URL and any future secrets never reach client JavaScript.python-engine/) — FastAPI service that does all of
the real analysis work: CV text extraction, evidence-aware skill
extraction, explainable scoring, recommendations, and certificate
(PDF) generation. The Python scoring engine is the sole authority on
the numeric score — no LLM is involved in deciding it.Repository interface
(python-engine/app/db/interface.py) is implemented today by a
zero-config SQLite store (local_store.py) so the whole app runs
locally with no external services. supabase/migrations/ contains
Postgres-ready SQL that mirrors the same shape, so a
SupabaseStore implementing the same interface is a drop-in swap
later — no other code changes needed.python-engine/app/data/career_models/ - no code changes required.app/nlp/taxonomy.py) - the
frontend never hard-codes skill names. Covers both tech skills
(Python, Docker, Kubernetes, ...) and education skills (lesson
planning, classroom management, differentiated instruction, ...) to
support non-tech careers like English Teacher.app/nlp/skill_extractor.py):
presence, evidence strength, depth (mentioned vs. actually
demonstrated - scoped to the sentence containing the mention, not a
fixed character window, so evidence from one sentence can't leak
into an unrelated neighbouring mention), and recency. Sentence
splitting correctly handles bullet-list CVs (lines separated by a
single newline, no punctuation - very common in real resumes), and
explicit self-rated proficiency ("Python - Moderate", "SQL:
Beginner") is detected and takes priority over a vaguer mention
elsewhere in the same CV.app/scoring/scorer.py) combining
coverage × evidence × depth × recency × career importance/frequency
into a 0–100 score, with a per-skill breakdown./verify/[certificateId] page. The career
dropdown is populated live from /api/careers, so it reflects
whatever careers exist in the data directory./dashboard route is protected and ready for
Phase 2 "save your results" features, while the core CV → score →
certificate flow works with zero setup and no account required.Per the build spec: job board, LinkedIn/GitHub integration, payments, chatbot/AI career coach, social features, mobile app, additional careers beyond ML Engineer, real-time market monitoring, resume builder, community features, and a large analytics dashboard. These are future phases.
cd python-engine
python3 -m venv .venv && source .venv/bin/activate # optional but recommended
pip install -r requirements.txt
cp .env.example .env # defaults already work locally
uvicorn app.main:app --reload --port 8000
Check it's up: curl http://localhost:8000/health → {"status":"ok"}.
The engine stores data in a local SQLite file
(python-engine/local_dev.db) by default — nothing external required.
In a second terminal:
cd frontend
npm install
cp .env.example .env.local # PYTHON_API_URL defaults to http://localhost:8000
npm run dev
Open http://localhost:3000.
The browser never calls the Python API directly. Next.js Route Handlers
under frontend/app/api/* read PYTHON_API_URL (server-side only) and
proxy the request, so the Python engine's location is never exposed to
client JavaScript and can be changed freely (e.g. to a deployed URL)
without touching frontend code.
cd python-engine
pytest
13 tests cover skill scoring across CV strength levels, validation errors, extraction failures, and the full analyze → certificate → verify API flow.
Frontend type-checking: cd frontend && npx tsc --noEmit.
cd frontend && npm run build
See frontend/.env.example and python-engine/.env.example for the
authoritative, commented list. Summary:
Frontend (frontend/.env.local)
| Variable | Required locally? | Notes |
|---|---|---|
PYTHON_API_URL | Yes | Points at your running Python engine. |
NEXT_PUBLIC_APP_URL | No | Used to build certificate verify links. |
NEXT_PUBLIC_SUPABASE_URL | No | Fill in when you connect Supabase. |
NEXT_PUBLIC_SUPABASE_ANON_KEY | No | Safe to expose to the browser. |
SUPABASE_SERVICE_ROLE_KEY | No | Server-side only. Never expose to the browser. |
AI_API_KEY | No | Optional; only used to rephrase recommendations. |
Python engine (python-engine/.env)
| Variable | Required locally? | Notes |
|---|---|---|
ALLOWED_ORIGINS | No (has default) | CORS allow-list. |
STORAGE_BACKEND | No (defaults to local) | local (SQLite) or supabase (implement first). |
LOCAL_DB_PATH | No | SQLite file path for local dev. |
PUBLIC_VERIFY_URL_BASE | No | Used on certificate PDFs; leave blank locally. |
AI_API_KEY | No | Optional, never required to run the core product. |
No secrets are hard-coded anywhere in the codebase.
Each career lives in its own file: python-engine/app/data/career_models/<slug>.json.
| Career | Slug | O*NET-SOC code | Match quality |
|---|---|---|---|
| ML Engineer | ml-engineer | 15-1221.00 (Computer and Information Research Scientists) | Closest available - O*NET has no distinct "ML Engineer" title yet |
| Data Scientist | data-scientist | 15-2051.00 (Data Scientists) | Exact match |
| Software Engineer | software-engineer | 15-1252.00 (Software Developers) | Exact match |
| English Teacher | english-teacher | 25-2031.00 (Secondary School Teachers) | "English Teacher" is O*NET's own listed sample job title for this broader occupation |
Every skill weight in these files carries a source tag so nothing is
silently presented as more verified than it is:
"onet_hot_technologies" - a real percentage of employer job
postings mentioning that skill for this occupation, pulled from
O*NET's public Hot Technologies report (Lightcast job-postings data).
This is genuine market data, not an estimate."onet_api" - a real numeric Importance score (0-100) from the
authenticated O*NET Web Services API, via scripts/onet_sync.py."onet_technology_list_only" - the skill is confirmed relevant by
O*NET's technology list, but no numeric score is available yet."benchmark_estimate" - not yet sourced from anywhere verified.
An initial estimate seeded by the product team. The API response
labels these clearly (onet_source / weight_source fields) so the
frontend never presents them as verified statistics.All ONET careers are generated from the free ONET Database. To rebuild
them (for example when ONET publishes a new release), open GitHub ->
Actions -> **Regenerate careers from ONET** -> Run workflow. It
downloads the latest text database, runs
scripts/onet_bulk_import.py --import-all, and commits the updated
app/data/career_models/ files plus scripts/last_import_report.json.
Skills are matched exactly through app/nlp/onet_elements.py (every
ONET Skill and Knowledge area, keyed by Element ID). Each skill in a
career file records the onet_element it came from, so the mapping can
be audited. Occupations ONET doesn't rate (mostly "All Other"
catch-alls) are skipped.
app/data/career_models/, update slug/name/description/onet,
and hand-write skill weights (mark them "benchmark_estimate"
honestly if you're guessing).db_29_1_text.zip).~/Downloads/db_29_1_text/.cd python-engine
python3 -m scripts.onet_bulk_import --db-dir ~/Downloads/db_29_1_text --list-occupations
python3 -m scripts.onet_bulk_import \
--db-dir ~/Downloads/db_29_1_text \
--soc-code <code> --career-slug <slug> --career-name "..."
cd python-engine
export ONET_USERNAME=... ONET_PASSWORD=...
python3 -m scripts.onet_sync --soc-code <code> --career-slug <slug> --career-name "..."
app/nlp/taxonomy.py first if the career
needs vocabulary that isn't covered yet (see the Education category
added for English Teacher as an example of extending into a
non-tech domain).list_careers() picks up new files
automatically, and the frontend's career dropdown (/api/careers) reflects
it immediately, no frontend code changes needed.Clerk (@clerk/nextjs) is already installed and wired into the code -
turning it on is two environment variables, not a code change.
frontend/.env.local:
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...
npm run dev. That's it:
components/AuthProvider.tsx now wraps the app in ClerkProvider.components/AuthSection.tsx).middleware.ts starts protecting /dashboard - visiting it while
signed out redirects to Clerk's sign-in flow automatically./dashboard (app/dashboard/page.tsx) lists every certificate the
signed-in user has generated, via GET /api/certificates
(app/api/certificates/route.ts, which uses the caller's own
verified Clerk session - never a client-supplied user id).app/api/certificate/route.ts) and prompts you to sign up/sign in
first if needed (components/GenerateCertificateButton.tsx). Set
REQUIRE_ACCOUNT_FOR_CERTIFICATE=true in the Python engine's .env
too for a defense-in-depth check on that side as well.Until you set the two env vars above, none of this activates: the app
builds, runs, and serves the full CV → score → certificate flow exactly
as if Clerk weren't installed at all (see lib/clerk.ts), with no
sign-up required anywhere.
A note on secrets: never paste your CLERK_SECRET_KEY (or any
secret key) into a chat tool, ticket, or anywhere outside your own
.env.local file (which is already git-ignored). If a secret key is
ever exposed somewhere it shouldn't be, roll it from the Clerk dashboard
app/terms/page.tsx and app/privacy/page.tsx contain a drafted Terms
of Service and Privacy Policy, written to reflect what this specific
application actually collects and does (CV upload, free certificate
generation requiring a Clerk account, public certificate verification,
no ads, no data sale). These are templates, not legal advice - they
say so directly on the page. Before launching for real:
[bracketed placeholder] (company name, contact email, retention policy, age threshold, etc.).Both pages are linked from the site footer.
This project is already a git repository with an initial commit. To push it to your own GitHub account:
# 1. Create a new, empty repository on github.com (don't initialize it
# with a README/license - this repo already has one).
# 2. From the project root:
git remote add origin https://github.com/<your-username>/<your-repo>.git
git branch -M main
git push -u origin main
Once pushed, .github/workflows/ci.yml runs automatically on every push
and pull request: it installs the Python engine's dependencies and runs
the full test suite, and separately type-checks and builds the frontend
(with no Clerk/Supabase/AI keys configured, proving the app builds
cleanly without them). No secrets or deployment credentials are needed
for CI to pass - it only tests and builds, it doesn't deploy anything.
Connecting this GitHub repo to Netlify (step 10 below) is what actually deploys the frontend - pushing to GitHub by itself does not deploy or launch anything.
supabase/migrations/ in order (via the SQL editor or
supabase db push) — this creates the schema, RLS policies, and seeds
the ML Engineer taxonomy/career model.python-engine/app/db/supabase_store.py against the
Repository interface in app/db/interface.py (same method shapes as
local_store.py), then set STORAGE_BACKEND=supabase and provide
SUPABASE_URL / SUPABASE_SERVICE_ROLE_KEY to the Python engine.NEXT_PUBLIC_SUPABASE_URL / NEXT_PUBLIC_SUPABASE_ANON_KEY on the
frontend only once you build the optional "create an account to save
your results" feature — the core flow doesn't require it.supabase/migrations/0008_usage_analytics.sql adds an anonymous
usage_events table. The site records which step someone reached (opened
the check page, picked a career, chose a file, got a score, clicked "Get my
certificate", shared) with the career and file type, via
frontend/lib/track.ts and POST /api/events. No names, emails, account
IDs or CV text are stored; unique people are counted with a random ID in
the browser's local storage (disclosed in the Privacy Policy). Events are
deleted after 12 months.
The founder reads these numbers in a Claude dashboard that queries
Supabase directly; there is no analytics page inside the app. The
migration's admin_usage_stats(days) function returns the same numbers in
one call, for any future in-app use.
frontend/netlify.toml (base directory, build
command, and the @netlify/plugin-nextjs plugin) automatically.PYTHON_API_URL in the Netlify site's environment variables to
point at wherever you deploy the Python engine (step 11).python-engine/Dockerfile builds a container exposing port 8000. Deploy
it to any container host you like (Fly.io, Render, Cloud Run, ECS, etc.).
Set ALLOWED_ORIGINS to your deployed frontend's URL and
PUBLIC_VERIFY_URL_BASE to your public domain once you have one.
Phase 1 works fully without any AI API key. If you later want more
natural-language recommendations, wire an AI API call into
app/recommendations/engine.py that takes the deterministic
recommendations as input and rephrases them — the ranked list of gaps and
the score must keep coming from the Python engine, never the LLM.
career-readiness-analyzer/
frontend/ Next.js app (TypeScript, Tailwind)
app/ Pages + Route Handlers (proxy to Python engine)
components/ Reusable UI components
lib/ Config + typed API helpers (server-only)
netlify.toml Netlify build config (not deployed by default)
python-engine/ FastAPI service - the real analysis engine
app/
api/ FastAPI routes
extractors/ PDF/DOCX text extraction
nlp/ Skill taxonomy + evidence-aware extraction
scoring/ Career model + explainable scoring
recommendations/ Deterministic recommendation engine
services/ Orchestration (analysis, certificates)
db/ Repository interface + local SQLite store
models/ Pydantic schemas
tests/ Pytest suite
Dockerfile Deployment-readiness only, not built/deployed
supabase/
migrations/ Postgres schema, RLS policies, seed data
README.md You are here
supabase/migrations/*.sql.app/db/supabase_store.py, set STORAGE_BACKEND=supabase.python-engine (Docker) somewhere with a stable URL.PUBLIC_VERIFY_URL_BASE / ALLOWED_ORIGINS on the deployed engine.PYTHON_API_URL there.REQUIRE_ACCOUNT_FOR_CERTIFICATE=true on the deployed Python engine.[bracketed placeholders] in app/terms/page.tsx and app/privacy/page.tsx, and have a lawyer review both (see section 7).scripts/onet_sync.py, or download the bulk database and run scripts/onet_bulk_import.py (see section 5), for each career to replace remaining benchmark estimates with real numeric scores.This project does not perform any of the above automatically — every step here is something you trigger yourself when ready.
supabase/migrations/frontend/netlify.toml) and a
Python Dockerfile for independent deployment later — neither is
used to deploy anything now..github/workflows/ci.yml - GitHub Actions CI that runs the backend
test suite and the frontend type-check/build on every push and PR.