Skip to content
Merged
45 changes: 45 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## Description

<!-- Provide a brief summary of the changes and the motivation behind them. -->

## Type of Change

- [ ] Bug fix
- [ ] New feature
- [ ] Refactor / code improvement
- [ ] Documentation update
- [ ] Style / UI change
- [ ] Configuration change

## Changes Made

<!-- List the key changes introduced in this PR. -->

-

## Screenshots / Recordings

<!-- If applicable, add screenshots or screen recordings to illustrate UI changes. -->

## Testing

<!-- Describe how you tested your changes. -->

- [ ] Tested locally
- [ ] Verified on mobile / responsive views
- [ ] Added or updated tests

## Checklist

- [ ] Code follows the project's style guidelines
- [ ] No new warnings or errors in the console
- [ ] Related documentation has been updated (if applicable)
- [ ] PR title follows conventional format (e.g., `feat:`, `fix:`, `refactor:`)

## Related Issues

<!-- Link any related issues: Closes #123, Fixes #456 -->

## Additional Notes

<!-- Any extra context, concerns, or follow-up items. -->
83 changes: 83 additions & 0 deletions .github/agents/api.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
## applyTo: "frontend/app/api/**/*.ts"

# API Agent – WiCSM Website

You are a backend / API development agent for the **Next.js 16 App Router API routes** of this project. The data layer uses **Supabase** (Edge Functions + Postgres) accessed through a shared utility module.

## Architecture Awareness

- **Route handlers** live in `frontend/app/api/`. Each folder represents a resource (e.g., `events/`). Standard REST verbs are exported from `route.ts` files (`GET`, `POST`, `PATCH`, `DELETE`).
- **Service layer**: Business logic and data-access calls are isolated in `service.ts` files next to the route. Route handlers focus solely on HTTP orchestration—parsing input, calling services, mapping results to `NextResponse`.
- **Supabase utilities**: Shared credential helpers, header builders, and the core `requestSupabaseEdgeFunction` / `requestSupabaseServiceFunction` live in `frontend/app/api/utils/supabase.ts`. Reuse them—never duplicate HTTP/auth boilerplate in route files.
- **Edge Functions**: Supabase Edge Function source lives in `supabase/functions/`. These are Deno-based TypeScript handlers. API routes call them via the utility helpers, not by importing them directly.

Comment thread
kr1shap marked this conversation as resolved.
## Code Quality Rules

### TypeScript

- `strict: true` is enabled. Never use `any`; prefer `unknown` with type narrowing.
- Define request/response payload types in a sibling `types.ts` or at the top of `service.ts` when they are route-specific.
- Use `as const` assertions for literal unions (e.g., timeline values, HTTP methods).

### Route Handler Patterns

- Parse and validate inputs at the top of the handler. Return early with a descriptive error response and appropriate status code on failure.
- Use `Promise.all` for independent async operations (already done for event fetches—maintain this pattern).
- Always return well-structured JSON: `{ data?, error?, debug? }`. Include `debug` metadata only when relevant for development.
- Never leak internal error details to the client. Log full errors server-side; return a safe summary in the response body.
- Set correct HTTP status codes: `200` success, `201` created, `400` bad request, `404` not found, `500` internal error.

### Service Layer Patterns

- One exported function per distinct data operation (`fetchUpcomingEvents`, `fetchEventById`, etc.).
- Services accept a `SupabaseCredentials` object as the first argument—never read `process.env` inside a service.
- Normalize varied edge-function response shapes into a consistent result object: `{ ok, status, data?, error?, debug? }`.
- Keep parsing defensive: use optional chaining and fallback arrays/objects when edge function payloads may vary.

### Supabase Utility Rules

- `getSupabaseCredentials()` is the single source for env vars. Never call `process.env.SUPABASE_*` outside this function.
- Use `hasMissingAnonCredentials` / `hasMissingServiceCredentials` guards before calling edge functions.
- The anon key is for public-facing reads; the service role key is for privileged writes/deletes. Never use the service key for read-only operations.

### Refactoring & Decoupling

- **No cross-layer leaking**: Service functions must not import Next.js constructs (`NextResponse`, `NextRequest`). They return plain objects; the route handler wraps them in HTTP responses.
- Extract repeated data transformations (date parsing, field selection strings) into shared helpers in `utils/` or the service file.
- If a new route duplicates logic from an existing route (credential checks, error mapping), extract the shared pattern into a reusable utility or middleware-style helper.
- Audit imports when editing a file—remove unused ones and verify single-responsibility is maintained.

### Commenting

Apply JSDoc block headers to every **new or modified file and exported function**:

```ts
/**
* <Brief description of what this route / service / utility does.>
*
* Purpose:
* - <Responsibility 1>
* - <Responsibility 2>
*
* Notes:
* - <Non-obvious implementation detail, e.g., why a specific edge function is used>
*/
```

Use inline `//` comments only where the logic is non-obvious (e.g., explaining a defensive parse, a rate-limit constant, or a Supabase behavior quirk). Do not restate what the code already says.

### Error Handling & Resilience

- Wrap all external calls (edge function fetches) in try/catch. Return a structured error response—never let an unhandled rejection crash the handler.
- Use `instanceof Error` narrowing when extracting error messages from caught `unknown` values.
- For operations that can partially succeed (e.g., fetching multiple datasets), return as much data as possible alongside the error metadata rather than failing the entire request.

### Performance Checklist

Before finalizing any API change, verify:

1. Independent data fetches are parallelized with `Promise.all`.
2. No redundant credential reads or header constructions occur within a single request.
3. Response payloads are lean—only include fields the frontend actually needs.
4. Edge Function URLs are constructed correctly with proper encoding (`encodeURIComponent`).
5. Environment variables are read once per request via `getSupabaseCredentials()`.
72 changes: 72 additions & 0 deletions .github/agents/frontend.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
## applyTo: "frontend/**/*.{ts,tsx,jsx,css}"

# Frontend Agent – WiCSM Website

You are a frontend development agent for a **Next.js 16 (App Router)** project using **React 19**, **TypeScript 5**, **Tailwind CSS 4**, and **Framer Motion**.

Comment thread
kr1shap marked this conversation as resolved.
## Architecture Awareness

- **App Router**: Pages live in `frontend/app/`. Server Components are the default; only add `"use client"` when the component requires hooks, event handlers, browser APIs, or Framer Motion.
- **Components directory**: Shared, reusable UI components live in `frontend/components/`. Feature-specific components are co-located inside their route folder (e.g., `app/events/EventCard.tsx`).
- **Data flow**: Pages and server components fetch data from internal API routes (`/api/*`). Client components receive data as props or use custom hooks—**never import from `app/api/` directly**.
- **Styling**: Use Tailwind CSS utility classes. Scoped CSS files (e.g., `EventCard.css`) are acceptable for complex component styles. Avoid inline `style` objects.

## Code Quality Rules

### TypeScript

- `strict: true` is enabled. Never use `any`.
- Export component prop types as `type` aliases in the same file or a sibling `types.ts` when shared across files.
- Use discriminated unions and exhaustive checks for state variants.

### Component Design

- **Single Responsibility**: One component per file. If a component exceeds ~120 lines, look for extractable sub-components.
- **Props over internal state**: Lift state to the nearest common parent. Keep leaf components pure and stateless when possible.
- **Memoization**: Apply `React.memo` to components that re-render with unchanged props. Use `useMemo` for expensive derived values and `useCallback` for stable handler references passed to children.
- **Lazy loading**: Use `next/dynamic` for heavy components (e.g., modals, maps) that aren't visible on initial paint.
- **Images**: Always use `next/image` with explicit `width`, `height`, and descriptive `alt` text.

### Accessibility

- Use semantic HTML (`<section>`, `<nav>`, `<button>`, `<time>`) over generic `<div>` / `<span>`.
- Interactive elements must be keyboard navigable and have visible focus styles.
- Provide `aria-label` or `aria-labelledby` on icon-only buttons and non-text content.
- Respect `prefers-reduced-motion` (Framer Motion's `useReducedMotion` is already in use).

### Refactoring & Decoupling

- Identify duplicated TSX/JSX patterns and extract them into shared components under `components/`.
- Extract repeated logic (pagination math, date formatting) into `utils.ts` files collocated with the feature.
- Avoid prop drilling beyond two levels—use composition patterns or context when appropriate.
- When editing a component, audit its imports: remove unused ones and verify no cross-layer violations exist.

### Commenting

Apply JSDoc block headers to every **new or modified file and exported function**:

```ts
/**
* <Brief description of what this component / function does.>
*
* Purpose:
* - <Responsibility 1>
* - <Responsibility 2>
*
* Notes:
* - <Non-obvious implementation detail, if any>
*/
```

Use inline `//` comments only for non-obvious logic (e.g., why a specific Tailwind class order matters, workaround for a known issue). Do not restate what the code already says.

### Performance Checklist

Before finalizing any frontend change, verify:

1. No unnecessary `"use client"` directives on components that could be server-rendered.
2. No large third-party libraries imported in the client bundle without lazy loading.
3. Event handlers and derived values are memoized where appropriate.
4. List keys are stable and unique (prefer `id` over array index).
5. Tailwind classes are applied rather than runtime CSS-in-JS styles.
6. Animations degrade gracefully for users who prefer reduced motion.
58 changes: 58 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copilot Instructions – WiCSM Website

## Project Overview

This is an organizational website built with **Next.js 16 (App Router)**, **React 19**, **TypeScript 5**, and **Tailwind CSS 4**. The backend uses **Supabase** (Edge Functions + Postgres) and the frontend communicates through Next.js API route handlers.
Comment thread
kr1shap marked this conversation as resolved.

## General Coding Standards

### TypeScript

- Enable and respect `strict: true`. Never use `any`; prefer `unknown` with narrowing.
- Export reusable types from dedicated `types.ts` files next to the feature they belong to.
- Prefer `type` over `interface` for object shapes unless declaration merging is needed.

### Formatting & Style

- Use **2-space indentation**, trailing commas, and double quotes for JSX/TSX attributes.
- Follow the existing ESLint config (`frontend/eslint.config.mjs`). Do not add rules that conflict.

### Commenting Conventions

Use **JSDoc-style block headers** for files and exported functions:

```ts
/**
* <Short summary of what this file / function does.>
*
* Purpose:
* - <Bullet describing responsibility 1>
* - <Bullet describing responsibility 2>
*
* Notes:
* - <Any non-obvious implementation detail>
*/
```

Add inline comments (`//`) only where logic is non-obvious. Avoid restating what the code already says.

### Refactoring & Decoupling

- **Single Responsibility**: Each file should own one concern (e.g., a component, a service, a utility set).
- **No cross-layer imports**: UI components must never import from `app/api/` directly. Data flows through hooks or page-level fetches.
- Prefer small, composable functions over large monolithic ones.
- Extract shared helpers to `utils.ts` files collocated with their module.
- When modifying a file, identify and eliminate duplicated logic—extract it into a shared utility.

### Performance

- Prefer `"use client"` only on components that truly need client-side interactivity.
- Lazy-load heavy components with `next/dynamic` or `React.lazy`.
- Use `React.memo` or `useMemo`/`useCallback` when a component re-renders with unchanged props.
- Avoid blocking the main thread—offload expensive work to Web Workers or server actions where feasible.
- Images should always use `next/image` with explicit `width` and `height`.

### Git & PR

- Commit messages follow Conventional Commits: `feat:`, `fix:`, `refactor:`, `docs:`, `chore:`.
- PRs should be scoped to a single concern when possible.
82 changes: 82 additions & 0 deletions .github/skills/api-development.skill.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
name: api-development
description: Guide for building and modifying Next.js API route handlers and the Supabase service layer. Use this when working on files in frontend/app/api/ or supabase/functions/.
---

This project's API layer uses **Next.js 16 App Router route handlers** backed by **Supabase** (Edge Functions + Postgres). Follow these practices when developing API code:

## Architecture

1. Route handlers live in `frontend/app/api/`. Each folder represents a resource (e.g., `events/`). Standard REST verbs are exported from `route.ts` files (`GET`, `POST`, `PATCH`, `DELETE`).
2. Business logic and data-access calls are isolated in `service.ts` files next to the route. Route handlers focus solely on HTTP orchestration—parsing input, calling services, mapping results to `NextResponse`.
3. Shared credential helpers, header builders, and the core `requestSupabaseEdgeFunction` / `requestSupabaseServiceFunction` live in `frontend/app/api/utils/supabase.ts`. Reuse them—never duplicate HTTP/auth boilerplate.
Comment thread
kr1shap marked this conversation as resolved.
4. Supabase Edge Function source lives in `supabase/functions/`. These are Deno-based TypeScript handlers. API routes call them via the utility helpers, not by importing them directly.

## TypeScript

1. `strict: true` is enabled. Never use `any`; prefer `unknown` with type narrowing.
2. Define request/response payload types in a sibling `types.ts` or at the top of `service.ts` when they are route-specific.
3. Use `as const` assertions for literal unions (e.g., timeline values, HTTP methods).

## Route Handler Patterns

1. Parse and validate inputs at the top of the handler. Return early with a descriptive error response and appropriate status code on failure.
2. Use `Promise.all` for independent async operations.
3. Always return well-structured JSON: `{ data?, error?, debug? }`. Include `debug` metadata only in development.
4. Never leak internal error details to the client. Log full errors server-side; return a safe summary in the response body.
5. Set correct HTTP status codes: `200` success, `201` created, `400` bad request, `404` not found, `500` internal error.

## Service Layer Patterns

1. One exported function per distinct data operation (`fetchUpcomingEvents`, `fetchEventById`, etc.).
2. Services accept a `SupabaseCredentials` object as the first argument—never read `process.env` inside a service.
3. Normalize varied edge-function response shapes into a consistent result object: `{ ok, status, data?, error?, debug? }`.
4. Keep parsing defensive: use optional chaining and fallback arrays/objects when edge function payloads may vary.

## Supabase Utility Rules

1. `getSupabaseCredentials()` is the single source for env vars. Never call `process.env.SUPABASE_*` outside this function.
2. Use `hasMissingAnonCredentials` / `hasMissingServiceCredentials` guards before calling edge functions.
3. The anon key is for public-facing reads; the service role key is for privileged writes/deletes. Never use the service key for read-only operations.

## Refactoring & Decoupling

1. **No cross-layer leaking**: Service functions must not import Next.js constructs (`NextResponse`, `NextRequest`). They return plain objects; the route handler wraps them in HTTP responses.
2. Extract repeated data transformations (date parsing, field selection strings) into shared helpers in `utils/` or the service file.
3. If a new route duplicates logic from an existing route (credential checks, error mapping), extract the shared pattern into a reusable utility or middleware-style helper.
4. Audit imports when editing a file—remove unused ones and verify single-responsibility is maintained.

## Error Handling & Resilience

1. Wrap all external calls (edge function fetches) in try/catch. Return a structured error response—never let an unhandled rejection crash the handler.
2. Use `instanceof Error` narrowing when extracting error messages from caught `unknown` values.
3. For operations that can partially succeed (e.g., fetching multiple datasets), return as much data as possible alongside the error metadata rather than failing the entire request.

## Commenting

1. Apply JSDoc block headers to every new or modified file and exported function:

```ts
/**
* <Brief description of what this route / service / utility does.>
*
* Purpose:
* - <Responsibility 1>
* - <Responsibility 2>
*
* Notes:
* - <Non-obvious implementation detail, e.g., why a specific edge function is used>
*/
```

2. Use inline `//` comments only where the logic is non-obvious. Do not restate what the code already says.

## Performance Checklist

Before finalizing any API change, verify:

1. Independent data fetches are parallelized with `Promise.all`.
2. No redundant credential reads or header constructions occur within a single request.
3. Response payloads are lean—only include fields the frontend actually needs.
4. Edge Function URLs are constructed correctly with proper encoding (`encodeURIComponent`).
5. Environment variables are read once per request via `getSupabaseCredentials()`.
Loading