1 Architecture Overview
The demonstrator aligns with the 2nth.ai Cloudflare-first architecture. For local testing, Cloudflare Tunnel is replaced by direct localhost access.
2nth.ai Alignment
| Layer | 2nth.ai | Huly Demonstrator |
|---|---|---|
| Edge / CDN | Cloudflare Workers/Pages | Cloudflare Tunnel + CDN |
| DNS / SSL | Cloudflare | Cloudflare (Full SSL) |
| Resend | Resend (SMTP bridge) | |
| AI Agents | Claude API via 2nth agents | Claude API (replaces OpenAI/Hulia) |
| Data | D1 / KV | CockroachDB + Elasticsearch + MinIO |
| Hosting | Cloudflare edge | Hetzner VPS (Docker) / local Mac |
2 Prerequisites
Lightweight Docker runtime for Mac. Much faster and lighter than Docker Desktop.
brew install orbstack
Required for cloning the repo and running seed scripts.
brew install git node
The Huly stack requires 8 GB RAM minimum free. Elasticsearch alone reserves 1 GB heap. Close heavy apps before starting.
3 Local Docker Setup
Clone the Huly self-host repository
git clone https://github.com/hcengineering/huly-selfhost.git
cd huly-selfhost
Run quick setup
The --quick flag configures for localhost:8087, skips all prompts, generates secrets, and auto-starts all containers.
./setup.sh --quick
Wait for services to initialise
All 14 containers need ~60 seconds to fully start. Check status with:
docker compose ps # all services should show "Up"
docker compose logs -f # follow logs (Ctrl+C to exit)
Verify Huly is running
Open http://localhost:8087 in your browser. You should see the Huly login page.
nginx, cockroach, redpanda, minio, elastic, rekoni, transactor, collaborator, account, workspace, front, fulltext, stats, kvs
4 Account & Workspace Creation
Create Admin Account (API)
curl -s -X POST "http://localhost:8087/_accounts" \
-H "Content-Type: application/json" \
-d '{"method": "signUp", "params": {
"email": "admin@agilex.co.za",
"password": "AgileX2024!",
"firstName": "Craig",
"lastName": "Sobey"
}}'
Returns a JWT token for authenticated requests.
Create Workspace
# Use the token from signUp response
curl -s -X POST "http://localhost:8087/_accounts" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"method": "createWorkspace", "params": {
"workspaceName": "AgileX Recruitment",
"workspaceUrl": "agilex-recruitment"
}}'
Returns a workspace token with the workspace UUID and URL.
The account service's STATS_URL must point to the internal Docker hostname, not localhost:8087 (unreachable inside containers). In compose.yml, change the account service environment:
- STATS_URL=http://stats:4900 # was: http://localhost:8087/_stats
Then restart: docker compose up -d account
5 Staff Onboarding (10 Members)
Each staff member is created in two steps: signUp (creates account) then invite + join (adds to workspace).
Step 1: Create Staff Accounts
# For each staff member:
curl -s -X POST "http://localhost:8087/_accounts" \
-H "Content-Type: application/json" \
-d '{"method": "signUp", "params": {
"email": "thandi.mokoena@agilex.co.za",
"password": "AgileX2024!",
"firstName": "Thandi",
"lastName": "Mokoena"
}}'
Step 2: Create Invite Link (as workspace Owner)
curl -s -X POST "http://localhost:8087/_accounts" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OWNER_TOKEN" \
-d '{"method": "createInviteLink", "params": {
"email": "thandi.mokoena@agilex.co.za",
"role": "OWNER",
"expHours": 720
}}'
# Returns: http://localhost:8087/login/join?inviteId=...
Step 3: Accept Invite (as the staff member)
# Extract inviteId from the URL, then:
curl -s -X POST "http://localhost:8087/_accounts" \
-H "Content-Type: application/json" \
-d '{"method": "join", "params": {
"email": "thandi.mokoena@agilex.co.za",
"password": "AgileX2024!",
"inviteId": "INVITE_ID_HERE"
}}'
Staff Directory
| Name | Role | Department | Access | |
|---|---|---|---|---|
| Craig Sobey | admin@agilex.co.za | Platform Admin | — | Owner |
| Thandi Mokoena | thandi.mokoena@agilex.co.za | Managing Director | Leadership | Owner |
| Pieter van der Merwe | pieter.vandermerwe@agilex.co.za | Head of Recruitment | Leadership | Maintainer |
| Naledi Khumalo | naledi.khumalo@agilex.co.za | Senior Recruitment Mgr | Leadership | Maintainer |
| Siyanda Dlamini | siyanda.dlamini@agilex.co.za | Banking Specialist | Consultants | User |
| James Reynolds | james.reynolds@agilex.co.za | Tech & AI Specialist | Consultants | User |
| Fatima Patel | fatima.patel@agilex.co.za | Graduate Programme Lead | Consultants | User |
| Bongani Ndlovu | bongani.ndlovu@agilex.co.za | Retail Specialist | Consultants | User |
| Sarah O'Connor | sarah.oconnor@agilex.co.za | PM Specialist | Consultants | User |
| Mpho Sithole | mpho.sithole@agilex.co.za | Research & Sourcing | Support | User |
| Lerato Mahlangu | lerato.mahlangu@agilex.co.za | Admin & Coordination | Support | User |
All staff passwords: AgileX2024!
6 Seed Recruitment Data
Data is seeded directly into CockroachDB using a Node.js script that generates SQL matching Huly's document schema (JSONB data column with class mixins).
Generate & Execute
# Generate SQL from seed script
node seed-recruitment.mjs > seed-data.sql
# Execute against CockroachDB
docker compose exec -T cockroach ./cockroach sql \
--url="$DB_URL" < seed-data.sql
# Restart transactor to pick up new data
docker compose restart transactor
Client Organisations (10)
| Client | Industry | City | HQ |
|---|---|---|---|
| Standard Bank Group | Banking | Johannesburg | Simmonds Street, JHB CBD |
| FirstRand Limited | Banking | Johannesburg | Sandton |
| Absa Group | Banking | Johannesburg | 15 Alice Lane, Sandton |
| Nedbank Group | Banking | Johannesburg | 135 Rivonia Road, Sandton |
| Capitec Bank | Banking | Stellenbosch | 5 Quantum Street, Technopark |
| Shoprite Holdings | Retail | Cape Town | Brackenfell |
| Woolworths Holdings | Retail | Cape Town | 93 Longmarket Street |
| Pick n Pay Stores | Retail | Cape Town | 101 Roeland Street |
| The Foschini Group (TFG) | Retail | Cape Town | Stanley Lewis Centre, Parow |
| Mr Price Group | Retail | Durban | 65 Masabalala Yengwa Ave |
Vacancies (15)
| # | Title | Client | Type | Salary Range |
|---|---|---|---|---|
| 1 | Senior AI/ML Engineer | Standard Bank | Permanent | R1.2M – R1.6M |
| 2 | Data Scientist – Risk Analytics | Standard Bank | Permanent | R950K – R1.3M |
| 3 | DevOps Engineer | FirstRand | Contract 12mo | R850 – R1,100/hr |
| 4 | Head of Digital Banking | Absa | Permanent | R2.5M – R3.2M |
| 5 | Cybersecurity Analyst | Nedbank | Permanent | R750K – R1.0M |
| 6 | Graduate Programme – Banking Ops | Capitec | Graduate 24mo | R320K – R380K |
| 7 | Supply Chain Director | Shoprite | Permanent | R2.0M – R2.8M |
| 8 | E-Commerce Product Manager | Woolworths | Permanent | R900K – R1.2M |
| 9 | IT Project Manager (SAP S/4HANA) | Pick n Pay | Contract 18mo | R950 – R1,200/hr |
| 10 | Senior BA – Retail Banking | FirstRand | Permanent | R800K – R1.1M |
| 11 | Cloud Architect | Absa | Permanent | R1.4M – R1.9M |
| 12 | Store Operations Manager | TFG | Permanent | R650K – R850K |
| 13 | Talent Acquisition Partner | Mr Price | Permanent | R600K – R800K |
| 14 | Graduate Programme – Data & Analytics | Shoprite | Graduate 18mo | R300K – R350K |
| 15 | Scrum Master – Digital Transformation | Nedbank | Contract 6mo | R750 – R950/hr |
Candidates (30)
| Name | Title | City | Vacancy | Stage |
|---|---|---|---|---|
| Nomvula Zulu | ML Engineer | Johannesburg | Senior AI/ML Engineer | Hired |
| Hendrik Botha | Supply Chain Manager | Cape Town | Supply Chain Director | Hired |
| Ayanda Mthembu | Business Analyst | Durban | Senior BA – Retail Banking | Hired |
| Priya Naidoo | Cybersecurity Analyst | Johannesburg | Cybersecurity Analyst | Hired |
| David Pretorius | Graduate – Banking Ops | Stellenbosch | Graduate Programme | Hired |
| Zanele Nkosi | Cloud Architect | Johannesburg | Cloud Architect | Offer |
| Mohammed Essop | E-Commerce PM | Cape Town | E-Commerce Product Mgr | Offer |
| Lindiwe Maseko | Scrum Master | Johannesburg | Scrum Master | Offer |
| Tshepo Molefe | DevOps Engineer | Pretoria | DevOps Engineer | Ref Check |
| Samantha Williams | Data Scientist | Johannesburg | Data Scientist – Risk | Ref Check |
| Kabelo Motaung | IT Project Manager | Johannesburg | IT PM (SAP S/4HANA) | Ref Check |
| Nkululeko Hadebe | AI Engineer | Durban | Senior AI/ML Engineer | Tech Assessment |
| Annika van Wyk | Cloud Solutions Architect | Cape Town | Cloud Architect | Tech Assessment |
| Sipho Mabaso | Senior BA – Payments | Johannesburg | Senior BA – Retail Banking | Tech Assessment |
| Chantal de Villiers | Digital Banking Strategist | Stellenbosch | Head of Digital Banking | Tech Assessment |
| Thabo Langa | DevOps Engineer | Johannesburg | DevOps Engineer | Interview |
| Precious Moyo | Talent Acquisition Partner | Pretoria | Talent Acquisition Partner | Interview |
| Ruan Erasmus | Store Ops Manager | Johannesburg | Store Operations Manager | Interview |
| Nosipho Dube | Graduate – Data Analytics | Durban | Graduate – Data & Analytics | Interview |
| Michael Smith | Product Manager | Cape Town | E-Commerce Product Mgr | Interview |
| Busisiwe Ngcobo | Risk Analyst | Johannesburg | Data Scientist – Risk | Screening |
| Jean-Pierre du Plessis | SAP Consultant | Cape Town | IT PM (SAP S/4HANA) | Screening |
| Amahle Cele | Graduate – Banking | Durban | Graduate Programme | Screening |
| Stefan Joubert | Scrum Master | Johannesburg | Scrum Master | Screening |
| Mandisa Sibiya | ML/AI Researcher | Johannesburg | Senior AI/ML Engineer | Sourced |
| Willem Swart | Security Engineer | Pretoria | Cybersecurity Analyst | Sourced |
| Thandeka Mkhize | Head of Digital | Johannesburg | Head of Digital Banking | Sourced |
| Grant Thompson | DevOps Engineer | Cape Town | DevOps Engineer | Rejected |
| Nomfundo Zwane | BA – Payments | Johannesburg | Senior BA | Rejected |
| Andre Fourie | Supply Chain Analyst | Stellenbosch | Supply Chain Director | Withdrawn |
7 Data Summary
Candidate Pipeline Distribution
| Stage | Count | Description |
|---|---|---|
| Sourced | 3 | Identified, not yet contacted |
| Screening | 4 | CV review and initial phone screen |
| Interview | 5 | First or second interview with client |
| Tech Assessment | 4 | Technical test or case study |
| Ref Check | 3 | Reference verification in progress |
| Offer | 3 | Offer extended, awaiting acceptance |
| Hired | 5 | Offer accepted, placement confirmed |
| Rejected | 2 | Did not proceed |
| Withdrawn | 1 | Candidate withdrew |
8 Login Reference
Email: admin@agilex.co.za
Password: AgileX2024!
Email: firstname.lastname@agilex.co.za
Password: AgileX2024!
Recruit — vacancies, candidate applications, pipeline board
HR — departments, staff records, org structure
Contacts — client organisations, all persons
Tracker — task management for recruitment workflow
9 Next Steps
Configure Resend for Email
Add a mail service to compose.yml with Resend SMTP credentials. Resend provides a free tier with 100 emails/day. Use smtp.resend.com:587 as SMTP host with your Resend API key as password.
Set Up Cloudflare Tunnel
Install cloudflared, create a tunnel, and route DNS for recruit.agilex.co.za. Zero inbound ports exposed, SSL termination at Cloudflare edge. See huly/cloudflare-tunnel.md.
Deploy to Hetzner VPS
Provision a CPX31 (4 vCPU, 8 GB RAM, ~R280/mo) in Falkenstein. Mirror the local Docker setup. See huly/hetzner-setup.md.
Replace OpenAI with Claude API
Swap the OPENAI_API_KEY in the aibot service for a Claude API integration via 2nth.ai agents, providing AI-powered candidate screening and communication.
Disable Public Signup
Set DISABLE_SIGNUP=true on both front and account services. New users join only via invite links.
POPIA Compliance
Add privacy notice and data processing agreement. All data stays on your infrastructure (Hetzner EU). Configure data retention policies for candidate records.