The verify endpoint is now public and doesn't require API key.
Instead it takes user_id and verification_code in the request body.
Changes:
- Removed X-API-Key header from verify request
- Added user_id to request body
- Endpoint returns API key after successful verification
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Problem: New users with email verification enabled receive api_key: null,
but script only checked for existing_user flag, not null API key.
Solution: Check if api_key is null first, then determine if it's:
- Existing unverified user (load key from config)
- New user with verification (api_key comes after verification)
- New user without verification (api_key provided immediately)
This fixes the 'Failed to extract API key' error for new registrations.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The API key is now generated during email verification, not registration.
Changes:
- Extract api_key from verification response
- Save the API key to config after successful verification
- Display confirmation message when API key is received
This works with the new security flow where API keys are only issued to verified users.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When a user tries to register with an email that already exists but is not verified:
- API now returns existing_user: true and api_key: null
- Script detects existing_user flag
- Loads existing API key from config file instead of expecting it in response
- Shows appropriate message about new verification code being sent
- Continues to verification step
This fixes the error 'Failed to extract user data' when users re-register.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace bash-specific &> with >/dev/null 2>&1
- Replace bash-specific == with POSIX-compliant = in [ ] tests
- Script now works with both sh and bash
- Fixes "unexpected operator" errors when run with sh
Issue: User ran script with 'sh' instead of 'bash', causing errors
Root cause: Bash-specific syntax (== and &>) not compatible with POSIX sh
Solution: Use POSIX-compliant alternatives that work in both shells
Changes:
1. Repository URL format: HTTPS → SSH
- Changed from: https://git.startanaicompany.com/user/repo.git
- Changed to: git@git.startanaicompany.com:user/repo.git
- Reason: Coolify requires SSH format for private repo deployments
2. API field name: git_token → gitea_api_token
- Changed from: "git_token": "${GITEA_API_TOKEN}"
- Changed to: "gitea_api_token": "${GITEA_API_TOKEN}"
- Reason: Match Coolify Wrapper API specification
These changes ensure the deployment script works with the Coolify
Wrapper API at apps.startanaicompany.com
The wrapper will now:
- Accept the SSH Git URL format
- Properly receive the Gitea API token
- Set up deploy keys and webhooks automatically
SAAC API now receives user's GITEA_API_TOKEN to enable Coolify to clone private repositories.
Changes:
- Added early validation of GITEA_API_TOKEN (before app creation)
- Pass git_token parameter to SAAC API in application creation request
- Removed duplicate GITEA_API_TOKEN check in webhook section
- Updated error message to explain both use cases (cloning + webhooks)
The SAAC API will use this token to configure Coolify with authenticated git access:
https://${GITEA_API_TOKEN}@git.startanaicompany.com/${user}/${repo}.git
This enables automatic deployments for private repositories.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Automatic deployments are essential for the template, so GITEA_API_TOKEN is now required.
Changes:
- .env.example: Marked both API keys as REQUIRED
- deploy-to-apps.example.sh: Script now exits with error if GITEA_API_TOKEN not set
- Added clear instructions on how to get Gitea API token
Without webhooks, users would need to manually trigger deployments after every push,
which defeats the purpose of automated infrastructure.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Users need GITEA_API_TOKEN for automatic webhook setup during deployment.
Marked as optional with clear instructions on where to get it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed SAAC API repository link (internal implementation detail)
- Changed DNS target from app.coolify.io to apps.startanaicompany.com
- Updated .env.example to only reference SAAC_API_KEY (not internal tokens)
- Simplified support section to only show template issues
Users should only interact with the SAAC API as a service, not see internal implementation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Users should see this as the "StartAnAiCompany platform" not as a Coolify proxy.
Changes:
- README.md: "StartAnAiCompany infrastructure" and "StartAnAiCompany platform"
- DEPLOYMENT_GUIDE.md: Removed all Coolify references
- deploy-to-apps.example.sh: "deployment platform" instead of "Coolify"
Now all user-facing documentation uses StartAnAiCompany/SAAC branding exclusively.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed deploy-to-coolify.example.sh (replaced by deploy-to-apps.example.sh)
- Removed COOLIFY_SETUP.md (replaced by DEPLOYMENT_GUIDE.md)
- Updated .gitignore to remove deploy-to-coolify.sh reference
- Updated README troubleshooting to use SAAC API instead of direct Coolify API
All users now deploy via the SAAC API at apps.startanaicompany.com rather than directly to Coolify.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed all references from "Coolify Wrapper" / "WRAPPER_API_KEY" to
"SAAC" / "SAAC_API_KEY" for better branding and user experience.
SAAC = StartAnAiCompany - makes it clear users are deploying to
StartAnAiCompany infrastructure rather than a "wrapper" service.
Changes:
- WRAPPER_API_KEY → SAAC_API_KEY throughout
- "Wrapper API" → "SAAC API" in all documentation
- Updated user-facing messages to reference StartAnAiCompany
This makes the service feel more direct and brand-focused rather
than like a proxy/wrapper layer.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This enables deployment via apps.startanaicompany.com instead of direct Coolify access.
New files:
- deploy-to-apps.example.sh: Deployment script using Wrapper API
- DEPLOYMENT_GUIDE.md: Comprehensive deployment documentation
Updated files:
- README.md: Updated deployment steps to use Wrapper API
- .gitignore: Added deploy-to-apps.sh to exclusions
Benefits:
- Users no longer need master Coolify token
- Each user gets their own API key
- Automatic resource isolation
- Rate limiting and audit logging
- Simpler deployment process
The old deploy-to-coolify.example.sh remains for reference but new
deployments should use the wrapper API.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed from double subdomain format (anna.recruitai.startanaicompany.com)
to single concatenated format (annarecruit.startanaicompany.com).
Changes:
- deploy-to-coolify.example.sh: Updated FULL_DOMAIN to ${SUBDOMAIN}recruit.startanaicompany.com
- .env.example: Updated comment to show correct example (annarecruit.startanaicompany.com)
- README.md: Updated domain examples to use correct format
- COOLIFY_SETUP.md: Updated all DNS and domain examples to use correct format
This ensures deployments generate domains like:
- annarecruit.startanaicompany.com (when SUBDOMAIN=anna)
- johnrecruit.startanaicompany.com (when SUBDOMAIN=john)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Created COOLIFY_SETUP.md with complete instructions for:
- One-time Coolify instance setup (API tokens, projects, UUIDs)
- Per-deployment setup for each recruitment site
- DNS configuration with Cloudflare
- Webhook configuration for automatic deployments
- Troubleshooting common issues
- Security best practices
- Scaling multiple sites
- Advanced configuration options
Updated README.md to reference the new setup guide.
This provides all the information users need to set up their own
Coolify instance and deploy multiple recruitment sites from the template.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removed files containing deployment-specific information:
- DEPLOYMENT_STATUS.md (contained UUIDs, IPs, specific deployment details)
- DEPLOYMENT_GUIDE.md (old deployment guide)
- .webhook-test (test file)
These files are not relevant for template users.
All configuration is now handled via .env.example and README.md.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Updated webhook to use correct Coolify API endpoint:
- Changed from /webhooks/source/gitea/events/manual/{uuid} to /api/v1/deploy?uuid={uuid}
- Added Bearer token authorization header to webhook
- Removed unnecessary webhook secret generation
- Uses GET request to /deploy endpoint as per Coolify API docs
This fix enables automatic deployments when pushing to repository.
Reference: https://coolify.io/docs/api-reference/api/operations/deploy-by-tag-or-uuid🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Created deploy-to-coolify.example.sh script that:
- Reads configuration from .env file
- Creates Coolify application via API
- Configures domain and Traefik labels
- Sets up GitHub webhook for automatic deployments
- Generates deployment secrets automatically
- Provides step-by-step deployment feedback
Updated .gitignore to exclude:
- deploy-to-coolify.sh (customized copy)
- deployment-info.txt (contains secrets)
Users copy the example script and customize for their deployment.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added init.js script and data attributes to all HTML files:
- All pages now load company configuration dynamically
- Added data-company-name attributes for company name elements
- Title tags will be updated by init.js at runtime
- Enables full customization without editing HTML files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive environment-based configuration system:
- Created config.js module to centralize all environment variables
- Updated server.js to use config module for all settings
- Added /api/config endpoint to expose company info to frontend
- Created init.js to dynamically inject config into HTML pages
- Updated .env.example with comprehensive configuration options
- Added data attributes to index.html for dynamic content
- Updated Dockerfile to include config.js
This allows users to customize:
- Company name, tagline, and description
- Branding colors (primary, accent, dark)
- Contact information (email, phone, address, hours)
- Social media links
- About page content
- Services offered
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Updated all navigation links in HTML files
- Updated all hrefs and window.location redirects in JavaScript
- All links now use clean URLs without .html extensions
- Improves SEO and provides cleaner user experience
- All migrations running successfully
- Database initialized with sample data
- Webhook configured with secret for auto-deployment
- Site fully functional at https://recruitai.startanaicompany.com
- Removed migrations volume mount from docker-compose.yml
- Added automatic migration runner in server.js on startup
- Migrations now run from files built into Docker image
- Fixes 'relation does not exist' errors
The volume mount was overwriting the public directory from the Docker
image with an empty directory from the host, causing ENOENT errors.
Public files are now served from the Docker image via COPY command.