← Home

Technical reference

Empever platform architecture

Empever is an operational platform — employers find leads and manage accounts in Marketing, build teams and hire in Jobs, and onboard staff in Payrolls; candidates find matched jobs and onboard when placed. This page documents how the monorepo, gateway, and department apps deliver that flow in production.

Last updated: 13 June 2026 · Deploy target: empever-platform-ansifi · Live domain: empever.com

1. What Empever achieves

Empever is an operational platform delivered from a single domain (empever.com). Employers find leads, manage CRM accounts, and build hiring teams; candidates find matched jobs and onboard into payroll; Marketing runs outreach and placement pipelines; and Payrolls handles staff records — all from one hub with shared navigation and a client switcher per organisation.

DepartmentPublic pathPrimary capability
Hub/Landing, master login gate, workspace shell, client switcher
HR / Payrolls/hr/Invoices, payroll runs, HRMS, compliance, per-client payroll DBs
Jobs/jobs/Candidate apply, employer roster, interview invites, shortlists, academy
Empever Marketing/marketing/Lead pool ingestion (Reddit, LinkedIn, web), CRM accounts, skill-matched project leads, outreach pipeline
Technical/technical/Academy, assessments, interview prep — often embedded in Jobs
One URL for the team Staff bookmark empever.com, not five SaaS products.
End-to-end hire flow Profile → interview → placement outreach → payroll staff onboarding.
Shared client context Hub client switch propagates to Jobs, placement CRM, and payroll databases.
Path-based routing One Cloud Run ingress proxies all department paths.
Composable departments Each app deploys independently; the hub stitches them together.

Company: Empever is a new venture — the operational platform at empever.com for leads, hiring, CRM, and payroll. Sevendyne is a platform client: a tech consultancy in Kochi, India, whose customers are managed through Empever (alongside other tenants such as Ansif).

2. System context

flowchart TB
  subgraph users [Users]
    Team[Internal team]
    Candidates[Candidates / employers]
  end
  subgraph dns [DNS]
    Apex[empever.com]
    Www[www.empever.com]
  end
  subgraph gcp [GCP asia-southeast1]
    Web[empever-web nginx hub + gateway]
    HR[empever-hr Next.js + Django]
    Mkt[empever-marketing Express + Vite]
    Tech[empever-technical Vite SPA]
    Jobs[empever-jobs static + Flask]
  end
  Team --> Apex
  Team --> Www
  Candidates --> Apex
  Apex --> Web
  Www --> Web
  Web -->|/hr/| HR
  Web -->|/marketing/| Mkt
  Web -->|/technical/| Tech
  Web -->|/jobs/| Jobs
  Mkt --> CRM[(SQLite CRM per tenant)]
  HR --> PayrollDB[(Payroll DBs per client)]
  Jobs --> PortalDB[(Candidates workspace DB)]
                    

Request flow (production):

  1. Browser hits https://empever.com/hr/login.
  2. DNS resolves to Cloud Run domain mapping on empever-web.
  3. empever-web nginx matches location /hr/ and proxies to EMPEVER_HR_UPSTREAM, preserving the path prefix.
  4. empever-hr serves the Next.js shell and Django HRMS behind its own nginx layer.

Hub static assets (index.html, login/, js/, config/) are served directly from empever-web without proxying.

3. Monorepo layout

empever/
├── index.html, login/, hub/, workspace/, invest/   # Static hub
├── js/, css/, config/                               # Shared hub runtime
├── architecture/                                    # This page
├── docker/                                         # Hub Dockerfile + nginx
├── scripts/                                        # Deploy, gateway, auth
├── payrolls/                                       # HR department
├── jobs/                                           # Hiring — talent apply & employer hire
├── marketing/                                      # Placement outreach & CRM
├── devkits/                                        # Technical / academy (embedded in Jobs)
└── Dockerfile + cloudbuild.yaml                    # empever-web build

Hub (repo root)

Static HTML + JavaScript — no Node server in production. Key files: config/platform-clients.json (client registry), config/platform-nav.json (nav paths), js/platform-clients.js (URL builder), js/master-auth.js (hub login → Marketing API).

HR — payrolls/

Stack: Next.js + Django HRMS + nginx · Service: empever-hr · Path: /hr/

Jobs — jobs/

Stack: Static HTML + Flask API · Service: empever-jobs · Path: /jobs/. Candidate profiles, employer matching, interview pipeline, workspace auth.

Empever Marketing — marketing/

Stack: Express API + Vite/React SPA + nginx · Service: empever-marketing · Path: /marketing/. Lead pool ingestion, CRM accounts, skill-first employer/candidate matching, outreach pipeline. Hub login integration (embedded iframe skips second login).

Technical — devkits/

Stack: Vite/React SPA · Service: empever-technical · Path: /technical/. Academy and interview prep — embedded in Jobs candidate workspace.

4. Gateway architecture

Production uses a single ingress service (empever-web) with nginx path proxies — one TLS certificate, one domain mapping, four upstream backends.

LocationUpstream env varBehavior
/(local static)Hub HTML, JS, CSS, config JSON
/hr/EMPEVER_HR_UPSTREAMReverse proxy, 300s read timeout
/marketing/EMPEVER_MARKETING_UPSTREAMReverse proxy + WebSocket headers
/technical/EMPEVER_TECHNICAL_UPSTREAMReverse proxy
/jobs/EMPEVER_JOBS_UPSTREAMReverse proxy

docker/start-empever-web.sh renders the gateway config via envsubst when all four upstream env vars are set; otherwise it falls back to static-only nginx (hub works; department paths 404).

After deploy, scripts/configure-empever-gateway.sh discovers each Cloud Run URL and sets upstream env vars on empever-web.

5. Platform clients (multi-tenancy)

Empever is a multi-client platform. The hub Switch client picker drives isolated data and outbound identity across departments.

FilePurpose
config/platform-clients.jsonHub UI: slug, CRM subdir, jobs tenant, payroll DB
marketing/data/crm/client_outbound.jsonFrom name/email + SMTP env prefix
marketing/data/crm/outreach_profiles.jsonPlacement outreach copy per client
marketing/channel/backend/.env.localSMTP/IMAP secrets (gitignored)
Hub Switch client
  → sessionStorage: empever_platform_client
  → App URLs: ?platform_client= & ?crm_subdir= & ?payroll_db=
  → API headers: X-Empever-Platform-Client, X-Empever-Crm-Subdir
  → CRM SQLite: data/crm/tenants/{subdir}/crm.db
  → SMTP: SMTP_{PREFIX}_* from .env.local

Default clients: sevendyne (production ICP) and dummy_client (sandbox).

6. Authentication architecture

There is no single sign-on across all apps today. Each department maintains its own session, coordinated by a global auth switch and hub master login.

AppLogin URLSession
Hub / workspace/login/Marketing API hub-login
Marketing/marketing/loginExpress session leads.sid
HR (Next)/hr/loginJWT cookie
Django HRMS/accounts/login/Django session
Jobs/jobs/login.htmlsessionStorage
TechnicalVia Jobs embedNo standalone login

Global switch: config/platform-auth.json · Toggle: scripts/enable-platform-auth.sh / disable-platform-auth.sh

Production defaults (June 2026)

Marketing production image sets EMPEVER_MARKETING_SKIP_LOGIN=0 and LEADSAPP_REQUIRE_AUTH=1. Local dev keeps auth off via marketing/docker-compose.dev.yml.

Hub iframe embed does not rely on SKIP_LOGIN — it uses hubEmbedAuth (?empever_embed=1 + X-Empever-Platform-Client header, or hub-login cookie after POST /marketing/api/auth/hub-login).

deploy-empever-gcp.sh runs configure-empever-production-auth.sh when EMPEVER_HUB_PASSWORD is set.

7. GCP deployment architecture

ServiceSourceMemory / CPU
empever-webrepo root512Mi / 1
empever-hrpayrolls/2Gi / 2
empever-marketingmarketing/1Gi / 1
empever-technicaldevkits/1Gi / 1
empever-jobsjobs/512Mi / 1

Region: asia-southeast1 · Project: empever-platform-ansifi

EMPEVER_GCP_PROJECT=empever-platform-ansifi bash scripts/deploy-empever-gcp.sh

Deploy pipeline: enable auth → bootstrap GCP → build & deploy 5 services → wire gateway upstreams → optional production auth secrets → print domain mapping commands.

gcloud beta run domain-mappings create --service=empever-web --domain=empever.com --region=asia-southeast1
gcloud beta run domain-mappings create --service=empever-web --domain=www.empever.com --region=asia-southeast1

Deploy performance & timing

A full platform deploy via deploy-empever-gcp.sh typically takes 25–30+ minutes. Individual service deploys are much faster, but every gcloud builds submit still runs the full Cloud Build pipeline.

Observed build times (empever-platform-ansifi, June 2026)

ServiceArchive sizeBuild durationNotes
empever-web280.8 MiB (3,410 files)2m 42sHub static + nginx gateway image
empever-hr1.2 GiB (57,057 files)6m 43sLargest bottleneck — see below
empever-marketing4.0 MiB (263 files)2m 47sSmall source; fixed pipeline overhead dominates
empever-technical4.6 MiB (142 files)3m 30sSmall source
empever-jobs4.5 MiB (202 files)2m 51sSmall source
Full script total~27 minSequential builds + gateway wiring

Why the full deploy takes long

  1. Five independent deploys, run sequentiallydeploy-empever-gcp.sh waits for each gcloud builds submit to finish before starting the next. You pay ~3–7 minutes per service, added together.
  2. HR upload is ~1.2 GiBpayrolls/ has no .gcloudignore, so local node_modules (~959 MB) and debugs/ (~101 MB) are bundled and uploaded on every HR build. Marketing, Jobs, and Technical each ship only ~4–5 MiB.
  3. Full Cloud Build pipeline per service — Every submit: compress locally → upload tarball to GCS → queue build → docker build → push to Artifact Registry → deploy new Cloud Run revision. Even a 4 MiB app spends ~3 minutes on pipeline overhead.
  4. Docker layer cache — Cold or partial cache means longer npm/pip installs inside the remote build.
  5. Cloud Run revision rollout — After each image push, GCP creates a new revision and routes traffic (usually fast, but one step per service).

Single-service deploys

Deploying only what changed is the fastest day-to-day workflow:

# Hub only (architecture page, index.html, etc.)
cd /home/ansif/works/empever
EMPEVER_GCP_PROJECT=empever-platform-ansifi gcloud builds submit --config=cloudbuild.yaml .

# Marketing only (~3–5 min)
cd marketing && gcloud builds submit --config=cloudbuild.yaml .

A single marketing deploy still takes ~3–5 minutes because the Cloud Build steps (upload, remote Docker build, registry push, Cloud Run deploy) run regardless of archive size.

What would speed up deploys

ChangeImpact
Add payrolls/.gcloudignore (exclude node_modules, debugs/)Largest win — HR upload drops from ~1.2 GiB to tens of MB
Deploy only changed servicesAvoid re-running all five builds
Parallel gcloud builds submitCut wall-clock time; harder to debug failures
CI/CD with cached Docker layersFaster repeat builds on every git push
Pre-built images (skip source submit)Build locally or in CI, push image directly

8. Local development architecture

Local dev does not mirror production path routing by default. Each app runs on its own port.

AppLocal originProduction path
Hubhttp://127.0.0.1:8092https://empever.com/
HRhttp://127.0.0.1:3001/hr/
Marketinghttp://127.0.0.1:5175/marketing/
Jobshttp://127.0.0.1:3080/jobs/
Technicalhttp://127.0.0.1:5174/technical/
./docker-up-all.sh
bash scripts/run-localhost.sh

9. Cross-app integration

  • Shared platform chromeEmpeverPlatformBar in HR, Marketing, Jobs; platform-nav-bar.js on hub.
  • Hiring pipeline — Jobs shortlist API, interview confirm links, in-app notifications; employer status updates through to payroll onboarding (manual today).
  • Marketing API as integration layer — syncs candidate intake from Jobs, talent pool, placement CRM, and outreach.
  • Hub shell embedding/hub/#/{app} loads department apps in an iframe shell.

10. Skill-first lead matching (June 2026 rebuild)

Employer project leads and candidate matched jobs use a shared skill-matching pipeline. External posts are ingested into a central pool; UI refresh filters by profile skills in under one second — no blocking live scan in the request path.

flowchart LR
  subgraph sources [External sources]
    Reddit[Reddit]
    LinkedIn[LinkedIn via web search]
    HN[HN / GitHub / SO]
  end
  subgraph background [Background ingest]
    Bulk[hiringBulkIngest cron]
    Pool[(web_intel_leads)]
  end
  subgraph sync [UI refresh - fast]
    JobsUI[Jobs workspace]
    Match[profileSkillLeadMatch]
    EmpStore[(employer_project_leads)]
    CandStore[(candidate_job_leads)]
  end
  sources --> Bulk --> Pool
  JobsUI --> Match --> Pool
  Match --> EmpStore
  Match --> CandStore
                    

Request flow:

  1. Jobs UI calls POST /jobs/api/workspace/me/project-leads/match (employer) or .../matched-jobs/match (candidate).
  2. Flask candidate_api.pymarkets_employer_leads.py / markets_candidate_leads.py.
  3. Marketing POST /api/portal/employer/:user/match-projects or /candidate/:uuid/match-jobs.
  4. runHiringEmployerMatch / runHiringCandidateMatch scan the pool via profileSkillLeadMatch.js — technical skills only, minimum hit count, junk filters.
  5. Background hiringBulkIngest.js (cron + startup) fetches from Reddit, LinkedIn, and web into web_intel_leads for the next refresh.

Key files changed

FileRole
marketing/.../lib/profileSkillLeadMatch.jsCore matcher — pool scan, skill scoring, discovery helpers
marketing/.../lib/hiringBulkIngest.jsBackground bulk ingestion cron
marketing/.../lib/runHiringEmployerMatch.jsEmployer project-lead match (pool-first)
marketing/.../routes/talentMatch.jsrunHiringCandidateMatch — candidate job match
marketing/.../routes/portalResolve.jsInternal portal APIs for Jobs bridge
marketing/docker/start-cloudrun.shWait for Node health before nginx (fixes 502 cold start)
jobs/backend/markets_employer_leads.pyJobs → Marketing employer match bridge
jobs/backend/markets_candidate_leads.pyJobs → Marketing candidate match bridge
jobs/js/employer-project-leads.jsEmployer workspace UI
jobs/js/candidate-matched-jobs.jsCandidate matched jobs UI
marketing/data/crm/outreach_profiles.jsonEmployer match_skills per client (e.g. Sevendyne)

Env tuning: HIRING_WEB_INTEL_POOL_LIMIT, EMPLOYER_PROJECT_MATCH_MIN, TALENT_MATCH_INTERNAL_MIN, HIRING_BULK_INGEST_DISABLED, TAVILY_API_KEY (web/LinkedIn search quality).

11. Data layer

StoreLocationScope
CRMmarketing/data/crm/tenants/{subdir}/crm.dbPer platform client
Outreachoutreach_profiles.jsonPer outreach client ID
PayrollPer payroll_db keyHR department
Jobs / candidatesjobs/backend/data/rxx_candidates.dbPer jobs_tenant
Jobs workspacejobs/data/workspace/workspace.dbPortal logins
Devkitsdevkits/data/devkits.sqliteTechnical assessments

Production persistence (GCS)

Cloud Run has no persistent disk. Each data service syncs SQLite to gs://empever-platform-ansifi-empever-db via EMPEVER_DB_GCS_BUCKET:

ServiceGCS prefixSync script
empever-marketingmarketing/marketing/docker/db-gcs-sync.sh
empever-jobsjobs/jobs/docker/db-gcs-sync.sh
empever-hrhr/payrolls/docker/db-gcs-sync.sh
empever-technicaltechnical/devkits/docker/db-gcs-sync.sh

Boot: GCS restore → app start → backup on shutdown (HR: every 5 min). Git SQL seeds run only when EMPEVER_FORCE_SEED_DB=1 — never on routine redeploys. empever-hr stays at max-instances=1 (SQLite single-writer). See jobs/docker/CLOUD_DB_TODO.md.

12. Operational scripts

ScriptPurpose
deploy-empever-gcp.shFull Empever deploy
configure-empever-gateway.shWire empever-web upstreams
configure-empever-production-auth.shProduction auth env on Cloud Run
pause-empever-gcp.shDelete services + domain mappings
run-localhost.shPython static hub on :8092
docker-up-all.shLocal Docker stacks

14. Current state (June 2026)

ComponentStatus
All 5 Cloud Run servicesDeployed in asia-southeast1
Gateway upstreamsWired on empever-web
Domainempever.com live
Skill-first lead matchingPool-first refresh + background bulk ingest
Production authMarketing SKIP_LOGIN=0; hub-login + embed bypass
GCS DB persistenceempever-platform-ansifi-empever-db on all data services
HR SQLite writermax-instances=1 + periodic GCS backup
Marketing cold startmin-instances=1 + Node health wait before nginx
Architecture pageempever.com/architecture

15. Known gaps

  1. Dual branding — Empever and Empever share one repo with separate deploy scripts.
  2. Project ID drift — Older docs reference empever-497411; live deploy uses empever-platform-ansifi.
  3. No SSO — Hub login gates workspace but does not issue tokens for HR or Jobs.
  4. GCS stopgap, not Cloud SQL — SQLite file sync survives redeploys; Payrolls should migrate to Cloud SQL long-term.
  5. payrolls/.gcloudignore — Missing; HR deploy uploads ~1.2 GiB including local node_modules.

16. Architecture principles

  1. One domain, many services — Users see empever.com; operators deploy five Cloud Run services.
  2. Hub is static + gateway — Minimal hub container; department complexity lives in child services.
  3. Client switch is the tenancy boundary — Registry JSON + headers, not separate subdomains.
  4. Marketing owns hub auth and CRM — Natural integration point for cross-app APIs.
  5. Independent deployability — Each cloudbuild can run alone; gateway script reconnects upstreams.
  6. Local-first velocity — Auth off, separate ports, Docker Compose; production adds gateway, auth, DNS.