JobFinder KE is a premium job platform that provides 48-hour early access to job openings from government-registered startups and live government tenders in Kenya. Subscribers receive opportunities before they're released to the public, giving them a significant competitive advantage in the job market.
- ** 48-Hour Early Access** β Get jobs before public release
- ** Government Verified** β All employers verified through Business Registration Service (BRS)
- ** Live Tender Alerts** β Real-time government procurement notifications
- ** Multi-Channel Notifications** β Email, SMS, and WhatsApp alerts
- ** M-Pesa Integration** β Seamless subscription payments
- ** Automated Web Scraping** β Continuous job sourcing from bebee.com
- ** Admin Dashboard** β Manual import controls and monitoring
JobFinder KE
βββ Django 6.0.3 Backend
βββ PostgreSQL Database
βββ Celery + Redis (Background Tasks)
βββ Django REST Framework (API endpoints)
βββ BeautifulSoup / Requests (Job scraping)
βββ Allauth (Social authentication)
βββ Custom CSS (jfke- scoped styling)
- Python 3.12+
- PostgreSQL 16+
- Redis (for Celery)
- Virtual environment (recommended)
git clone https://github.com/yourusername/jobfinder-ke.git
cd jobfinder-kepython3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activatepip install -r requirements.txtCreate a .env file in the project root:
# Database
DB_NAME=jobs
DB_USER=your_username
DB_PASSWORD=your_password
DB_HOST=localhost
DB_PORT=5432
# Google OAuth
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
# Email
EMAIL_HOST_USER=noreply@jobfinder.ke
EMAIL_HOST_PASSWORD=your_email_password
# MβPesa
MPESA_CONSUMER_KEY=your_consumer_key
MPESA_CONSUMER_SECRET=your_consumer_secret
MPESA_SHORTCODE=888888
# Security
DJANGO_SECRET_KEY=your_secret_key
DEBUG=Truesudo -u postgres psql
CREATE DATABASE jobs;
CREATE USER your_username WITH PASSWORD 'your_password';
ALTER ROLE your_username SET client_encoding TO 'utf8';
ALTER ROLE your_username SET default_transaction_isolation TO 'read committed';
ALTER ROLE your_username SET timezone TO 'Africa/Nairobi';
GRANT ALL PRIVILEGES ON DATABASE jobs TO your_username;
\q
python manage.py makemigrations
python manage.py migratepython manage.py createsuperuserpython manage.py collectstaticpython manage.py runserverVisit http://127.0.0.1:8000
Access: http://127.0.0.1:8000/admin/ then use the custom admin actions.
# Import jobs from bebee.com (30 pages = ~600 jobs)
python manage.py import_bebee_jobs --pages 30
# Dry run (preview without saving)
python manage.py import_bebee_jobs --pages 5 --dry-runAdd to crontab:
0 2 * * * cd /path/to/jobfinder-ke && python manage.py import_bebee_jobs --pages 30 >> /var/log/job_import.log 2>&1jobfinder-ke/
βββ job_orm/ # Project configuration
β βββ settings.py
β βββ urls.py
β βββ celery.py
βββ jobs/ # Main application
β βββ models.py
β βββ views.py
β βββ urls.py
β βββ admin.py
β βββ bebee_scraper.py
β βββ management/
β β βββ commands/
β β βββ import_bebee_jobs.py
β βββ templates/jobs/
βββ templates/ # Global templates
β βββ base.html
β βββ index.html
β βββ pricing.html
β βββ subscribe.html
βββ static/ # Static files (CSS, JS, images)
βββ media/ # User uploaded files
βββ requirements.txt
User (Custom)
βββ role (job_seeker/employer/admin)
βββ phone_number (unique)
βββ is_subscribed
βββ subscription_end_date
EmployerProfile
βββ company_name
βββ business_registration_number (unique)
βββ kra_pin
βββ sector
βββ is_verified (government verified)
βββ jobs (ForeignKey)
JobPosting
βββ title, description, requirements
βββ location, salary_range
βββ application_deadline
βββ is_pre_public (48βhour early access)
βββ public_at
βββ status (draft/published/closed)
GovernmentTender
βββ tender_number (unique)
βββ title, description
βββ ministry, value_estimate
βββ deadline, published_at
βββ is_active
UserSubscription
βββ user, amount_paid
βββ mpesa_transaction_id (unique)
βββ start_date, end_date
βββ is_active
JobApplication
βββ job, applicant
βββ cover_letter, cv_file
βββ status
βββ is_priority| Source | Type | Frequency | Method |
|---|---|---|---|
| bebee.com | Jobs | Every 6 hours | API (REST) |
| BRS Kenya | Startups | Daily | Web scraping (planned) |
| KEPSA | Member Jobs | Weekly | Web scraping (planned) |
- Responsive design (mobile, tablet, desktop)
- Live job feed with slideβin animations
- Animated stats counters (from live API)
- Early access badges
- MβPesa payment flow
- Scoped CSS (
jfke-prefix) β no conflicts with other pages
- Google OAuth2 (social login)
- Phone number verification
- Roleβbased access (job seeker / employer / admin)
- CSRF protection
- SQL injection prevention (Django ORM)
- XSS protection (autoβescaping)
Pricing Plans:
- Monthly: KES 500 / month
- Annual: KES 5,000 / year (17% savings)
Payment Methods:
- MβPesa (PayBill number: 888888)
- Card payments (coming soon)
Features:
- 7βday free trial
- Cancel anytime
- Automatic billing
- Transaction history
| Endpoint | Method | Description |
|---|---|---|
/api/stats/ |
GET | Live stats (jobs, tenders, subscribers) |
/api/jobs/ |
GET | Job listings with filters |
/api/tenders/ |
GET | Tender listings |
/api/subscribe/ |
POST | Subscription activation |
# Run all tests
python manage.py test
# Run jobs app tests
python manage.py test jobs
# With coverage
coverage run manage.py test
coverage report
coverage html- Database indexes on foreign keys and frequently filtered fields
select_related()andprefetch_related()for related objects- Redis caching for session storage and API responses
- Pagination (20 items per page)
- Lazy loading of images
- CDN for fonts and static assets
No jobs on /jobs/
python manage.py shell -c "from jobs.models import JobPosting; from django.utils import timezone; print(JobPosting.objects.filter(status='published', application_deadline__gt=timezone.now()).count())"
python manage.py import_bebee_jobs --pages 5Cron jobs not running
sudo systemctl status cron
tail -f /var/log/syslog | grep CRONSector filter shows no results
Run the sector updater script (provided in the codebase) to assign sectors from job titles.
sudo apt update
sudo apt install nginx postgresql redis-server supervisor
pip install gunicorn
gunicorn --bind 0.0.0.0:8000 job_orm.wsgi:application
sudo nano /etc/nginx/sites-available/jobfinderNginx config:
server {
listen 80;
server_name jobfinder.ke;
location /static/ {
alias /path/to/static/;
}
location /media/ {
alias /path/to/media/;
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}sudo ln -s /etc/nginx/sites-available/jobfinder /etc/nginx/sites-enabled/
sudo systemctl restart nginx| Variable | Required | Default | Description |
|---|---|---|---|
DB_NAME |
Yes | β | PostgreSQL database name |
DB_USER |
Yes | β | Database username |
DB_PASSWORD |
Yes | β | Database password |
GOOGLE_CLIENT_ID |
Yes | β | Google OAuth client ID |
GOOGLE_CLIENT_SECRET |
Yes | β | Google OAuth secret |
MPESA_CONSUMER_KEY |
For payments | β | MβPesa API key |
MPESA_CONSUMER_SECRET |
For payments | β | MβPesa API secret |
EMAIL_HOST_USER |
For digests | β | SMTP username |
EMAIL_HOST_PASSWORD |
For digests | β | SMTP password |
DJANGO_SECRET_KEY |
Yes | β | Django secret key |
DEBUG |
No | False | Debug mode |
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Coding standards:
- PEP 8
- Black formatting
- Docstrings for functions
- Tests for new features
Distributed under the MIT License. See LICENSE for more information.
- Email: support@jobfinder.ke
- Phone: +254 742 164 615
- WhatsApp: +254 742 164 615
- Website: https://jobfinder.ke
- Business Registration Service (BRS) Kenya
- Kenya Private Sector Alliance (KEPSA)
- bebee for job listings
- All our subscribers and partners
Built with β€οΈ for Kenyan job seekers and businesses
"First Access. Zero Competition."