Skip to content

Commit 9fdad2e

Browse files
LEANDERANTONYclaude
andcommitted
Docs + landing: refresh cadence is 4 hours, not 30 min
Production cron was bumped from `*/30 * * * *` (48× per day) to `0 */4 * * *` (6× per day) tonight — six refreshes is plenty for ATS data that doesn't churn that fast at the source, and it cuts upstream load 8× across the four providers. Synced every user-facing claim to the new reality: README.md - Capability table: "refreshed every 30 minutes" → "every 4 hours" - Job-discovery bullet: "30-minute refresh cadence" expanded into the 6-tick UTC schedule (00:00 / 04:00 / 08:00 / 12:00 / 16:00 / 20:00) so anyone reading can predict when the cache moves. frontend/src/components/landing-page.tsx - Step 02 body: "refreshed every 30 minutes" → "refreshed several times a day" - Bento tile body: same Kept the marketing copy soft ("several times a day") rather than the precise "every 4 hours" — the latter reads like an ops-bound constraint to a job seeker. docs/architecture.md - Persistence-model bullet: "every ~30 min" → "every 4 hours (six times a day)" - cached_jobs RPC paragraph: documents the actual jobname `cached_jobs_refresh_4h` and the production cron expression `0 */4 * * *`. docs/images/job-agent-architecture.svg - Cached Job Index card third line: "30-min refresh" → "4-hour refresh" backend/routers/jobs.py - search_jobs docstring: "every 30 min" → "every 4 hours" - refresh_cache docstring: "every 30 min" → "every 4 hours (six times a day on the `0 */4 * * *` schedule)" Intentionally LEFT AS-IS: - DEVLOG.md (Days 39-40) — historical day log; on those days 30 min was the cadence, the log is a record of that moment. - docs/adr/ADR-013-cached-jobs-... — the ADR's "Decision" section captures what we chose at the time. The bump to 4 h is a subsequent operational tune, not a reversal of that decision. ADRs stay frozen by convention. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 0eb338f commit 9fdad2e

5 files changed

Lines changed: 11 additions & 10 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
| System | What it does |
3232
|--------|--------------|
33-
| **Live job search** | Cached index of ~12,000 open roles from Greenhouse, Lever, Ashby, and Workday — refreshed every 30 minutes. Filter by company, work mode, role type, posted-within. Sort by relevance, recency, or alphabetical. |
33+
| **Live job search** | Cached index of ~12,000 open roles from Greenhouse, Lever, Ashby, and Workday — refreshed every 4 hours. Filter by company, work mode, role type, posted-within. Sort by relevance, recency, or alphabetical. |
3434
| **Resume intake** | Upload PDF / DOCX / TXT, or chat one into existence with the conversational builder. Parsed into a normalized profile with skills, experience timeline, projects, publications, and certifications. |
3535
| **JD review** | LLM-first JD parser with regex fallback. Surfaces hard skills, soft skills, and must-haves; shows match score against the loaded resume. |
3636
| **Supervised pipeline** | Matchmaker → Forge (tailoring) → Gatekeeper (review) → Resume Generation → Cover Letter. Three-layer LLM retry stack with per-agent fallback isolation, deterministic floor on every stage. |
@@ -45,7 +45,7 @@
4545
The cached jobs layer lives in Postgres (`cached_jobs` table) and is refreshed by a scheduled worker that fans out across all four sources. Highlights:
4646

4747
- **~117 Greenhouse boards** + **30 Lever sites** + **36 Ashby boards** + **11 Workday Fortune-500 tenants** in the active source pool.
48-
- **30-minute refresh cadence** via `pg_net` cron triggering the `/admin/refresh-cache` endpoint.
48+
- **4-hour refresh cadence** via `pg_net` cron triggering the `/admin/refresh-cache` endpoint (6 refreshes per day at 00:00 / 04:00 / 08:00 / 12:00 / 16:00 / 20:00 UTC).
4949
- **Relevance-ranked search** through a Postgres RPC that combines query token coverage with recency.
5050
- **Saved-jobs drawer** with a 24-hour TTL — bookmarks survive page reloads but expire if you don't act on them, with an `EXPIRED` badge so nothing silently disappears.
5151

backend/routers/jobs.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def search_jobs(
2929
3030
Default path (`live=false`): query the cached_jobs Supabase table
3131
via Postgres full-text — ~30ms, no upstream load. The cache is
32-
refreshed every 30 min by /admin/refresh-cache.
32+
refreshed every 4 hours by /admin/refresh-cache.
3333
3434
Escape hatch (`?live=true`): bypass the cache and fan out to
3535
every configured Greenhouse / Lever board live. Slower (1-3s) and
@@ -89,7 +89,8 @@ def refresh_cache(
8989
):
9090
"""Refresh cached_jobs from all configured providers.
9191
92-
This is what Supabase pg_cron hits every 30 min. Returns the
92+
This is what Supabase pg_cron hits every 4 hours (six times a
93+
day on the `0 */4 * * *` schedule). Returns the
9394
structured refresh report (see `refresh_cached_jobs`) so cron
9495
output can be inspected when something goes wrong.
9596
"""

docs/architecture.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ Per-user persistent state:
196196

197197
Global (non-user-scoped) state:
198198

199-
- `cached_jobs` — the indexed set of upstream postings refreshed every ~30 min by the backend's `refresh_cached_jobs` worker; see [ADR-013](adr/ADR-013-cached-jobs-cache-layer-with-scheduled-refresh.md)
199+
- `cached_jobs` — the indexed set of upstream postings refreshed every 4 hours (six times a day) by the backend's `refresh_cached_jobs` worker; see [ADR-013](adr/ADR-013-cached-jobs-cache-layer-with-scheduled-refresh.md)
200200

201201
Each `saved_workspaces` row stores one latest snapshot per user, including enough data to restore the current resume/JD/workflow state.
202202

@@ -211,7 +211,7 @@ Each `saved_jobs` row stores one shortlisted posting per user and normalized job
211211

212212
Each `resume_builder_sessions` row stores one in-progress conversational resume-builder draft per user with a 7-day TTL refreshed on every save. A `pg_cron` job (`cleanup-expired-resume-builder-sessions`) hard-deletes expired rows every 5 min and RLS hides expired rows from per-user queries; see [ADR-016](adr/ADR-016-conversational-llm-resume-builder.md).
213213

214-
Each `cached_jobs` row holds one upstream posting keyed on `(source, job_id)`. The table has GENERATED STORED columns (`work_mode`, `employment_type_norm`) backing the dropdown filters and `removed_at` tombstones for upstream-closed jobs the user has bookmarked. A `pg_cron` + `pg_net` schedule POSTs to `/admin/refresh-cache` every ~30 min (see `docs/sql/job_cache_cron_setup.sql`); ranked search reads from this table via the `search_cached_jobs_ranked` RPC, per [ADR-014](adr/ADR-014-postgres-rpc-for-ranked-search.md).
214+
Each `cached_jobs` row holds one upstream posting keyed on `(source, job_id)`. The table has GENERATED STORED columns (`work_mode`, `employment_type_norm`) backing the dropdown filters and `removed_at` tombstones for upstream-closed jobs the user has bookmarked. A `pg_cron` + `pg_net` schedule (`cached_jobs_refresh_4h`) POSTs to `/admin/refresh-cache` every 4 hours, six times a day (see `docs/sql/job_cache_cron_setup.sql` for the template — production runs `0 */4 * * *`); ranked search reads from this table via the `search_cached_jobs_ranked` RPC, per [ADR-014](adr/ADR-014-postgres-rpc-for-ranked-search.md).
215215

216216
## Testing Model
217217

docs/images/job-agent-architecture.svg

Lines changed: 1 addition & 1 deletion
Loading

frontend/src/components/landing-page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ const WORKBENCH_STEPS = [
4040
eyebrow: "02 · Job Search",
4141
title: "Search 12,000+ open roles in one place",
4242
body:
43-
"Live listings from Greenhouse, Lever, Ashby, and Workday — refreshed every 30 minutes so you always see what's actually open. Filter by company, work mode, role type, or how recent the posting is. Sort by best match, newest, or alphabetically.",
43+
"Live listings from Greenhouse, Lever, Ashby, and Workday — refreshed several times a day so you always see what's actually open. Filter by company, work mode, role type, or how recent the posting is. Sort by best match, newest, or alphabetically.",
4444
aside:
4545
"Saved a job that's no longer hiring? Your bookmark stays put with a clear \"Expired\" tag — nothing gets lost from your shortlist.",
4646
},
@@ -889,8 +889,8 @@ function BentoSection() {
889889
</h3>
890890
<p className="l-bento-body">
891891
Live listings from 130+ companies including Stripe, Pinterest,
892-
Anthropic, Notion, Walmart, and Disney. Refreshed every 30
893-
minutes so you&apos;re always seeing what&apos;s actually open.
892+
Anthropic, Notion, Walmart, and Disney. Refreshed several
893+
times a day so you&apos;re always seeing what&apos;s actually open.
894894
</p>
895895
<div className="l-bento-providers">
896896
<span className="l-bento-provider">greenhouse</span>

0 commit comments

Comments
 (0)