GC Jobs
← Home
Two services on PCT 107 (debian, 192.168.2.81) for Government of Canada job hunting.
gcjobs-qa (stack: gcjobs-qa)
Streamlit STAR interview prep assistant at gcjobs.carr-family.org (Authentik protected).
- Port: 8501 (host-mode on 192.168.2.81)
- Image:
gcjobs-qa:latest— built locally on PCT 107 - Data volume:
gcjobs-qa_gcjobs_data→/app/data/(resume.json, star_answers.csv, etc.) - Env:
OPENAI_API_KEYin compose
gcjobs-filler (stack: gcjobs-filler)
Selenium bot that pre-fills GC Jobs (PSC) applications section-by-section and emails a summary for manual review before submitting.
- URL:
gcjobs-filler.carr-family.org(no Authentik — static route inroutes.yml) - Port: 8000 (FastAPI, host-mode on 192.168.2.81)
- Image:
gcjobs-filler:latest— built locally on PCT 107 from/tank/appdata/gcjobs-filler/app/ - Compose:
/tank/appdata/gcjobs-filler/docker-compose.yml—traefik.enable=false, routing viaroutes.yml - Data:
/tank/appdata/gcjobs-filler/data/on ZFS — mounted into PCT 107 viamp3, then Docker bind-mounts to/app/data - STAR data: gcjobs-qa answer library mounted read-only at
/app/star_datafromgcjobs-qa_gcjobs_datavolume on PCT 107 - Permissions: data dir
chmod 777, files666, screenshots dir777(ZFS owned root:root, container writes as unprivileged user) - Notifications: email via Proton Bridge SMTP when pre-fill completes
Bot Flow
Navigate to page1710?careerChoiceId=<id>&psrsMode=11 → PSC login (UserNumber/Password) → OTP from Proton Bridge IMAP (Folders/GC Jobs) → optional page1570 (Notice page — bot clicks Continue) → optional page1960 (Confirmation/consent — bot checks checkbox then clicks Continue) → /applicant/<appid>/page1600 → fill 8 sections → stop before Submit → email notification.
8 sections filled: Employee info, Résumé, Screening Questions, Work locations, Classification, Education, Languages, Employment Equity.
On unexpected pages: bot saves a screenshot to /app/data/screenshots/ for debugging.
Supported Job URL Formats
| Format | Example |
|---|---|
| Standard posting | page1800?poster=2424673 |
| Direct apply link | page1710?careerChoiceId=2424673 |
| Newer PSC format | /applicant/1156524/page1820?careerChoice=2424673 |
Career ID is extracted automatically from any of these formats.
Config Files
| File | Purpose |
|---|---|
/tank/appdata/gcjobs-filler/data/config.yml |
GCKey creds ([email protected]), IMAP config, email, monitor settings |
/tank/appdata/gcjobs-filler/data/profile.yml |
Employment info, language prefs, screening Q answers + narratives |
Key profile.yml Settings
employment.classification— must match visible text in the PSC dropdown (e.g."EC-05")screening_questions— map question-text substrings to'yes'/'no'; bot fuzzy-matches (≥85%) dynamically per jobscreening_narratives— free-text responses for Yes answers; same substring keys
Screening Question Resolution Pipeline (app/ai_helper.py)
- Fuzzy match (≥85% via
rapidfuzz) againstprofile.ymlscreening_questions→ use profiled answer - If answer is
yesand no narrative inscreening_narratives, fuzzy-match question against STAR CSV → AI adapts that answer as narrative - No profile match → fuzzy-match (≥70%) against STAR CSV → answer
yes+ AI-adapt STAR narrative - No STAR match → ask OpenAI (
gpt-4o-mini) yes/no from resume.json → if yes, generate narrative viagpt-4o
"Section link not found for screeningQuestions" — normal; the bot skips jobs with no screening questions.
Web UI Tabs
| Tab | Purpose |
|---|---|
| Apply | Submit a job URL |
| Monitor | Watch the bot's progress |
| Jobs | Browse scraped job listings |
| History | Past applications |
| Profile | Employment, languages, education, EE consent, screening Qs + narratives |
| STAR Answers | Searchable answer library (from gcjobs-qa) |
| Settings | GCKey creds, IMAP, SMTP, monitor config |
Settings password gotcha — browsers block pre-filling type="password" fields, so opening Settings shows blank boxes. The backend preserves existing passwords when an empty string is submitted — safe to save without touching password fields.
Monitor Filters (Settings tab)
keywords— title/classification substringsclassifications— e.g.EC-05language_requirements— e.g.bilingual,english essential; blank = all
Jobs table shows extracted language requirement per posting (colour-coded: purple = bilingual, blue = English essential).
Rebuild & Redeploy
# Build (context is parent dir — Dockerfile does COPY app/ .) tar -cf - -C /tank/appdata/gcjobs-filler --exclude='./data' . | \ pct exec 107 -- bash -c 'rm -rf /tmp/gcjobs-build && mkdir -p /tmp/gcjobs-build && tar -xf - -C /tmp/gcjobs-build' pct exec 107 -- docker build -t gcjobs-filler:latest /tmp/gcjobs-build/ # Image-only change (no compose changes): pct exec 108 -- docker service update --force gcjobs-filler_gcjobs-filler # Compose changes (volumes, ports, etc.) — must pipe file in; PCT 108 can't read /tank/appdata/gcjobs-filler/ directly: cat /tank/appdata/gcjobs-filler/docker-compose.yml | \ pct exec 108 -- bash -c 'cat > /tmp/gcjobs-filler-compose.yml' pct exec 108 -- docker stack deploy -c /tmp/gcjobs-filler-compose.yml gcjobs-filler
Deploy gotcha: PCT 108 cannot access /tank/appdata/gcjobs-filler/ (not in its LXC mounts). Always pipe the compose file in via stdin. cp /tank/... /tmp/... on the Proxmox host writes to the host's /tmp/, not PCT 108's.
Known Issue
Client.__init__() got an unexpected keyword argument 'proxies' — AI narrative generation is broken in gcjobs-filler. Leaving screening question narratives unfilled. Cause: OpenAI client version incompatibility.
