Project
Section One
Open source
A source-grounded college-football desk, built as a team-portable platform and tested by shipping a second edition without a redesign.
- Next.js
- TypeScript
- Drizzle
- RAG
- Playwright
Problem
College football fans want fast context before a game. The available signal is scattered across schedules, game notes, official links, data feeds, and rumor-heavy commentary. Section One answers three questions for one team at a time: what matters this week, what to watch during the game, and what supports that read. A fan can already get a feed; what they cannot get is five things that actually matter, chosen by someone who knows which five.
Product Boundary
Team identity, source policy, voice, protected-mark guidance, color anchors, aliases, and starter questions live in typed configuration. Components carry no team name, color, or matchup claim; if adding a team required changing a component, the boundary would be wrong. The product avoids official logos, mascot branding, and affiliation language, which keeps it legally cleaner and forces the experience to stand on source quality instead of borrowed brand equity.
The Second Edition Test
A portability claim is worth what the second instance proves. Adding the Utah State edition alongside Texas cost two fixes and no redesign. The question classifier had reserved a single word for the team's name, which fit Texas and not Utah State, so anything team-shaped in shared logic now reads from config. And the structural dark belongs to the school when the school has one: only a primary too bright to be structure, as burnt orange is, gets a counterweight. Getting that backwards is what gave Utah State a brown masthead in its first draft.
Architecture
The Next.js app serves a home route that takes team requests and a canonical /teams/[slug] edition for each enabled team, plus API routes for health, ingest, and chat. Schedules are build outputs, not hand-typed rows: pnpm schedule:build regenerates a fixture from CollegeFootballData so kickoff times, venues, and broadcast assignments come from the source. Documents are normalized, de-duplicated, and chunked, then retrieved by hybrid search that fuses deterministic lexical scoring with pgvector cosine search through reciprocal rank fusion. With no database or no seeded embeddings, vector search returns nothing and retrieval degrades to lexical rather than failing.
Editorial Rules
The weekly sections are governed by written rules, not author discretion. Rankings are read from the team outward: most teams are unranked, so the list under the standing line is the ranked opponents on that team's own schedule, hardest first. News items are graded on impact, echo, and freshness, decayed by age, and filled under a cap of two per outlet with at least three distinct outlets and local reporting never outnumbered by national. Every item carries its outlet and links out; an item without a source is not publishable, and fixture tests enforce that instead of trusting the author.
Guardrails
The chat path carries citations, freshness text, confidence, provider metadata, and a mode for every answer. Rumor, injury, betting, and message-board questions route through a static guardrail response instead of laundering untrusted claims. If a live LLM provider is unavailable, the app falls back to a deterministic mock provider so the product still returns a grounded answer from the retrieved context.
Quality Bar
The release check combines lint, typecheck, unit tests, voice evals, build, ingest, and Playwright e2e coverage. Offline fixtures make the core flow runnable without private keys. Database smoke tests cover Drizzle migrations and seeding for teams, games, source documents, chunks, sessions, messages, and citations, including the expected warning path when the live CFBD key is absent.
Stack
Next.js 16 · React 19 · TypeScript · Tailwind CSS v4 · Drizzle · Postgres + pgvector · Anthropic/OpenAI adapters · Vitest · Playwright