An open-source, AI-powered interactive CV platform — turn your career history into a recruiter-facing public profile with retrieval-augmented chat and structured job-fit analysis.
Profiley lets candidates upload their CV and supporting documents, automatically extracts and indexes them into a searchable knowledge base, and exposes a polished public profile that recruiters can browse, chat with, and run job-fit analysis against — all backed by transparent, admin-managed AI model routing.
- Repository: https://github.com/akram0zaki/profiley
- Status: active development; dev environment deployed
- License: AGPL-3.0-or-later (code) · CC BY 4.0 (documentation)
- Highlights
- Feature Status
- Technology Stack
- Architecture Overview
- Project Structure
- Pages and Routes
- Getting Started
- Useful Scripts
- Deployment
- Documentation
- Security
- Contributing
- License and Attribution
- 🧠 Retrieval-augmented chat over your own documents using
pgvectorand an admin-managed model registry (OpenAI, Gemini, Mistral). - 📄 Document ingestion pipeline with signed uploads, background processing, chunking, and embeddings — all in Supabase Edge Functions.
- 🌐 Public recruiter profile with shareable slug, gated contact form, live persona chat, and structured job-fit analysis.
- 📊 Owner dashboard with live analytics: recruiter visits, events, conversations, uploads, and job-fit runs.
- 🛡️ Row-Level Security everywhere — multi-tenant data is RLS-scoped from day one.
- ☁️ One-command deploys to Cloudflare Pages (frontend) and Supabase (schema + edge functions).
- ✅ Authentication: Google, GitHub, and email magic link
- ✅ Profile management: editable profile, preferences, visibility, and shareable public slug
- ✅ Document upload: signed upload URLs, storage, processing status, deletion, and knowledge chunk generation
- ✅ Knowledge base: direct chunk browsing plus retrieval over vectorized knowledge
- ✅ AI chat: recruiter-facing persona chat backed by edge functions, with citations
- ✅ Job-fit analysis: structured analysis persisted to the database
- ✅ Public profile: live recruiter view, activity tracking, and gated contact/chat/job-fit features
- ✅ Dashboard: live analytics from recruiter visits, events, conversations, uploads, and job-fit runs
- ✅ Settings and admin: privacy controls, persona tone, model registry, feature-to-model assignment, and provider health
- ✅ Cloudflare Pages deployment: dev and prod workflows
- 🔜 Live AI avatar generation
- 🔜 Real-time voice conversations with AI
- 🔜 Apple OAuth
- 🔜 Per-user model overrides
- 🔜 Full observability and test hardening (pgTAP, k6, Sentry/PostHog)
Frontend
- React 18 · React Router 7 · TypeScript
- Vite 6 · Tailwind CSS v4
- Radix UI + shadcn/ui patterns · Sonner
Backend & infrastructure
- Supabase: Auth, Postgres, Storage, Edge Functions (Deno)
pgvectorfor embeddings and RAG- Cloudflare Pages + Wrangler
- AI provider routing across OpenAI, Gemini, and Mistral via admin-managed configs
┌────────────────────────┐
│ Cloudflare Pages │
│ React SPA (Vite) │
└──────────┬─────────────┘
│ HTTPS
▼
┌────────────────────────────────────────────────┐
│ Supabase Project │
│ │
│ Auth │
│ │ │
│ ▼ │
│ Postgres (RLS) ◄──► Edge Functions (Deno) │
│ │ │ │
│ ▼ ▼ │
│ pgvector AI providers │
│ (OpenAI / Gemini / │
│ Mistral, admin-routed) │
│ │
│ Storage — signed uploads & documents │
└────────────────────────────────────────────────┘
See docs/concept/ and docs/flows/ for deeper design notes and flow diagrams.
apps/
frontend/ # React SPA (Vite, Tailwind, shadcn/ui)
src/app/ # Pages, components, contexts
src/lib/ # Shared client utilities
functions/ # Cloudflare Pages functions
test/ # Vitest specs
supabase/
migrations/ # Versioned SQL migrations (RLS, schema, seeds)
functions/ # Deno edge functions (one folder per function)
tests/ # Deno tests for edge functions
docs/
DESIGN_SYSTEM.md
I18N_RTL_GUIDE.md
testing.md
concept/ # Product design, PRD, init guide
flows/ # Mermaid diagrams for ingestion, chat, etc.
| Route | Purpose |
|---|---|
/ |
Marketing landing page |
/login |
Sign-in with Google, GitHub, or magic link |
/auth/callback |
OAuth / magic-link callback |
/onboarding |
Multi-step profile setup persisted to Supabase |
/dashboard |
Owner dashboard with live analytics |
/profile |
Profile editor |
/uploads |
Document upload and processing management |
/knowledge |
Knowledge chunk browser |
/chat-preview |
Owner-side chat preview |
/job-fit-preview |
Owner-side job-fit preview |
/public/:username |
Public recruiter-facing profile |
/settings |
Account and privacy settings |
/settings/ai |
Persona and model summary |
/settings/avatar |
Placeholder for the future avatar workflow |
/admin |
Admin-only provider registry and health dashboard |
- Node.js 20+
- pnpm 9+
- A Supabase project (free tier is fine for local development)
- Populated env files:
apps/frontend/.env.development— local/dev frontend buildsapps/frontend/.env.production— production frontend buildssupabase/.env— Supabase CLI work (project refs, DB password)supabase/functions/.env.development/.env.production— edge function secrets.github/.env.ci— Cloudflare deploys
See
supabase/functions/.env.exampleanddocs/concept/profiley-init-guide.mdfor the full list of required keys.
git clone https://github.com/akram0zaki/profiley.git
cd profiley
pnpm installpnpm devThis runs the Vite app from apps/frontend against apps/frontend/.env.development.
pnpm test # frontend (Vitest) + edge (Deno) tests
pnpm test:frontend # Vitest only
pnpm test:edge # Deno tests in supabase/tests/Testing strategy and conventions are documented in docs/testing.md.
pnpm build # development build (apps/frontend/dist)
pnpm build:prod # production build
pnpm preview # preview the built bundleRun from the repository root:
| Script | Description |
|---|---|
pnpm dev |
Run the frontend locally in development mode |
pnpm build / pnpm build:prod |
Build the SPA in development / production mode |
pnpm preview |
Preview the built frontend bundle |
pnpm test |
Run frontend and edge tests |
pnpm run ci |
Run every CI check locally (build + deno check + tests) |
pnpm run ci:edge |
Type-check every edge function, as CI does |
pnpm run deploy |
Build and deploy to the dev Cloudflare Pages project |
pnpm deploy:prod |
Build and deploy to the prod Cloudflare Pages project |
pnpm install points core.hooksPath at .githooks, whose pre-push hook
runs pnpm run ci — the same three checks GitHub Actions runs on a PR, so a
push fails locally instead of on the PR:
ci:build— production build of the SPAci:edge—deno checkon everysupabase/functions/*/index.tspnpm test— Vitest plus Deno tests
Both the hook and the workflow call scripts/ci-edge-check.sh, so there is one
definition of the edge check. It runs from supabase/: from the repo root Deno
resolves the root package.json and fails on missing npm type packages.
Skip the hook for a single push with git push --no-verify. If hooks are not
active (a clone that never ran pnpm install), enable them with
git config core.hooksPath .githooks.
There are two environments, each a Supabase project paired with a Cloudflare Pages project:
| Environment | Supabase project | Pages project | Vite mode | Edge secrets file |
|---|---|---|---|---|
| dev (staging) | $SUPABASE_PROJECT_REF_DEV |
$CLOUDFLARE_PAGES_PROJECT_DEV (e.g. profiley-dev) |
development |
supabase/functions/.env.development |
| prod | $SUPABASE_PROJECT_REF_PROD |
$CLOUDFLARE_PAGES_PROJECT_PROD (e.g. profiley) |
production |
supabase/functions/.env.production |
Always deploy the backend before the frontend, so the new UI never calls functions or columns that are not there yet. Run pnpm test first.
Local deploys ship your working tree, not git — uncommitted changes and untracked migrations are included. The GitHub Actions workflow only deploys what is pushed to
main.
Schema and edge functions are managed entirely through workspace files (supabase/migrations/*.sql and supabase/functions/<name>/index.ts) — never via the dashboard.
set -a && source supabase/.env && set +a
# Schema
supabase link --project-ref "$SUPABASE_PROJECT_REF_DEV"
supabase db push --password "$SUPABASE_DB_PASSWORD_DEV"
# Edge function secrets (idempotent)
supabase secrets set \
--project-ref "$SUPABASE_PROJECT_REF_DEV" \
--env-file supabase/functions/.env.development
# Edge functions (all of them)
for fn in supabase/functions/*/; do
name=$(basename "$fn")
[[ "$name" == "_shared" ]] && continue
supabase functions deploy "$name" --project-ref "$SUPABASE_PROJECT_REF_DEV" --no-verify-jwt
doneFor production, use the _PROD variables and supabase/functions/.env.production.
--no-verify-jwt is required: public and cron-driven functions receive no JWT, and authenticated ones validate it themselves via requireUser(). Do not run supabase login — the CLI authenticates with the SUPABASE_ACCESS_TOKEN in supabase/.env.
pnpm run deploy # dev (staging) project — plain `pnpm deploy` is a pnpm built-in and fails
pnpm deploy:prod # prod projectEach deploy script sources .github/.env.ci, builds with the matching Vite mode (reading apps/frontend/.env.development or .env.production), and publishes apps/frontend/dist via Wrangler. Required variables in .github/.env.ci:
CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_IDCLOUDFLARE_PAGES_PROJECT_DEVCLOUDFLARE_PAGES_PROJECT_PROD
The Pages Functions runtime variables (SUPABASE_URL, SUPABASE_ANON_KEY, PUBLIC_APP_ORIGIN) are set once per Pages project in the Cloudflare dashboard; wrangler pages deploy does not upload them.
The manual deploy workflow (.github/workflows/deploy.yml) is prod-only: it pushes migrations, deploys every edge function, then builds and publishes the frontend. Trigger it from the Actions tab or with gh workflow run deploy.yml. It never runs on push, does not sync edge function secrets, and needs the repo secrets listed in the init guide.
Run the smoke test in docs/concept/profiley-init-guide.md §8. The same guide covers first-time setup (creating the Pages projects, auth providers, cron secret) and the full deploy checklist.
docs/DESIGN_SYSTEM.md— UI tokens, components, and patternsdocs/I18N_RTL_GUIDE.md— locale and RTL rulesdocs/testing.md— frontend and edge testing strategydocs/concept/profiley-prd.md— product requirementsdocs/concept/profiley-design.md— design notesdocs/concept/profiley-init-guide.md— secrets, Supabase setup, deploy checklistdocs/flows/— Mermaid diagrams for ingestion, chat, and other flowsAGENTS.md— cross-cutting rules for automated and human contributors
For production use with real user data:
- Keep secrets in the gitignored env files documented in
AGENTS.md. Never put secrets inVITE_*variables — those are inlined into the public client bundle. - Apply schema changes through
supabase/migrations/and verify Row-Level Security policies on every change. - Rotate the Supabase DB password and provider API keys before opening the project to external traffic.
- Found a vulnerability? Please open a private security advisory via GitHub rather than a public issue.
Contributions are welcome — see CONTRIBUTING.md for the full policy. In short:
- Code is contributed under AGPL-3.0-or-later.
- Documentation is contributed under CC BY 4.0.
- The Profiley name, logo, and branding are not licensed for reuse — see
TRADEMARKS.md. - Follow the workspace conventions in
AGENTS.mdand the runtime-specific instructions under.github/instructions/. - Add or update tests for every functional change and update
CHANGELOG.mdfor meaningful product or operational changes.
- Source code: GNU Affero General Public License v3.0 or later. If you modify and run Profiley as a network service, you must make the corresponding source code available to its users.
- Documentation and written content: Creative Commons Attribution 4.0 International, unless otherwise noted.
- Branding and trademarks: the Profiley name, logo, and visual identity are reserved — see
TRADEMARKS.md. - Third-party notices and credits live in
NOTICEandATTRIBUTIONS.md.
Copyright © 2026 Akram Zaki.
Built with React, Supabase, and Cloudflare. Last updated: April 28, 2026.