diff --git a/argocd/manifests/jobsync/deployment.yaml b/argocd/manifests/jobsync/deployment.yaml index 833a9b8..be19a81 100644 --- a/argocd/manifests/jobsync/deployment.yaml +++ b/argocd/manifests/jobsync/deployment.yaml @@ -45,6 +45,11 @@ spec: secretKeyRef: name: jobsync-secrets key: encryption_key + - name: RAPIDAPI_KEY + valueFrom: + secretKeyRef: + name: jobsync-secrets + key: rapidapi_key volumeMounts: - name: data mountPath: /data diff --git a/argocd/manifests/jobsync/external-secret.yaml b/argocd/manifests/jobsync/external-secret.yaml index e4ef3a2..39d58dc 100644 --- a/argocd/manifests/jobsync/external-secret.yaml +++ b/argocd/manifests/jobsync/external-secret.yaml @@ -21,3 +21,7 @@ spec: remoteRef: key: JobSync property: encryption_key + - secretKey: rapidapi_key + remoteRef: + key: JobSync + property: rapidapi_key diff --git a/docs/changelog.d/feature-jobsync-docs-and-rapidapi.doc.md b/docs/changelog.d/feature-jobsync-docs-and-rapidapi.doc.md new file mode 100644 index 0000000..6da4b27 --- /dev/null +++ b/docs/changelog.d/feature-jobsync-docs-and-rapidapi.doc.md @@ -0,0 +1 @@ +Add JobSync reference card, update ringtail workloads table, document observability via Loki, and wire RAPIDAPI_KEY through ExternalSecret for job search automation. diff --git a/docs/how-to/jobsync/deploy-jobsync.md b/docs/how-to/jobsync/deploy-jobsync.md index 6b72ad7..0683a4b 100644 --- a/docs/how-to/jobsync/deploy-jobsync.md +++ b/docs/how-to/jobsync/deploy-jobsync.md @@ -39,6 +39,7 @@ All in `argocd/manifests/jobsync/`: | `AUTH_TRUST_HOST` | Hardcoded | `true` | | `TZ` | Hardcoded | `America/Los_Angeles` | | `OLLAMA_BASE_URL` | Hardcoded | `http://ollama.ollama.svc.cluster.local:11434` | +| `RAPIDAPI_KEY` | ExternalSecret | JSearch job search API key | ## Updating the Container @@ -50,11 +51,22 @@ See [[build-jobsync-container]] for nix build details. ## Notes -- **1Password item:** "JobSync" in blumeops vault, fields `auth_secret` and `encryption_key` +- **1Password item:** "JobSync" in blumeops vault, fields `auth_secret`, `encryption_key`, and `rapidapi_key` - **Caddy route:** `jobsync.ops.eblu.me` → `https://jobsync.tail8d86e.ts.net` (in `ansible/roles/caddy/defaults/main.yml`) - **`service-versions.yaml`:** Must have a `jobsync` entry or the pre-commit hook rejects container changes +## Observability + +JobSync has no metrics endpoint. Logs are collected by Alloy on ringtail and shipped to Loki. Query in Grafana: + +```logql +{namespace="jobsync", app="jobsync"} +``` + +The app runs a scheduled job search daily at 4 AM. Search failures appear in logs during those executions. + ## Related +- [[jobsync]] — Service reference card - [[build-jobsync-container]] - [[deploy-k8s-service]] diff --git a/docs/reference/infrastructure/ringtail.md b/docs/reference/infrastructure/ringtail.md index ef77702..d8e2a05 100644 --- a/docs/reference/infrastructure/ringtail.md +++ b/docs/reference/infrastructure/ringtail.md @@ -70,6 +70,8 @@ Sync order: `1password-connect-ringtail` -> `external-secrets-crds-ringtail` -> | Mosquitto | `mqtt` | MQTT broker for Frigate events | | [[authentik]] | `authentik` | OIDC identity provider | | [[ntfy]] | `ntfy` | Push notification server | +| [[ollama]] | `ollama` | LLM inference with GPU (RTX 4080) | +| [[jobsync]] | `jobsync` | Job application tracker | | nvidia-device-plugin | `nvidia-device-plugin` | Exposes GPU to pods via CDI + nvidia RuntimeClass | ### Manual Cluster Registration diff --git a/docs/reference/reference.md b/docs/reference/reference.md index e9baa20..40cec80 100644 --- a/docs/reference/reference.md +++ b/docs/reference/reference.md @@ -25,6 +25,7 @@ Individual service reference cards with URLs and configuration details. | [[grafana]] | Dashboards & visualization | k8s | | [[immich]] | Photo management | k8s | | [[jellyfin]] | Media server | indri | +| [[jobsync]] | Job application tracker | k8s (ringtail) | | [[kiwix]] | Offline Wikipedia & ZIM archives | k8s | | [[loki]] | Log aggregation | k8s | | [[tempo]] | Distributed tracing | k8s | diff --git a/docs/reference/services/jobsync.md b/docs/reference/services/jobsync.md new file mode 100644 index 0000000..0a28de4 --- /dev/null +++ b/docs/reference/services/jobsync.md @@ -0,0 +1,104 @@ +--- +title: JobSync +modified: 2026-03-08 +tags: + - service + - job-search +--- + +# JobSync + +Self-hosted job application tracker. Tracks job applications, automates job searching via the JSearch API, and provides AI-powered resume tailoring via [[ollama|Ollama]]. + +## Quick Reference + +| Property | Value | +|----------|-------| +| **URL** | https://jobsync.ops.eblu.me | +| **Tailscale URL** | https://jobsync.tail8d86e.ts.net | +| **Namespace** | `jobsync` | +| **Cluster** | ringtail k3s | +| **Image** | `blumeops/jobsync` (Nix-built) | +| **Upstream** | https://github.com/Gsync/jobsync | +| **Manifests** | `argocd/manifests/jobsync/` | +| **Port** | 3000 | + +## Architecture + +``` +Browser ──HTTPS──► Caddy (jobsync.ops.eblu.me) + │ + ▼ + Tailscale ProxyGroup + │ + ▼ + JobSync (Next.js) + ┌───────┴───────┐ + │ │ + SQLite (/data) Ollama (in-cluster) + │ │ + PVC 5Gi GPU-accelerated LLM +``` + +- **Framework:** Next.js 15 + Prisma ORM +- **Database:** SQLite on a 5Gi PVC at `/data` +- **Auth:** Local email/password accounts (NextAuth v5), no SSO +- **AI:** Ollama at `http://ollama.ollama.svc.cluster.local:11434` for resume tailoring +- **Job Search:** JSearch API via RapidAPI (requires `RAPIDAPI_KEY`) + +## Job Search (JSearch / RapidAPI) + +The automated job search feature uses the [JSearch API](https://rapidapi.com/letscrape-6bRBa3QguO5/api/jsearch) on RapidAPI. The API key can be configured two ways (checked in order): + +1. **Per-user:** Added via Settings > API Keys in the web UI (encrypted with `ENCRYPTION_KEY`) +2. **Environment variable:** `RAPIDAPI_KEY` env var as a fallback for all users + +Without either, job search automations fail with: `Search failed: network - RAPIDAPI_KEY is not configured` + +The free tier allows 200 requests/month. The key is stored in 1Password ("JobSync" item, `rapidapi_key` field) and synced via ExternalSecret. + +## Secrets + +All secrets are in the **JobSync** 1Password item (blumeops vault), synced by ExternalSecret: + +| Secret | 1Password Field | Purpose | +|--------|-----------------|---------| +| `auth_secret` | `auth_secret` | NextAuth session signing | +| `encryption_key` | `encryption_key` | AES-256-GCM for stored API keys | +| `rapidapi_key` | `rapidapi_key` | JSearch job search API | + +## Observability + +JobSync has no metrics endpoint or Grafana dashboard. Logs are collected by [[alloy|Alloy]] on ringtail and shipped to Loki on indri. + +**Querying logs in Grafana:** + +```logql +{namespace="jobsync", app="jobsync"} +``` + +To search for job search errors specifically: + +```logql +{namespace="jobsync", app="jobsync"} |~ "(?i)(rapid|search failed|error)" +``` + +The app runs a scheduled job search daily at 4 AM. Failures appear in logs during those executions. + +## Container + +Built with Nix on ringtail (x86_64). See [[build-jobsync-container]] for details. + +```fish +mise run container-release jobsync +``` + +Update `newTag` in `argocd/manifests/jobsync/kustomization.yaml` after building, then `argocd app sync jobsync`. + +## Related + +- [[ollama]] — AI backend for resume tailoring +- [[ringtail]] — Host node +- [[deploy-jobsync]] — Deployment how-to +- [[build-jobsync-container]] — Container build guide +- [[apps]] — ArgoCD application registry