93 lines
4.1 KiB
Markdown
Executable File
93 lines
4.1 KiB
Markdown
Executable File
# VYNDR — Claude Code Project Context
|
|
|
|
## What This Is
|
|
Sports betting intelligence SaaS. Real software product.
|
|
Three tiers: Free (5 scans), Analyst ($19.99 / $14.99 founder), Desk ($49.99 / $34.99 founder).
|
|
|
|
## Tech Stack
|
|
- Backend: Node.js / Express
|
|
- Database: Supabase (PostgreSQL)
|
|
- Frontend: React Native (built in Cursor)
|
|
- Data: The Odds API ($30/mo), nba_api (free, Python wrapper)
|
|
- Caching: Redis — 15min for odds, 24hr for season averages, 1hr for recent games
|
|
- Payments: Stripe
|
|
|
|
## Critical Rules — Non-Negotiable
|
|
|
|
### 1. NO CODE WITHOUT A SPEC
|
|
Every feature requires a spec file in `specs/` before any code is written.
|
|
Spec must include: endpoints, data shapes, acceptance criteria, test plan.
|
|
Get approval before building.
|
|
|
|
### 2. WSL2 HEREDOC RULE
|
|
WSL2 corrupts heredoc for files over 10 lines.
|
|
ALWAYS use Python file-writing: `python3` with triple-quoted strings.
|
|
This applies to every file creation operation.
|
|
|
|
### 3. 5 QUALITY GATES (all must pass before any feature is marked complete)
|
|
1. Unit tests pass
|
|
2. Integration tests pass
|
|
3. Acceptance criteria met (from spec)
|
|
4. PR description written
|
|
5. CLAUDE.md updated if anything new learned
|
|
|
|
### 4. BUILD-STATE.md
|
|
Update after every session. What shipped, what's next, any blockers.
|
|
|
|
### 5. BLOCKERS.md
|
|
If you hit something you cannot resolve: log it. Don't guess. Don't skip.
|
|
|
|
## Folder Structure
|
|
```
|
|
vyndr/
|
|
├── src/
|
|
│ ├── routes/ # Express route handlers
|
|
│ ├── models/ # Supabase data models
|
|
│ ├── services/ # Business logic (prop analysis, odds normalization)
|
|
│ ├── middleware/ # Auth, rate limiting, scan counting
|
|
│ └── utils/ # Helpers, formatters, validators
|
|
├── tests/ # Unit + integration tests
|
|
├── docs/ # API docs, architecture notes
|
|
├── specs/ # Feature specs (write BEFORE code)
|
|
├── build-briefs/ # Session summaries
|
|
├── CLAUDE.md # This file
|
|
├── ROADMAP.md # Feature roadmap with phases
|
|
├── BUILD-STATE.md # Current build status
|
|
├── BLOCKERS.md # Unresolved blockers
|
|
└── DECISIONS.md # Architecture decisions log
|
|
```
|
|
|
|
## All-Day Intelligence Layer (Session 23)
|
|
Free/cheap content that keeps the platform alive when odds-api props are
|
|
empty. NONE of these spend odds-api credits:
|
|
- `/api/schedule/:sport` — cache-aside ESPN scoreboard (`scheduleService`),
|
|
self-heals on cache miss. Per-game `hasOdds`/`hasGameLines` flags peek at
|
|
other caches without fetching.
|
|
- `/api/gamelines/:sport` — Tank01 book-by-book lines (RAPID_API_KEY quota).
|
|
- `/api/streaks/:sport` + `/api/hotlist/:sport` — PURE engines
|
|
(`streaksService`, `hotListService`) computed from cached game logs. NO
|
|
API calls. Logs loaded by `rosterLogs.js` (prefetch blob, else Redis SCAN
|
|
over `gamelogs:{sport}:{player}:{count}`). Empty roster = valid empty state.
|
|
- `?stat=` filters narrow streaks/hotlist; categories in `config/statFilters.js`
|
|
(mirror `web/src/config/statFilters.ts`). Discovery: `/api/stats/filters/:sport`.
|
|
- Dead providers: set `status: 'dead'` in `config/providers.js` to drop a
|
|
provider from fallback chains + configured list (ParlayAPI host is dead).
|
|
|
|
## Frontend ↔ Backend Wiring (Session 25 — non-obvious)
|
|
A new Express route under `/api/*` is NOT reachable from the browser until
|
|
a matching **Next.js proxy route** exists at `web/src/app/api/.../route.ts`
|
|
that forwards to `${BACKEND_URL}/api/...`. The browser hits the Next origin,
|
|
not Express directly. This bit us: schedule/gamelines/streaks/hotlist
|
|
endpoints worked on Express but 404'd in the UI for two sessions. When
|
|
adding a backend endpoint the frontend calls, ALWAYS add the proxy too
|
|
(pattern: `web/src/app/api/odds/nba/route.ts`).
|
|
|
|
Tank01 betting-odds real shape: sportsbooks are TOP-LEVEL keys on each
|
|
game object (`{ awayTeam, homeTeam, bet365:{...} }`), not a `sportsBooks`
|
|
array. Filter `NON_BOOK_KEYS` to extract books (see `gameLines.js`).
|
|
|
|
## Active Skills
|
|
- vyndr-voice (all user-facing output)
|
|
- prop-analysis (grading methodology)
|
|
- monetization-system (scan-5 pitch, tier conversion)
|