Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
cd0815b
refine ai summary llm prompt
anchen9 Mar 13, 2026
afcae29
first draft schema
anchen9 Mar 20, 2026
bea066d
add aidescription field
anchen9 Mar 22, 2026
86b6203
tweak host club portion
anchen9 Apr 10, 2026
3a5563e
initial commit for design system
anchen9 Apr 13, 2026
85e16a8
restructure repo to accomodate monorepo structure
anchen9 Apr 14, 2026
0139d2d
chore: add formatter
megany128 Apr 14, 2026
c4f03dc
ui: add explicit type hints to text
megany128 Apr 14, 2026
ec7872c
feat: design tweaks
megany128 Apr 14, 2026
6304f84
ui: design tweaks
megany128 Apr 14, 2026
3d4e96b
ui: polish design system
megany128 Apr 15, 2026
4b8f57a
design system front end tweaks
zw757 Apr 17, 2026
738642f
Merge branch 'annie/setup-design-system' of https://github.com/cornel…
zw757 Apr 17, 2026
45dd9ca
dashboard updates
NikhillA Apr 18, 2026
4894bcf
Dashboard
NikhillA Apr 22, 2026
418e3b9
prettier fix
anchen9 Apr 22, 2026
bdfbd52
Merge pull request #3 from cornell-dti/annie/schema
anchen9 Apr 22, 2026
e610766
Merge remote-tracking branch 'origin/main' into annie/setup-design-sy…
anchen9 Apr 22, 2026
a491293
prettier fixes pt2
anchen9 Apr 22, 2026
3781b5c
new pages
NikhillA Apr 23, 2026
05f78b7
profile changes
NikhillA Apr 23, 2026
6fa9d16
checkpoint: landing page
megany128 Apr 24, 2026
2d1572b
wip: dashboard home layout + sample data
megany128 Apr 24, 2026
adfb63b
merge: pull design system updates from annie/setup-design-system
megany128 Apr 24, 2026
7c75857
ui: wire up home page
megany128 Apr 24, 2026
8baadf5
checkpoint: dashboard ui
megany128 Apr 26, 2026
d25d823
ui: finish landing page
megany128 Apr 27, 2026
5919461
chore: add convex AI files
megany128 Apr 27, 2026
2b0c1bb
feat: initial FE+BE wiring
megany128 Apr 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "cd \"$CLAUDE_PROJECT_DIR\" && bun run type-check && bun run lint && bun run format:check",
"timeout": 120
}
]
}
]
}
}
29 changes: 29 additions & 0 deletions .cursor/rules/frontend/figma.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## Figma MCP Integration Rules

These rules define how to translate Figma inputs into code for this project and must be followed for every Figma-driven change.

### Required flow (do not skip)

1. Run get_design_context first to fetch the structured representation for the exact node(s).
2. If the response is too large or truncated, run get_metadata to get the high‑level node map and then re‑fetch only the required node(s) with get_design_context.
3. Run get_screenshot for a visual reference of the node variant being implemented.
4. Only after you have both get_design_context and get_screenshot, download any assets needed and start implementation.
5. Translate the output (usually React + Tailwind) into this project’s conventions, styles and framework.  Reuse the project’s color tokens, components, and typography wherever possible.
6. Validate against Figma for 1:1 look and behavior before marking complete.

### Implementation rules

- Treat the Figma MCP output (React + Tailwind) as a representation of design and behavior, not as final code style.
- Replace Tailwind utility classes with the project’s preferred utilities/design‑system tokens when applicable.
- Reuse existing components (e.g., buttons, inputs, typography, icon wrappers) instead of duplicating functionality.
- Use the project’s color system, typography scale, and spacing tokens consistently.
- Respect existing routing, state management, and data‑fetch patterns already adopted in the repo.
- Strive for 1:1 visual parity with the Figma design. When conflicts arise, prefer design‑system tokens and adjust spacing or sizes minimally to match visuals.
- Validate the final UI against the Figma screenshot for both look and behavior.

### Figma MCP server rules

  - The Figma MCP server provides an assets endpoint which can serve image and SVG assets
  - IMPORTANT: If the Figma MCP server returns a localhost source for an image or an SVG, use that image or SVG source directly
  - IMPORTANT: DO NOT import/add new icon packages, all the assets should be in the Figma payload
  - IMPORTANT: do NOT use or create placeholders if a localhost source is provided
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ jobs:
run: bun run type-check
- name: Lint check
run: bun run lint
- name: Format check
run: bun run format:check
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,10 @@ dist-ssr
*.njsproj
*.sln
*.sw?

# Visual-QA artefacts (generated by scripts/screenshot-home.mjs)
specs/iterations/*.png

# Env
.env
.env.local
6 changes: 6 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
dist
pnpm-lock.yaml
convex/_generated
apps/dashboard/test-results
apps/dashboard/playwright-report
8 changes: 8 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"semi": true,
"singleQuote": false,
"trailingComma": "all",
"printWidth": 80,
"tabWidth": 2,
"plugins": ["prettier-plugin-tailwindcss"]
}
75 changes: 75 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Cornell Loop — Agent Guide

Loop is an event-discovery dashboard for Cornell student orgs. Students follow clubs, RSVP to events, and browse a feed of upcoming happenings. Convex backs auth + data; a browser extension surface is also planned.

Keep this file concise — it loads every new session.

## Repo layout

- `apps/dashboard/` — Vite + React 19 + TypeScript SPA (the main web app).
- `shared/ui/` — design system (components, tokens, utils). Imported in the dashboard via the `@app/ui` alias (see `apps/dashboard/vite.config.ts`).
- `ai/`, `scripts/`, `specs/` — docs, codegen helpers, and visual-QA artefacts.

No other apps today; workspace is set up to grow (e.g. extension).

## Tech stack

- **React 19** + **React Router v7** (see `apps/dashboard/src/App.tsx` for routes).
- **Convex** (`@convex-dev/auth`) for auth. `ProtectedRoute` has a **dev bypass** — protected routes render without login when `import.meta.env.DEV`. Great for iteration. **Always read `apps/dashboard/convex/_generated/ai/guidelines.md` first** before touching Convex code — its rules override training data.
- **Tailwind CSS v4** via `@tailwindcss/vite`. No config file; content scanning is via `@source` directives inside `apps/dashboard/src/index.css`. **Important:** `shared/ui/src` is explicitly `@source`'d so design-system classes land in the generated CSS. If a design-system class silently stops working, check that this `@source` is still present.
- **Design tokens** are plain CSS custom properties in `shared/ui/src/styles/tokens.css` (`--color-*`, `--space-*`, `--font-*`, `--radius-*`, `--shadow-*`, etc.). **Never hardcode colors/spacing/fonts.** Reference tokens with Tailwind arbitrary-value syntax, e.g. `bg-[var(--color-surface)]`, `gap-[var(--space-4)]`.
- **Fonts**: DM Sans (body), Inter (UI), Manrope (brand wordmark). Loaded in `apps/dashboard/index.html`.
- **SVG** via `vite-plugin-svgr` (`import Icon from './x.svg?react'`).

## Package manager

- This repo uses **bun** (not pnpm — ignore any older doc that says otherwise).
- Root scripts forward into the dashboard package:
- `bun run dev` — start Vite (default 5173, falls back to 5174 if busy).
- `bun run build` — `tsc -b && vite build`.
- `bun run type-check` — `tsc --noEmit`.
- `bun run lint` — ESLint.
- `bun run format` / `bun run format:check` — Prettier (with tailwind plugin).
- If bun is unavailable in a sandbox, `node scripts/*.mjs` still works for scripts.

## Automated checks (Claude Stop hook)

A `Stop` hook in `.claude/settings.json` runs `bun run type-check && bun run lint && bun run format:check` at the end of every turn. If it fails, address the errors before finishing — even pre-existing ones.

## Visual QA workflow

- **Screenshot the dashboard** with Playwright:
- `node scripts/screenshot-home.mjs <label>` — screenshots `/home` at 1280/1440/1920 viewports into `specs/iterations/`.
- `node scripts/screenshot-scroll.mjs <label>` — screenshots scrolled state to verify sticky sidebar behaviour.
- Requires the dev server running: `bun run dev &`. The scripts assume `http://localhost:5174/home`; override with `HOME_URL=...`.
- `specs/iterations/*.png` is gitignored.
- Design-system gallery route (dev-only): `/design-system` renders every token and component with sample data. Use it as the visual source of truth when the Figma file conflicts with component behaviour.

## Sample data

`apps/dashboard/src/data/sampleHome.ts` exports `SAMPLE_POSTS`, `SAMPLE_RSVP_GROUPS`, `SAMPLE_CLUBS`. These feed `/home` until Convex tables exist.

## Coding rules

- **Ask clarifying questions** when a prompt or approach is unclear — don't guess.
- **Default to delegating** cohesive / repetitive / multi-file tasks to subagents. Reserve the main conversation for decision-making, proposals, and review. Brief subagents with: files to touch, pattern to follow, and "run type-check/lint/format when done".
- **Fix pre-existing warnings** in files you touch, regardless of origin.
- **Never use `any` or `as` casts.** Fix the type or schema properly.
- **Never leave TODOs.** Implement everything.
- **Never hardcode design values.** Reference `tokens.css` via `var(--…)`.
- When adding files, prefer editing existing ones. Don't create docs or READMEs unless asked.

## Figma MCP rules

Required flow for any Figma-driven change:

1. `get_design_context` with the exact node id(s).
2. If truncated, `get_metadata` → re-fetch specific nodes.
3. `get_screenshot` for the visual reference.
4. Download assets only after you have both context + screenshot. Start implementation then.
5. Translate the Tailwind output into **this repo's** tokens and existing components. Do not import icon packages — assets come from Figma. Reuse `Button`, `Tag`, `Avatar`, `DashboardPost`, `SearchPanel`, etc. from `@app/ui`.
6. Validate against the Figma screenshot.

The Figma MCP output is a representation, not final code. Use localhost image URLs directly when provided; never invent placeholders when one exists.

**When Figma and the design system disagree, the design system is the source of truth.** Confirm by checking `/design-system` or `shared/ui/src/components/*`.
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ If you are developing a production application, we recommend updating the config

```js
export default defineConfig([
globalIgnores(['dist']),
globalIgnores(["dist"]),
{
files: ['**/*.{ts,tsx}'],
files: ["**/*.{ts,tsx}"],
extends: [
// Other configs...

Expand All @@ -34,40 +34,40 @@ export default defineConfig([
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
project: ["./tsconfig.node.json", "./tsconfig.app.json"],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
]);
```

You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:

```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
import reactX from "eslint-plugin-react-x";
import reactDom from "eslint-plugin-react-dom";

export default defineConfig([
globalIgnores(['dist']),
globalIgnores(["dist"]),
{
files: ['**/*.{ts,tsx}'],
files: ["**/*.{ts,tsx}"],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
reactX.configs["recommended-typescript"],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
project: ["./tsconfig.node.json", "./tsconfig.app.json"],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
]);
```
92 changes: 92 additions & 0 deletions ai/data/dummy_data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
[
{
"listserv": "ACSU",
"host": "ACSU",
"club": "ACSU",
"title": "ACSU Student Faculty Luncheon",
"description": "Connect with CS professors and students over lunch with other CS students.",
"date": "2026-03-13",
"location": "CIS 250 (Young Conference Room)",
"tags": ["networking", "cs", "faculty"]
},
{
"listserv": "ACSU",
"host": "ACSU",
"club": "ACSU",
"title": "1:1 Faculty Coffee Chat Week",
"description": "Sign up for informal 1:1 chats with professors about research opportunities, careers, and advice.",
"date": "2026-03-09",
"location": "Various campus locations",
"tags": ["research", "mentorship", "coffee"]
},
{
"listserv": "ACSU",
"host": "Cornell AppDev & Ramp",
"club": "Cornell AppDev",
"title": "AppDev x Ramp - HACK→HIRED",
"description": "One-day AI-focused hackathon with workshops, prizes, and a chance to interview for a Fall SWE internship at Ramp.",
"date": "2026-03-14",
"location": "eHub",
"tags": ["hackathon", "career", "recruiting", "ai"]
},
{
"listserv": "ACSU",
"host": "Citadel GQS",
"club": "",
"title": "Citadel Global Quantitative Strategies Tech Talk",
"description": "Tech talk on quantitative trading careers and how your research skills translate to GQS at Citadel.",
"date": "2026-03-17",
"location": "Upson 142",
"tags": ["finance", "tech-talk", "recruiting"]
},
{
"listserv": "WICC",
"host": "WICC",
"club": "WICC",
"title": "Cracking Your Career (CYC)",
"description": "Four-part series on pathways in computing, interviewing, resumes, and standing out in tech roles.",
"date": "2026-03-03",
"location": "Gates 114",
"tags": ["career", "workshop"]
},
{
"listserv": "WICC",
"host": "WICC & MathWorks",
"club": "WICC",
"title": "WICC x MathWorks MATLAB Challenge",
"description": "Hands-on MATLAB challenge using MATLAB Copilot with prizes, swag, and info on careers at MathWorks.",
"date": "2026-03-16",
"location": "Gates G01",
"tags": ["workshop", "mathworks", "ai", "swag"]
},
{
"listserv": "WICC",
"host": "WICC & Jane Street",
"club": "WICC",
"title": "WICC x Jane Street Tech Talks",
"description": "Talk on predictable communication at scale and Aria, Jane Street's low-latency messaging system, with food and swag.",
"date": "2026-03-18",
"location": "Phillips 101",
"tags": ["talk", "jane-street", "systems"]
},
{
"listserv": "WICC",
"host": "External",
"club": "",
"title": "HackDartmouth XI",
"description": "24-hour hackathon at Dartmouth with workshops, prizes, and a Lost In Space theme.",
"date": "2026-04-11",
"location": "Dartmouth",
"tags": ["hackathon", "travel"]
},
{
"listserv": "WICC",
"host": "Jane Street",
"club": "",
"title": "Jane Street FOCUS Program",
"description": "Multi-day NYC program for first-year students to explore trading, software development, and strategy at Jane Street.",
"date": "2026-05-19",
"location": "New York City",
"tags": ["program", "first-year", "professional-track"]
}
]
26 changes: 26 additions & 0 deletions ai/prompts/clubSummary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
export function clubSummaryPrompt(events: any[]) {
return `
You are writing a very short description of what a student club does, based only on their recent events.

You are given a JSON array called "events". All events belong to the **same club**, with a "club" field that contains its name.

### Your task
- Write **2–3 concise sentences** (max **70 words total**) describing:
- What the club focuses on (e.g. hackathons, career prep, mentorship, theory, community building).
- The typical kinds of events they run (talks, workshops, study groups, socials, conferences, etc.).
- The community/audience they serve (e.g. CS undergrads, women in computing, international students, etc.).
- **Start the first sentence with the club name**, taken from the "club" field (e.g. "ACSU is...", "WICC is...").
- Do **not** mention specific dates, rooms, or one‑off logistics; speak in general patterns.
- Keep the tone clear and informative; no emojis.

### Style constraints
- Output **plain text only** (no markdown headings or bullets).
- Use 2–3 sentences in a single short paragraph.

Here are the events for this club (JSON):
\`\`\`json
${JSON.stringify(events, null, 2)}
\`\`\`
`;
}
48 changes: 48 additions & 0 deletions ai/prompts/weeklySummary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
export function weeklySummaryPrompt(events: any[]) {
return `
You are generating a concise weekly opportunities digest for a single student.

You are given a JSON array called "events". Each event may look like:
{
"listserv": "ACSU", // listserv or source that advertised the event
"host": "Cornell AppDev", // primary hosting org or company (may differ from listserv)
"title": "AppDev x Ramp - HACK→HIRED",
"description": "One‑day hackathon with prizes and recruiting",
"date": "2026-03-14",
"location": "eHub",
"tags": ["hackathon", "career", "recruiting"]
}

Important:
- \`listserv\` = who sent/advertised the opportunity (ACSU, WICC, etc.).
- \`host\` = who is actually running the event (AppDev, Ramp, a company, a conference, etc.).
Many events are cross‑posted; do not assume the listserv owns the event.

### Your task
- Write a **compact markdown digest** for this week, **no intro or outro sentences**.
- **Group events by listserv** using markdown headings based on the \`listserv\` field:
- Use a level-3 heading for each listserv that appears, like:
- \`### ACSU\`
- \`### WICC\`
- \`### Cornell\`
- \`### Opportunities\`
- Under each heading, list at most **3 high‑value events** that were advertised on that listserv, chosen for impact (recruiting, hackathons, major talks, strong mentorship/community events).
- For each event, use **one clean bullet point** in this exact format:
- \`- **Title (Mar 14)** – 1‑sentence description that clearly names the **host** or event type, the key value prop, and location if available.\`
- Keep each description **under 25 words**.
- Prefer **hackathons, recruiting, mentorship, and flagship events** over minor or redundant ones.
- If a listserv has more than 3 events, summarize only the top 3 and ignore the rest.

### Style constraints
- Output **markdown only** (no code fences).
- Use only \`###\` headings and \`- \` bullets, nothing else.
- **No emojis, no unsubscribe text, no calendar links, no greetings or sign‑offs.**
- **Total digest <= 220 words** across all sections.

Now write the digest based on this JSON:
\`\`\`json
${JSON.stringify(events, null, 2)}
\`\`\`
`;
}
Loading
Loading