Imported from sfynn13433-code/SKCS-Sports-Edge-skcsai (
AGENTS.md). Install upstream withnpx skills add sfynn13433-code/SKCS-Sports-Edge-skcsai. Copyright stays with the author.
AGENTS.md
Project at a Glance
SKCS AI is a multi-sport prediction platform (13+ sports) with real-time accuracy tracking, AI-powered analysis, and tiered subscription features.
- Frontend: HTML/CSS/JavaScript in
public/→ Vercel - Backend: Node.js + Express in
backend/→ Render (https://skcsai-z8cd.onrender.com) - Database: PostgreSQL via Supabase
- Live Domain: https://skcs.co.za
Architecture
Backend Services (backend/services/)
The pipeline architecture follows a staged AI analysis model:
- aiProvider.js - Manages AI inference: Groq (primary) → Dolphin/Llama (fallback)
- aiPipeline.js - Orchestrates multi-stage prediction generation
- syncService.js - Fetches and normalizes data from external 13+ sports APIs
- subscriptionTiming.js - Handles subscription expiry, grace periods, and tier calculations
- accaBuilder.js, direct1x2Builder.js - Constructs combination bets and direct market predictions
- contextIngestionService.js - Injects real-time context (injuries, form, weather) into analysis
Key API clients in backend/apiClients.js connect to RapidAPI, API-Sports, Odds API, and weather services.
Database & Migrations
- PostgreSQL via Supabase (connection pooling with PgBouncer)
- Bootstrap:
backend/dbBootstrap.jsruns on server startup to ensure schema compatibility - Queries: Use
backend/db.js(pg pool wrapper) for all DB operations - Example tables:
fixtures,predictions,direct1x2_prediction_final,subscriptions,profiles
Authentication & Authorization
- Primary: Supabase JWT tokens (via
backend/middleware/supabaseJwt.js) - Fallback: Admin/User API keys in headers (
x-api-key) - Admin Bypass: Email
sfynn13433@gmail.comgets immediate VIP access (see middleware for god mode logic) - Subscription Tiers: core, elite, vip — resolved in
resolveAccessContext()function
Configuration
- backend/config.js - Central env var mapping for APIs, database, AI providers
- backend/config/subscriptionMatrix.js - Defines tier capabilities and feature gates
- backend/config/subscriptionPlans.js - Normalizes plan IDs and retrieves plan metadata
Key env vars:
DATABASE_URL- PostgreSQL connection stringGROQ_API_KEY- Groq inference (primary AI)DOLPHIN_URL- Local/Render Dolphin service fallbackDATA_MODE=live- Switches between live and test data modesNODE_ENV=production- Always production on Render
Development Workflow
Local Setup
npm install # Install dependencies
npm run build:supabase # Bundle Supabase client to public/js/
npm run dev # Start server with nodemon (watches backend/)
Running Pipelines & Utilities
npm run sync:live # Trigger live data sync from all sports APIs
npm run refresh:trigger # Trigger prediction regeneration pipeline
npm run grade:trigger # Grade existing predictions against match results
npm run accuracy:track # Track & store prediction accuracy metrics
Scripts live in scripts/ directory. Common patterns:
trigger-*.js- Hit HTTP endpoints on Render to kick off async jobscheck-*.js- Validate database state, schema, or data integritybackfill-*.js- Manually populate missing fields or correct historical data
Testing & Debugging
- Smoke tests:
npm run testornpm testrunsscripts/smoke-test.js - Rulebook drift guard:
npm run verify:rulebookcatches legacy80/70/59or76%thresholds (local only, no GitHub billing) - Local pre-commit hook: run
npm run install:hooksonce per clone to block commits that reintroduce legacy rule thresholds - API testing: Use postman, curl, or scripts like
scripts/test-api.jswith bearer token headers - Database audit:
scripts/audit-database.jsandscripts/master-qa.jsvalidate tables and data consistency - Logger: Use
backend/utils/jobLogger.jsfor structured job execution logs
Deployment Policy
- For any user-approved change that is meant to go live, do not stop at local edits.
- After verification, commit the changes and push them to the GitHub remote named
deployon branchmain. - Treat that
deployremote as the live production GitHub repo for this workspace. - Vercel and Render are expected to auto-deploy from
deploy/main, so a successful push is the step that should trigger all three targets: GitHub, Vercel, and Render. - Do not claim the site is deployed unless the push to
deploy/mainsucceeded. - If the push fails, report the exact blocker and stop instead of claiming deployment success.
- If the user explicitly asks not to deploy, skip the commit/push step.
Deployment Targets & Build Commands
Vercel (Frontend)
- Output Directory:
public/ - Before Deploy:
npm run build:supabase(bundles Supabase client) - Cron Job:
/api/pipeline/run-fullon Monday 02:00 UTC (defined invercel.json) - Rewrites: Handles
/subscribe/*and/termsroutes viavercel.json
Render (Backend)
- Build Command:
npm install && npm run build:supabase - Start Command:
npm start(runsbackend/server-express.js) - Health Check:
GET /api/health - Port: 10000 (internal), exposed as https://skcsai-z8cd.onrender.com
- Region: Frankfurt, free tier
- Separate Cron Service:
skcs-weekly-global-scraperunsnode backend/deploy-trigger.json Monday 02:00 UTC perrender.yaml
Backend API Structure
Main server in backend/server-express.js listens on $PORT (default 10000).
Core routes (backend/routes/):
/api/predictions/*- Get predictions, filter by tier/sport, track accuracy/api/pipeline/*- Refresh/grade predictions, sync live data/api/user/*- User profile, subscription status/api/debug/*- Internal diagnostics (requires admin key)/api/health- Health check for Render
Critical: No node-cron on Render. All scheduled tasks are triggered externally via HTTP endpoints to avoid race conditions on scaled/sleeping instances.
Critical Code Patterns & Rules
Subscriptions & Tiers
Subscription flow:
- User authenticates via Supabase JWT or API key
requireSupabaseUsermiddleware fetches active subscriptions from DBresolveAccessContext()maps subscription tiers → access scopes- Prediction routes gate features via
getPlanCapabilities()matrix
Example: A user with elite_30day_deep_vip plan gets:
- Daily prediction quota: 500 predictions
- Deep tier analysis enabled
- Access to all secondary markets
Prediction Confidence Tiers & Risk Framework
From STRICT_RULES.md / SKCS_MASTER_RULEBOOK.md — ALL predictions must follow this framework:
- 75-100%: ✅ Low Risk (Green)
- 55-74%: 📊 Medium Risk (Blue)
- 30-54%: ⚠️ High Risk (Orange) — Must attach secondary insights; UI warns users
- 0-29%: 🛑 Extreme Risk (Red) — Not published; enforce exactly 4 secondary insights when surfaced
Secondary insight rules (mandatory):
- Confidence threshold: 72% minimum
- Max 4 per match
- Double Chance is a separate market group (not part of the secondary pool)
- Same Match Builder sizes: 4, 6, 8
- Allowed secondary markets: draw no bet, goals/team totals, BTTS, corners, cards, half markets
- ACCA leg minimum: 75%
Do NOT modify these rules: they are enforced at database level and in backend/services/. Violations create inconsistent user experiences.
AI Provider Fallback Chain
From backend/services/aiProvider.js:
- Groq (primary) — URL:
https://api.groq.com/openai/v1/chat/completions, model:llama-3.1-8b-instant - Dolphin (fallback) — Local/Render service, URL:
$DOLPHIN_URL(defaulthttp://127.0.0.1:8080) - Template (fallback) — Returns placeholder insights if both fail
JSON response extraction uses extractAndParseJSON() helper — tolerates markdown code blocks and partial responses.
Date & Timezone Handling
- SAST (UTC+2):
Africa/Johannesburgtimezone used for rolling sync cutoffs - Normalized Dates: Use
backend/utils/dateNormalization.jsfor fixture dates - Prediction Window: 15-minute grace period post-kickoff (matches more than 15 min past kickoff are rejected)
- Active sync window: 11:59 SAST daily rolling cutoff
Environment-Specific Behavior
Render uses DATA_MODE=live (hardcoded in render.yaml). Local dev can use .env to override.
If DATABASE_URL is missing:
- No PostgreSQL pool is created
- Server boots cleanly but DB operations fail gracefully
- Useful for local development without a remote DB
Remote Notes
deployis the production remote to use for live updates.originmay not be available or may not be the live deployment repo. Do not rely onoriginfor production deployment unless the user explicitly changes the setup.