Next.js App Router website for TUM.ai, plus a small workspace package for typed Notion data access.
.
├── src/ website app
├── packages/notion-data/ shared Notion client + row mappers
├── public/assets/ shipped logos, photos, and media
├── docs/ contributor docs + brand source files
├── scripts/ small build helpers
└── test/ Node-based regression tests
This is a pnpm workspace with two packages:
@tumai/webat the repo root@tumai/notion-datainpackages/notion-data
- Next.js 16 App Router
- React 19
- Tailwind CSS v4
- Biome for linting/formatting
- pnpm workspaces
- Vercel for deployment
- Notion as the source for events, partners, and research data
Install dependencies:
pnpm installPull local env vars from Vercel:
pnpm exec vercel link --yes --project website --scope tum-ai
pnpm exec vercel env pull .env.local --yes --environment=developmentRun the app:
pnpm devLocal dev uses .next-dev. Local builds use isolated dist dirs too, so dev, build, and typecheck do not fight over .next.
pnpm dev # start local dev server
pnpm build # production build into .next-prod
pnpm start # serve the .next-prod build
pnpm lint # biome + workspace lint
pnpm test # Node test runner via tsx
pnpm verify # lint + test + build
pnpm typecheck # Next build-based typecheck into .next-typecheck
pnpm typecheck:all # root typecheck + packages/notion-data typecheckCI currently runs pnpm verify on pull requests to main.
The app reads these server-side environment variables:
NOTION_TOKENNOTION_DB_IDNOTION_TOKEN_PARTNERSNOTION_DB_PARTNERS_IDNOTION_TOKEN_RESEARCHNOTION_DB_RESEARCH_ID
packages/notion-data reads process.env directly. It does not load .env files on its own, so local development should use .env.local or Vercel env pull. If the values are missing, the Notion fetchers return empty arrays instead of crashing.
src/app/owns routing, route handlers, metadata wiring, and the root layout.src/views/holds page-level composition.src/components/holds reusable sections and shared UI primitives.src/data/holds static copy and curated data arrays.src/lib/holds utilities, redirects, security helpers, shared types, and cached Notion access.packages/notion-data/is the only place that talks directly to Notion.
Two pages currently fetch live Notion data on the server:
/events/research
Three API routes mirror the same cached data as JSON:
/api/getNotes(legacy name, returns events)/api/getPartners/api/getResearch
If you need to:
- add or change a route: start in
src/app/, then connect it to a view insrc/views/ - update static page copy: check
src/data/first, then the matching component - change events or research rendering: update both the page view and the Notion-backed types/data path
- change global nav, footer, or font setup: edit
src/app/layout.tsx,src/components/Header.tsx,src/components/Footer.tsx - change shared styling or tokens: edit
src/styles/index.css - change SEO or JSON-LD: edit
src/config/seo.ts - change Notion field mapping: edit
packages/notion-data/src/index.ts, then verifysrc/lib/notion.tsconsumers still match
One important legacy file remains:
src/data/routes.tsxis not runtime routing anymore. App Router files insrc/app/are the source of truth.
- docs/repo-structure.md: architecture and directory map
- docs/contributor-guide.md: practical recipes for common changes
Brand source material is kept under docs/brand/source/.