This guide covers setting up the development environment, managing environment configurations, integrating PostgreSQL and Piston code execution engines via Docker, and securing our Docusaurus documentation site on Cloudflare.
Ensure you have the following installed on your host system:
The development stack runs inside Docker Compose, configuring hot-reloading for the backend, running background arq tasks, and providing a sandboxed Piston runtime environment.
You need both the main platform repository and the Piston code execution fork:
# Clone the main recruitment platform repository
git clone https://github.com/p99softadmin/Talent-Acquisition-Platform.git
cd Talent-Acquisition-Platform
# Clone the piston execution engine repo as a sibling directory
cd ..
git clone https://github.com/p99softadmin/piston.git
cd Talent-Acquisition-Platform
Copy the example environment configuration to create your local environment:
cp backend/.env.example backend/.env
docker-compose.dev.ymlThe dev docker-compose stack spins up the following services:
backend: FastAPI application exposed on http://localhost:8000. Runs migrations and bootstraps parsing assets on startup.worker: Shared arq worker (interviews, Slack, analytics, offers).worker-assessment: Dedicated arq worker for assessment jobs (AI generation, invites, SQL, grading, session video, PDF).redis: Cache and broker storage on http://localhost:6379.postgres: Local PostgreSQL 16 (enabled by default on port 5432).minio: Object storage for resumes/reports (ports 9000 / console 9001).proctoring-engine: Standalone Video Analysis Engine on http://localhost:8100 (Live Camera Monitoring). Backend talks to it via PROCTORING_ENGINE_URL. Detectors are on by default (STUB_DETECTORS=false, Docker PROCTORING_INSTALL_ML=full): MediaPipe face/gaze plus YOLO object detection (phone/earbuds/person). Sessions use Redis db/1. Alerting still frames are not stored by default (PROCTORING_EVIDENCE_ENABLED=false); recruiters review via session video + jump-to-offset. Set PROCTORING_INSTALL_ML=face and rebuild for a lighter MediaPipe-only image. After session.mp4 is ready, the assessment worker optionally re-samples the recording (PROCTORING_SESSION_REANALYSIS_ENABLED=true) so brief events missed live still appear in results/PDF.piston: Self-hosted sandbox engine running on port 2000 to execute code safely.piston_runtime_bootstrap: Installs language runtimes (Python, Node, Go, Rust, Java, etc.) inside the Piston container during first start.Local PostgreSQL 16 is enabled by default in docker-compose.dev.yml (postgres service, postgres_data volume, and backend/worker depends_on). To use an external database instead, comment out those Compose entries and point DATABASE_URL in backend/.env at your host.
Start all services in detached mode:
docker compose -f docker-compose.dev.yml up -d
Note: The first launch will bootstrap Piston and download runtimes (Node, Python, Go). This might take 3–5 minutes.
Verify runtimes are loaded successfully:
curl http://localhost:2000/api/v2/runtimes
If you prefer running components directly on your host machine (outside Docker) for debugging:
cd backend
# Create virtualenv
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Bootstrap resume parser NLP models and download stopwords
python scripts/bootstrap_resume_parser.py
python -m nltk.downloader stopwords
# Setup configuration
cp .env.example .env
# Edit .env and customize DATABASE_URL, JWT_SECRET_KEY, ANTHROPIC_API_KEY
# Run migrations
alembic upgrade head
# Start FastAPI dev server
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
API Documentation will be interactive at: http://localhost:8000/docs
cd frontend
# Install package dependencies
npm install
# Setup local environment configurations
cp .env.example .env.local
# Run developer server
npm run dev
Frontend application will be running at: http://localhost:5173
The platform reads settings from configuration files (.env).
.env.prodPROJECT_NAME, VERSION, API_V1_STR)PISTON_URL=http://piston:2000)MINIO_ENDPOINT=minio:9000)The platform natively supports both local MinIO (for offline/local dev) and AWS S3 (for staging/production).
docker-compose.dev.yml at localhost:9000.STORAGE_PROVIDER=s3 and AWS credentials (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_STORAGE_BUCKET_NAME, AWS_REGION).For local development, you must create a .env file containing secrets. Do NOT commit this file. Obtain the current development API keys and testing tokens from your teammates or configure them manually:
JWT_SECRET_KEY: Generate using openssl rand -hex 32FERNET_KEY: Symmetric encryption key generated via python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"ANTHROPIC_API_KEY: API key for accessing Claude AI models.SERPER_API_KEY: Search engine service key for sourcing candidate profiles.GITHUB_TOKEN: Read-only access token for querying GitHub search API.AWS_ACCESS_KEY_ID & AWS_SECRET_ACCESS_KEY: Credentials for AWS Bedrock services.Optional Live Camera Monitoring (defaults work for local Docker Compose):
PROCTORING_ENGINE_URL: Video Analysis Engine base URL (Compose default http://proctoring-engine:8100, local host default http://127.0.0.1:8100)PROCTORING_ENGINE_API_KEY: Shared secret sent as X-Proctoring-Engine-Key (must match engine ENGINE_API_KEY; must not stay as dev-proctoring-engine-key when ENV=production)PROCTORING_VIDEO_ANALYSIS_ENABLED: true/false toggle for candidate frame proxy endpointsPROCTORING_EVIDENCE_ENABLED: Optional still-frame archive to MinIO (proctoring-evidence/...). Default off — session video is the source of truth for recruiter reviewproctoring-sessions/{org}/{submission}/parts/; finalize byte-concatenates parts into session.webm via a temp file (and deletes temporary parts) for recruiter timeline review and PDF integrity links (Alembic d4a91c2e7b15 — run alembic upgrade head)PROCTORING_IDENTITY_ENABLED: enroll identity after 3 consistent single-face frames and flag identity_mismatch (SFace ONNX embeddings via OpenCV Zoo)PROCTORING_RETENTION_DAYS: daily worker purge of proctoring-evidence/ + proctoring-sessions/ older than N days (0 disables)PROCTORING_ENGINE_TIMEOUT_SECONDS: HTTP timeout to the engine (default 5)PROCTORING_ENGINE_CIRCUIT_FAILURE_THRESHOLD / PROCTORING_ENGINE_CIRCUIT_COOLDOWN_SECONDS: Fail-open circuit breaker when the engine is downREDIS_URL (Compose sets Redis db/1), STUB_DETECTORS / PROCTORING_STUB_DETECTORS (Compose default false), PROCTORING_INSTALL_ML (Compose default full = MediaPipe + YOLO phone/earbuds; set face for MediaPipe-only), ENV / PROCTORING_ENGINE_ENVOptional Safe Exam Browser lockdown (Desktop integrity mode / hardware_fingerprint):
SEB_ENFORCEMENT_ENABLED: when true, Desktop-mode assessments require a valid X-SafeExamBrowser-ConfigKeyHash on begin, identity enroll, accept, and in-progress candidate routes (default false for backward compatibility)SEB_CONFIG_PASSWORD: encrypts generated .seb configs (required in production when enforcement is on). Candidates receive a per-invitation unlock password in the download response (shown on the SEB wizard step) — do not share the base env secret with candidatesSEB_QUIT_PASSWORD_SECRET: optional HMAC material for per-invitation quit passwords (falls back to JWT_SECRET_KEY)POST /api/v1/candidate/invite/seb-config and open the file in SEBPUBLIC_API_BASE_URL and CANDIDATE_ASSESSMENT_BASE_URL include the correct scheme, host, and port (URL filters and Config Key are origin-bound); reverse proxies should set X-Forwarded-Proto / X-Forwarded-HostallowVideoCapture / allowAudioCapture in the generated .seb so getUserMedia works inside SEB.seb startURL embeds /take/{token} (no invite paste inside SEB). Exit is password-free: app submits first, then navigates to quitURL (?seb_quit=1) so SEB closes without a quit passwordSEB_CONFIG_PASSWORD is set it hashes into hashedAdminPassword only; file encryption still uses a per-invitation derived password shown on download. Leave empty for password-free .seb openX-TAP-SEB-Page-ConfigKeyHash + X-TAP-SEB-Page-URL from the SEB JS API when native request headers are missingalembic upgrade head (documents seb_quit violation type)We use Docusaurus to generate and maintain developer manuals, code explanations, and documentation files.
If you are initializing or running the Docusaurus documentation portal:
# Initialize a new Docusaurus project (if not already in the repository)
npx -y create-docusaurus@latest docs-site classic
# Start local server
cd docs-site
npm run start
The documentation portal is served locally at http://localhost:3000.
To host the Docusaurus site on Cloudflare Pages:
Docusaurus v2npm run buildbuildTo secure private engineering documentation so that only P99soft employees can view it:
dash.teams.cloudflare.com).Talent Acquisition Platform Documentation24 Hoursdocs.p99soft.com or tap-docs.pages.dev).Restrict to P99soft StaffAllowEmails ending inp99soft.com@p99soft.com email address; all other domains are securely denied access.To maintain a clean and automated collaborative environment, we enforce the Conventional Commits specification for all commit messages. This ensures that changes can be tracked, version tags can be automatically resolved, and CHANGELOGs can be built programmatically via semantic-release.
Commit messages must follow the format:
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
Where <type> must be one of:
feat: A new feature (corresponds to a minor version bump)fix: A bug fix (corresponds to a patch version bump)docs: Documentation only changesstyle: Changes that do not affect the meaning of the code (white-space, formatting, etc.)refactor: A code change that neither fixes a bug nor adds a featureperf: A code change that improves performancetest: Adding missing tests or correcting existing testschore: Changes to the build process or auxiliary tools and librariesExample of a valid commit message:
git commit -m "feat(auth): integrate google sso endpoints"
We use Husky combined with Commitlint to automatically run checks before any commit is processed:
git commit, Husky intercepts the action and executes @commitlint/cli.@commitlint/config-conventional.If you cloned the repository fresh, run:
# Installs hook packages and configures git hooks automatically (via the prepare script)
npm install
If you need to manually re-link or troubleshoot the Git hooks:
npx husky
Always keep the database schema in sync with your models during development:
# Run all pending migrations
alembic upgrade head
# Autogenerate a new migration file after modifying SQLAlchemy models
alembic revision --autogenerate -m "describe_your_changes"
# Rollback the last migration
alembic downgrade -1
# View migration chain history
alembic history
Verify PostgreSQL is healthy and accepting connections. If using Docker, inspect container health:
docker compose -f docker-compose.dev.yml logs postgres
Ensure your DATABASE_URL in .env matches the configuration of the database service.
If Piston API returns an empty list, the runtime bootstrap is likely still installing packages:
docker compose -f docker-compose.dev.yml logs -f piston_runtime_bootstrap
Check that no other system processes are running on port 2000.
Clear local storage in your browser console if authentication issues persist after database resets:
localStorage.clear();