The public website for THS Armada — KTH's and Sweden's largest student career fair.
- Tech Stack
- Prerequisites
- Getting Started
- VS Code workspace and launches
- Scripts
- Storybook
- Project Structure
- Key Conventions
- CI / CD
- Backend environments
- Framework: Next.js 16 (App Router)
- Language: TypeScript
- UI: React 19, shadcn/ui (Radix + CVA), some MUI components
- Styling: Tailwind CSS v4 (CSS-first config)
- Data fetching: TanStack React Query, server components with async
fetch*functions - Backend API: ArmadaCMS (Go REST API)
- Deployment: Vercel
- Node.js 24.x
- pnpm (pinned version via
packageManagerinpackage.json)
-
Clone the repo
git clone https://github.com/armada-ths/armada.nu.git cd armada.nu -
Install dependencies
pnpm install
-
Set up environment variables
cp .env.example .env.local
Fill in the values you need. Not all variables are required — see the comments in
.env.examplefor details. -
Start the dev server
pnpm dev
Open http://localhost:8000.
This repo includes shared VS Code configuration for both single-repo and multi-repo workflows.
In .vscode/ you will find:
tasks.json— shared tasks fordev,lint,type-check, andbuildlaunch.json— browser launches that use the shared dev tasks
If you work on both the public site and the CMS together, open:
Armada.code-workspace
That workspace opens:
armada.nu../ArmadaCMS
and includes compound launches such as:
✅ Frontend + Prod CMS✅ Full Stack Local (Docker)
This requires you to have both repos checked out in the same parent directory.
| Command | Description |
|---|---|
pnpm dev |
Start dev server (port 8000) |
pnpm build |
Production build |
pnpm start |
Start production server |
pnpm storybook |
Run Storybook (port 6006) |
pnpm build-storybook |
Build static Storybook output |
pnpm lint |
Run ESLint |
pnpm type-check |
Run TypeScript type checking |
pnpm format |
Format code with Prettier |
pnpm format:check |
Check formatting |
This repo uses Storybook to build and review UI components in isolation. Story files live next to components and use the *.stories.tsx naming convention. Prefer multiple story variants and play functions for interactive states. The repo also integrates with Chromatic for visual regression testing via CI — see the CI / CD section.
src/
├── app/ # Next.js App Router pages
│ ├── _components/ # Landing page components
│ ├── about/ # /about routes
│ ├── exhibitor/ # /exhibitor routes
│ ├── student/ # /student routes
│ ├── globals.css # Tailwind v4 theme & global styles
│ ├── layout.tsx # Root layout (fonts, metadata)
│ └── page.tsx # Homepage
├── components/
│ ├── shared/ # Shared components (Page, NavigationMenu, Footer, hooks)
│ └── ui/ # shadcn/ui primitives
├── lib/
│ └── utils.ts # cn(), date helpers (Luxon)
├── env.ts # All env vars — add new ones here
└── feature_flags.ts # Feature flag definitions & CMS-backed defaults
- Adding env vars: Always register them in
src/env.ts. UseNEXT_PUBLIC_prefix for client-safe vars. - Data fetching: Use the dual-export pattern in
src/components/shared/hooks/api/—fetch*()for server components,use*()hooks for client components. - Feature flags: Use
await feature("FLAG_NAME")in server components (seesrc/components/shared/feature.ts). Default values are fetched from ArmadaCMS (/api/v1/featureflags), with Vercel flag cookie overrides applied. - Adding shadcn components:
npx shadcn@latest add <component> - Adding pages: Add an entry to
src/app/sitemap.ts. If the page is gated by a feature flag, the sitemap conditionally includes it. - Cache revalidation: The site uses ISR with on-demand revalidation. Each data hook sets
next: { revalidate: 86400, tags: ["<tag>"] }. The CMS triggersPOST /api/revalidateafter write operations to purge specific cache tags instantly. See the tag inventory in copilot-instructions.md for the full list. - Analytics: Vercel Analytics and Speed Insights are loaded in the root layout. Use
TrackedLinkfromsrc/components/shared/TrackedLink.tsxfor user-interaction tracking. - Brand colors:
- Prefer semantic Tailwind classes like
text-melon,bg-coconut,text-licorice(fromsrc/app/globals.css). - Runtime JS/TS color values live in
src/lib/colors.ts(HEX_COLORS). src/app/globals.cssandsrc/lib/colors.tsare a paired source of truth and must be kept in sync when adding/changing color values.- Avoid hardcoded hex values in
src/**/*.{ts,tsx,js,jsx}; add/reuse constants insrc/lib/colors.ts.
- Prefer semantic Tailwind classes like
CI is handled by GitHub Actions and CD by Vercel's GitHub integration.
Repository checks live in .github/workflows/:
ci.yml— runs on push tomain/stagingand on pull requests; runspnpm lint,pnpm type-check, andpnpm format:checkas separate jobs.chromatic.yml— runs on every push; builds Storybook and uploads it to Chromatic for visual regression testing. PRs get a Chromatic status check with visual diffs.CHROMATIC_PROJECT_TOKENis stored as a GitHub secret — do not commit it to the repo. TheautoAcceptChanges: mainoption auto-approves baseline updates on themainbranch.codeql.yml— runs on push tomain/staging, PRs, and on a weekly schedule; CodeQL security analysis covering JavaScript/TypeScript and Actions workflows.
Deployments are handled automatically by Vercel's GitHub integration:
- Every push to
maintriggers a production deployment to armada.nu. - Every push to
stagingtriggers a preview deployment to staging.armada.nu. - Pull requests from branches other than
main/stagingtrigger preview deployments with unique Vercel URLs. - Preview deployments are protected by Vercel Deployment Protection;
VERCEL_AUTOMATION_BYPASS_SECRETis used by the CMS to send cache revalidation requests to preview/staging deployments. - Vercel project configuration (env vars, domain settings, etc.) is managed with Terraform — see
infra/terraform/vercel/prod/README.mdfor details.
Set NEXT_PUBLIC_API_URL in .env.local to point the dev server at a different backend:
| Environment | API base URL |
|---|---|
| Local dev | http://localhost:8080/api/v1 |
| Staging | https://staging.cms.armada.nu/api/v1 |
| Production | https://cms.armada.nu/api/v1 |