Newcomer Repo & Workers Guide
Audience: engineers new to the Timed Trading repo (day 1 / first week). Start here, then follow the reading path below.
1. What you are looking at
Timed Trading is a Cloudflare Workers + Pages product:
| Layer | What it is |
|---|---|
| Pages frontend | Prebuilt HTML/JS from react-app/ → react-app-dist/, auto-deploys on git push to main |
| API monolith | timed-trading-ingest — all /timed/* routes + Durable Objects |
| Role cron workers | tt-feed, tt-engine, tt-research — same codebase, role-gated crons |
| Broker bridge | tt-broker-bridge — separate sidecar (worker-bridge/) for IBKR / Webull / Robinhood (+ E*TRADE scaffold) |
| Data | D1 (timed-trading-ledger) + KV (timed:prices, timed:latest, …) |
| Market data | TwelveData primary; Alpaca for execution / fallback |
Product entry for signed-in users is /today.html (not the retired /index-react.html).
2. Read in this order (~15–20 min)
Paths below are in the git repo root (e.g. /workspace/… on the agent VM, or the local clone):
AGENTS.md— onboarding contract, house rules, Cursor Cloud local tipsCONTEXT.md— stack, deploy, journey pages, condensed critical lessonsskills/README.md— index of how-to playbooksskills/worker-topology.md— which worker runs which cronskills/deploy.md— what to deploy when; merge ≠ deploy
Do not try to memorize CONTEXT.md lessons on day 1. Skim the Stack / Deploy / Product entry sections; grep lessons when something looks familiar.
3. Repo map
| Path | Role |
|---|---|
worker/ | Main Worker source + wrangler.toml for timed-trading-ingest. Routes, scoring, trade logic, DOs (PriceStream, PriceHub, …). |
worker-feed/ | Wrangler config for tt-feed. Bundles feed entry + shared worker/ modules. Owns price-feed cron after cutover. |
worker-engine/ | Wrangler config for tt-engine. Same monolith bundle (main = "../worker/index.js"). Owns */5 scoring + trade lifecycle. |
worker-research/ | Wrangler config for tt-research. Same monolith bundle. Owns hourly research + 22:00 UTC nightly batch. |
worker-bridge/ | Separate codebase for tt-broker-bridge. Broker adapters, sizing, reconciler, mirror kernel. No CF Access end-user auth. |
react-app/ | Source HTML + JSX pages, shared rail, tokens, _worker.js (Pages proxy). |
react-app-dist/ | Built output Pages serves. Commit after npm run build:frontend. |
scripts/ | Build, deploy helpers, replay, analysis. |
skills/ | Reusable playbooks (prefer these over inventing procedures). |
tasks/ | Live plans (todo.md), lessons (lessons.md), session plans. |
docs/ | Longer architectural docs + runbooks. |
CONTEXT.md / AGENTS.md | Session onboarding — load every session. |
Mental model: four Cloudflare Worker scripts share one trading codebase; the bridge is a fifth script with its own tree. Pages is independent of Worker deploys.
4. Which worker runs what
Canonical detail: skills/worker-topology.md.
| Worker script | Config dir | Owns |
|---|---|---|
timed-trading-ingest | worker/ | All /timed/* HTTP, Durable Objects, any cron not externalized |
tt-feed | worker-feed/ | Price-feed cron + stream keep-alive (worker/feed/*) |
tt-engine | worker-engine/ | */5 scoring + trade lifecycle lanes |
tt-research | worker-research/ | Hourly research arms + nightly mega-batch |
tt-broker-bridge | worker-bridge/ | Broker connect / order / positions / reconcile (sidecar) |
Cutover flags (do not dual-run)
| Domain | Monolith (stop doing X) | Dedicated (start doing X) |
|---|---|---|
| Feed | PRICE_FEED_EXTERNAL=true | FEED_ENABLED=true on tt-feed |
| Engine | ENGINE_EXTERNAL=true | ENGINE_ENABLED=true on tt-engine |
| Research | RESEARCH_SLOTS_EXTERNAL=true | RESEARCH_ENABLED=true on tt-research |
Order: flip monolith *_EXTERNAL first, then enable the dedicated worker. Overlap corrupts state. Flags are dashboard vars (keep_vars = true); never wrangler secret put a name that already exists as a var.
Binding parity
Role workers declare their own bindings. A binding added only to worker/wrangler.toml is not on tt-engine/feed/research. DOs stay owned by the monolith — role workers reference them with script_name = "timed-trading-ingest". Silent if (env.SOME_BINDING) fallbacks have caused multi-day freshness outages; prefer surfacing misses in health/tombstones.
5. Pages vs Worker (critical)
| Concern | Pages | Worker(s) |
|---|---|---|
| Serves | HTML/JS/CSS from react-app-dist/ | /timed/* JSON APIs, crons, DOs |
| Deploy trigger | Push/merge to main (git-connected Pages) | Wrangler / CI workflows per script |
| Local | wrangler pages dev react-app-dist --port 8788 | wrangler dev in worker/ on 8787 |
| Proxy | react-app/_worker.js hardcodes WORKER_ORIGIN to production | — |
npm run deploy:workerdoes not update UI pages.- Changing
worker/without redeploying tt-engine / tt-research leaves cron lanes on old code (npm run deploy:cronsor CI). - A green GitHub Actions run is not proof prod moved — check
deployedShaon/timed/healthor Cloudflare version dates (skills/deploy.md). - For local API work against a local worker, temporarily point built
react-app-dist/_worker.jsathttp://localhost:8787(revert; do not commit).
6. How to run locally
Full notes live in AGENTS.md → Cursor Cloud specific instructions. Condensed:
Prerequisites
cd /workspace # or clone root
npm install # no lockfile; use install not ci
Create git-ignored worker/.dev.vars:
TIMED_API_KEY=local-dev-key
CF_ACCESS_AUD=local-dev-aud
Optional for live quotes / LLM: TWELVEDATA_API_KEY, OPENAI_API_KEY.
Without those secrets, wrangler dev returns 503 runtime_misconfigured.
Boot
# Terminal A — API (Miniflare KV/D1/DO; small seed universe)
cd worker && ../node_modules/.bin/wrangler dev --port 8787
# Terminal B — frontend (after build)
cd /workspace
npm run build:frontend
./node_modules/.bin/wrangler pages dev react-app-dist --port 8788
Port 8788 is allow-listed in worker CORS_ALLOW_ORIGIN.
Auth locally
| Caller | Effect |
|---|---|
?key=local-dev-key or X-API-Key: local-dev-key | Admin-tier, unredacted prices + scores |
| No key | Member/anon view (_redacted:true) |
Cloudflare Access (Google OAuth) cannot complete on a typical cloud VM — only public surfaces like /splash render in a browser. Exercise authenticated logic via curl + API key.
Useful local probes
curl -s "http://localhost:8787/timed/health"
curl -s "http://localhost:8787/timed/all?slim=1" -H "X-API-Key: local-dev-key" | head -c 200
# Crons do not auto-fire in wrangler dev:
curl "http://localhost:8787/cdn-cgi/handler/scheduled"
Local D1 starts empty; schema is created lazily by d1Ensure*Schema(). POST /timed/ingest-capture is a robust way to exercise ingest without a full scoring universe.
Tests (the only gate)
npm test # vitest
# CI also: node --check on worker entrypoints + esbuild bundle check
There is no lint step. npm run build:frontend always dirties react-app-dist/ cache-bust stamps — revert if built only to verify.
7. Auth, tiers, and entitlements (day-1 version)
Canonical matrices: skills/user-state-matrix.md, skills/security-auth-patterns.md.
| Label | Meaning |
|---|---|
| Pro | Paying subscriber |
| VIP | Invite / manual grant — entitled like Pro (no monthly fee) |
| Admin | Operator |
| Member | Signed in, never paid — code tier free |
| Anon | Not signed in |
Live prices + proprietary scores go to Pro / VIP / Admin only:
- Server:
canAccessLivePrices()+redactTickerMapForTier()inworker/api.js - UI display gate:
window._ttIsPro - Members and anon get neither; prefer structured 200s with
_redacted/tier_required, not noisy 4xx on poll endpoints
- CF Access gates authenticated HTML pages (Google OAuth).
- Stripe drives Pro subscription state; VIP codes / admin grants use
subscription_status='manual'. - API key (
TIMED_API_KEY) is operator/admin path — preferX-API-Keyheader;?key=is deprecated.
8. Price pipeline (invariants to internalize)
Full rules: workspace .cursor/rules/price-data-pipeline.mdc + CONTEXT lessons. Do not invent alternate change math.
- TwelveData first (
DATA_PROVIDER=twelvedata); Alpaca is execution / fallback. getDailyChange(t)inreact-app/shared-price-utils.jsis the only client daily-change path.- KV
timed:pricesshort keys:p,pc,dc,dp, … Extended:ahp,ahdc,ahdp. - Value timestamps are mandatory:
q_ts(quote receipt) andp_ts(last price move). Freshness gates key off these — never pollt. Writers must stamp and never regress stamps. - PriceStream DO (TwelveData WS) must own symbols in
timed:prices; orphan symbols can get clobbered by KV eventual consistency between cron and DO. - Outside RTH, preserve day-change and EXT fields appropriately; never write AH fields during RTH.
- Footer must include "Market data powered by Twelve Data" (licensing).
If prices look "stuck on yesterday," check value stamps and /timed/health (valueStaleCount), not just t.
9. Where to look for common tasks
| Need | Skill (repo path) |
|---|---|
| Deploy / confirm prod moved | skills/deploy.md |
| Which cron / worker | skills/worker-topology.md |
| Stale / wrong ticker score | skills/rescore-ticker.md |
| Snapshot / universe / stale scores | skills/all-snapshot.md |
| D1 query | skills/d1-debugging.md |
| KV inspect | skills/kv-inspection.md |
| HTTP 401/403/404/503 | skills/debug-http-codes.md |
| New route / WS / LLM HTML | skills/security-auth-patterns.md |
| Broker / IBKR / Webull | skills/broker-bridge.md |
| Partner broker isolation | skills/partner-onboarding.md |
| Frontend blank / build | skills/frontend-build.md |
| UI design system | skills/verda-ui-migration.md |
| Discord alerts | skills/discord-alerts.md |
| Billing / VIP / tax | skills/billing-and-sales-tax.md |
Full index: skills/README.md. If more than ~3 tool calls inventing a procedure, write a skill before leaving.
10. House rules (do not skip)
From AGENTS.md / CONTEXT:
- No emojis in code, commits, or PRs unless asked.
- User-facing product copy: avoid "you / your" (compliance).
- Never inline daily change math — use
getDailyChange. - Gate live prices + scores to Pro/VIP/Admin.
- Plan non-trivial work in
tasks/todo.md(append; avoid merge-conflict churn on the Active header from feature PRs). - Stop after two failed attempts at the same approach — re-plan.
- Verify before done; after operator corrections, update
tasks/lessons.md+ a one-liner in CONTEXT. - One logical change per commit/PR; before pushing an existing branch run
bash scripts/check-branch-merge-state.sh.
11. First-week checklist
Day 1 — Orient
- Read AGENTS.md + CONTEXT Stack/Deploy/Product sections + skills README
- Skim worker-topology.md and this guide’s architecture companion
- Map the five Worker scripts and what Pages serves
- Clone/build:
npm install,npm testgreen (or know why not)
Day 2 — Local loop
worker/.dev.varswith placeholder secrets- Boot
wrangler devon 8787; hit/timed/healthand a keyed/timed/all?slim=1 - Build frontend; understand Pages→production proxy caveat
- Trigger a scheduled handler once; note crons don’t auto-fire locally
Day 3 — Data plane
- Inspect
timed:pricesshape (KV skill); findq_ts/p_ts - Trace one ticker from TwelveData → PriceStream/cron → KV → UI
getDailyChange - Read
skills/all-snapshot.md(slim index vs full payload OOM history)
Day 4 — Auth & gating
- Walk user-state-matrix; confirm Member vs Pro vs VIP vs Admin
- Call an endpoint without key (redacted) vs with key (full)
- Read security-auth-patterns (route guards, WS tickets, no unguarded mutators)
Day 5 — Deploy awareness
- Read deploy.md decision tree; list which scripts a
worker/**change touches - Know how to verify
deployedSha/ version dates (merge ≠ deploy) - Note Pages vs Worker independence (UI field without worker stamp = blank badges)
Days 6–7 — One vertical slice
- Pick a small skill-backed task (rescore, KV inspect, Discord dry-run, or a UI token fix)
- Ship behind the usual PR/check-branch-merge-state discipline
- Grep
tasks/lessons.mdfor the area touched before claiming done
12. Architecture visual
Mermaid + partner-facing detail: engineering partner onboarding.
13. Unknowns / do not invent
Mark these as “ask the operator” rather than guessing:
- Exact production Cloudflare account / Pages project dashboard URLs (not required for local work)
- Which cutover flags are currently live in prod (read dashboard vars or
/timed/health/ role health endpoints — do not assume) - Partner-specific broker credentials and
BRIDGE_*secrets (never commit; see partner-onboarding skill) - Any infra not present under
worker*/wrangler.tomlor documented in skills