From 7037362b406f3b525755bc577d3f80b1b44c0696 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sun, 1 Mar 2026 05:35:46 +0100 Subject: [PATCH] Update docs --- .aiassistant/rules/guidelines.md | 12 +- .github/copilot-instructions.md | 12 +- .junie/guidelines.md | 12 +- CONTRIBUTING.md | 531 ++++++++++++++++++++++++++----- backend/api/README.md | 459 +++++++++++++++++++++++--- docs/TESTING.md | 15 +- docs/architecture.md | 385 ++++++++++++++++++++++ web/README.md | 356 ++++++++++++++++++++- 8 files changed, 1620 insertions(+), 162 deletions(-) create mode 100644 docs/architecture.md diff --git a/.aiassistant/rules/guidelines.md b/.aiassistant/rules/guidelines.md index 4ef3b760..766db60b 100644 --- a/.aiassistant/rules/guidelines.md +++ b/.aiassistant/rules/guidelines.md @@ -520,7 +520,7 @@ What testing is not How we apply it here -- Unit and integration tests live in each package and run with Jest (see `jest.config.js`). +- Unit and integration tests live in each package and run with Jest (see `jest.config.ts`). - Critical user journeys are covered by Playwright E2E tests under `tests/e2e` (see `playwright.config.ts`). ### Test types at a glance @@ -528,18 +528,20 @@ How we apply it here This project uses three complementary test types. Use the right level for the job: - Unit tests + - Purpose: Verify a single function/module in isolation; fast, deterministic. - Where: Each package under `tests/unit` (e.g., `backend/api/tests/unit`, `web/tests/unit`, `common/tests/unit`, etc.). - - Runner: Jest (configured via root `jest.config.js`). + - Runner: Jest (configured via root `jest.config.ts`). - Naming: `*.unit.test.ts` (or `.tsx` for React in `web`). - When to use: Pure logic, utilities, hooks, reducers, small components with mocked dependencies. - Integration tests + - Purpose: Verify multiple units working together (e.g., function + DB/client, component + context/provider) without spinning up the full app. - Where: Each package under `tests/integration` (e.g., `backend/shared/tests/integration`, `web/tests/integration`). - - Runner: Jest (configured via root `jest.config.js`). + - Runner: Jest (configured via root `jest.config.ts`). - Naming: `*.integration.test.ts` (or `.tsx` for React in `web`). - When to use: Boundaries between modules, real serialization/parsing, API handlers with mocked network/DB, component trees with providers. @@ -565,7 +567,7 @@ yarn test:e2e ```filetree # Config -jest.config.js (for unit and integration tests) +jest.config.ts (for unit and integration tests) playwright.config.ts (for e2e tests) # Top-level End-to-End (Playwright) @@ -617,7 +619,7 @@ web/ - End-to-End tests live under `tests/e2e` and are executed by Playwright. The root `playwright.config.ts` sets `testDir` to `./tests/e2e`. - Unit and integration tests live in each package’s `tests` folder and are executed by Jest via the root - `jest.config.js` projects array. + `jest.config.ts` projects array. - Naming: - Unit: `*.unit.test.ts` (or `.tsx` for React in `web`) - Integration: `*.integration.test.ts` diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index e6f75f32..c9967d72 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -514,7 +514,7 @@ What testing is not How we apply it here -- Unit and integration tests live in each package and run with Jest (see `jest.config.js`). +- Unit and integration tests live in each package and run with Jest (see `jest.config.ts`). - Critical user journeys are covered by Playwright E2E tests under `tests/e2e` (see `playwright.config.ts`). ### Test types at a glance @@ -522,18 +522,20 @@ How we apply it here This project uses three complementary test types. Use the right level for the job: - Unit tests + - Purpose: Verify a single function/module in isolation; fast, deterministic. - Where: Each package under `tests/unit` (e.g., `backend/api/tests/unit`, `web/tests/unit`, `common/tests/unit`, etc.). - - Runner: Jest (configured via root `jest.config.js`). + - Runner: Jest (configured via root `jest.config.ts`). - Naming: `*.unit.test.ts` (or `.tsx` for React in `web`). - When to use: Pure logic, utilities, hooks, reducers, small components with mocked dependencies. - Integration tests + - Purpose: Verify multiple units working together (e.g., function + DB/client, component + context/provider) without spinning up the full app. - Where: Each package under `tests/integration` (e.g., `backend/shared/tests/integration`, `web/tests/integration`). - - Runner: Jest (configured via root `jest.config.js`). + - Runner: Jest (configured via root `jest.config.ts`). - Naming: `*.integration.test.ts` (or `.tsx` for React in `web`). - When to use: Boundaries between modules, real serialization/parsing, API handlers with mocked network/DB, component trees with providers. @@ -559,7 +561,7 @@ yarn test:e2e ```filetree # Config -jest.config.js (for unit and integration tests) +jest.config.ts (for unit and integration tests) playwright.config.ts (for e2e tests) # Top-level End-to-End (Playwright) @@ -611,7 +613,7 @@ web/ - End-to-End tests live under `tests/e2e` and are executed by Playwright. The root `playwright.config.ts` sets `testDir` to `./tests/e2e`. - Unit and integration tests live in each package’s `tests` folder and are executed by Jest via the root - `jest.config.js` projects array. + `jest.config.ts` projects array. - Naming: - Unit: `*.unit.test.ts` (or `.tsx` for React in `web`) - Integration: `*.integration.test.ts` diff --git a/.junie/guidelines.md b/.junie/guidelines.md index e6f75f32..c9967d72 100644 --- a/.junie/guidelines.md +++ b/.junie/guidelines.md @@ -514,7 +514,7 @@ What testing is not How we apply it here -- Unit and integration tests live in each package and run with Jest (see `jest.config.js`). +- Unit and integration tests live in each package and run with Jest (see `jest.config.ts`). - Critical user journeys are covered by Playwright E2E tests under `tests/e2e` (see `playwright.config.ts`). ### Test types at a glance @@ -522,18 +522,20 @@ How we apply it here This project uses three complementary test types. Use the right level for the job: - Unit tests + - Purpose: Verify a single function/module in isolation; fast, deterministic. - Where: Each package under `tests/unit` (e.g., `backend/api/tests/unit`, `web/tests/unit`, `common/tests/unit`, etc.). - - Runner: Jest (configured via root `jest.config.js`). + - Runner: Jest (configured via root `jest.config.ts`). - Naming: `*.unit.test.ts` (or `.tsx` for React in `web`). - When to use: Pure logic, utilities, hooks, reducers, small components with mocked dependencies. - Integration tests + - Purpose: Verify multiple units working together (e.g., function + DB/client, component + context/provider) without spinning up the full app. - Where: Each package under `tests/integration` (e.g., `backend/shared/tests/integration`, `web/tests/integration`). - - Runner: Jest (configured via root `jest.config.js`). + - Runner: Jest (configured via root `jest.config.ts`). - Naming: `*.integration.test.ts` (or `.tsx` for React in `web`). - When to use: Boundaries between modules, real serialization/parsing, API handlers with mocked network/DB, component trees with providers. @@ -559,7 +561,7 @@ yarn test:e2e ```filetree # Config -jest.config.js (for unit and integration tests) +jest.config.ts (for unit and integration tests) playwright.config.ts (for e2e tests) # Top-level End-to-End (Playwright) @@ -611,7 +613,7 @@ web/ - End-to-End tests live under `tests/e2e` and are executed by Playwright. The root `playwright.config.ts` sets `testDir` to `./tests/e2e`. - Unit and integration tests live in each package’s `tests` folder and are executed by Jest via the root - `jest.config.js` projects array. + `jest.config.ts` projects array. - Naming: - Unit: `*.unit.test.ts` (or `.tsx` for React in `web`) - Integration: `*.integration.test.ts` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b33229d7..a929df18 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,128 +1,491 @@ -# Contributing to This Repository +# Contributing to Compass -We welcome pull requests, but only if they meet the project's quality and design standards. Follow the process below precisely to avoid wasting time—yours or ours. +Thank you for your interest in contributing to Compass! This document provides comprehensive guidelines for contributing to this open-source project. -## Prerequisites +## Table of Contents -- Familiarity with Git and GitHub (basic commands, branching, forking, etc.) -- A functioning development environment -- Node.js, Python, or other relevant runtime/tools installed (check the `README.md`) -- Read the [Development Documentation](docs/development.md) for project-specific setup and guidelines (adding languages, - profile fields, etc.) +- [Code of Conduct](#code-of-conduct) +- [Getting Started](#getting-started) +- [Development Environment](#development-environment) +- [Project Structure](#project-structure) +- [Coding Standards](#coding-standards) +- [Making Changes](#making-changes) +- [Testing](#testing) +- [Pull Request Guidelines](#pull-request-guidelines) +- [Commit Message Guidelines](#commit-message-guidelines) +- [Documentation](#documentation) +- [Questions and Support](#questions-and-support) -## Fork & Clone +## Code of Conduct -1. **Fork the repository** using the GitHub UI. -2. **Clone your fork** locally: +Please read and follow our [Code of Conduct](./CODE_OF_CONDUCT.md). We are committed to providing a welcoming and inclusive environment for all contributors. +## Getting Started + +### Prerequisites + +Before contributing, ensure you have the following installed: + +- **Node.js** 20.x or later +- **Yarn** 1.x (classic) +- **Git** +- **Docker** (optional, for isolated development) + +### Fork and Clone + +1. Fork the [repository](https://github.com/CompassConnections/Compass) on GitHub +2. Clone your fork: ```bash - git clone https://github.com/your-username/Compass.git - cd your-fork - + git clone https://github.com//Compass.git + cd Compass ``` - -3. **Add the upstream remote**: - +3. Add the upstream remote: ```bash git remote add upstream https://github.com/CompassConnections/Compass.git ``` -## Create a New Branch - -Never work on `main` or `master`. +### Install Dependencies ```bash -git checkout -b fix/brief-but-specific-description +yarn install --frozen-lockfile ``` -Use a clear, descriptive branch name. Avoid vague names like `patch-1`. +## Development Environment -## Stay Updated - -Before you start, make sure your fork is up to date: +### Running the Development Server ```bash -git fetch upstream -git checkout main -git merge upstream/main +yarn dev ``` -Then rebase your feature branch if needed: +Visit http://localhost:3000 to see the application. + +### Isolated Development (Recommended) + +For full isolation with local Supabase and Firebase emulators: ```bash -git checkout fix/your-feature -git rebase main +yarn dev:isolated ``` -## Make Atomic Commits +Benefits: -Each commit should represent a single logical change. Follow this format: +- No conflicts with other contributors +- Works offline +- Faster database queries +- Free to reset and reseed data -```text -type(scope): concise description +Requirements: -body explaining what and why, if necessary +- Docker (~500MB) +- Supabase CLI +- Java 21+ (for Firebase emulators) +- Firebase CLI + +See the [README](./README.md) for detailed setup instructions. + +### Running Tests + +```bash +# Run all tests +yarn test + +# Run tests with coverage +yarn test:coverage + +# Run tests in watch mode +yarn test:watch + +# Run E2E tests +yarn test:e2e ``` +### Linting and Type Checking + +```bash +# Lint all packages +yarn lint + +# Fix linting issues +yarn lint-fix + +# Type check all packages +yarn typecheck +``` + +## Project Structure + +This is a Yarn workspaces monorepo with the following packages: + +``` +Compass/ +├── web/ # Next.js web application +│ ├── components/ # React components +│ ├── hooks/ # Custom React hooks +│ ├── lib/ # Utilities and services +│ ├── pages/ # Next.js pages +│ └── messages/ # Internationalization files +├── backend/ +│ ├── api/ # Express API server +│ ├── shared/ # Shared backend utilities +│ ├── email/ # React email templates +│ └── scripts/ # Database migration scripts +├── common/ # Shared TypeScript types and utilities +├── supabase/ # Database migrations and config +├── android/ # Capacitor Android app +└── docs/ # Project documentation +``` + +### Key Technologies + +| Layer | Technology | +| -------- | -------------------------------- | +| Frontend | Next.js 14, React 18, TypeScript | +| Styling | Tailwind CSS | +| Backend | Express.js, Node.js | +| Database | PostgreSQL (Supabase) | +| Auth | Firebase Auth | +| Storage | Firebase Storage | +| Mobile | Capacitor (Android) | +| Testing | Jest, Playwright | + +## Coding Standards + +### TypeScript + +- Use strict TypeScript typing +- Avoid `any` type; use `unknown` when necessary +- Prefer interfaces over types for object shapes +- Use `const` assertions where appropriate + +### React Components + +- Use functional components with hooks +- Name components after their file name +- Export primary component at the top of the file +- Use composition over inheritance +- Keep components small and focused + +Example component structure: + +```tsx +import clsx from 'clsx' +import {useState} from 'react' + +interface ProfileCardProps { + name: string + age: number + onSelect?: (id: string) => void + className?: string +} + +export function ProfileCard({name, age, onSelect, className}: ProfileCardProps) { + const [selected, setSelected] = useState(false) + + const handleClick = () => { + setSelected(!selected) + onSelect?.(name) + } + + return ( +
+

+ {name}, {age} +

+ +
+ ) +} +``` + +### Naming Conventions + +- **Files**: kebab-case (`profile-card.tsx`) +- **Components**: PascalCase (`ProfileCard`) +- **Hooks**: camelCase with `use` prefix (`useUserProfile`) +- **Constants**: SCREAMING_SNAKE_CASE +- **Types/Interfaces**: PascalCase + +### Import Order + +Run `yarn lint-fix` to automatically sort imports: + +1. External libraries (React, Next.js, etc.) +2. Internal packages (`common/`, `shared/`) +3. Relative imports (`../`, `./`) +4. Type imports + +### Error Handling + +- Use try-catch for async operations +- Create custom error types for API errors +- Implement error boundaries for React components +- Log errors with appropriate context + Example: +```typescript +import {APIError} from './errors' + +try { + const result = await api('endpoint', params) + return result +} catch (err) { + if (err instanceof APIError) { + logger.error('API error', {status: err.status, message: err.message}) + } else { + logger.error('Unexpected error', err) + } + throw err +} +``` + +### Accessibility + +- Use semantic HTML elements +- Include ARIA labels where appropriate +- Ensure keyboard navigation works +- Use the `SkipLink` component for main content +- Announce dynamic content changes with `useLiveRegion` + +```tsx +import {useLiveRegion} from 'web/components/live-region' + +function MyComponent() { + const {announce} = useLiveRegion() + + const handleAction = () => { + // Action completed + announce('Action successful', 'polite') + } +} +``` + +## Making Changes + +### Creating a Branch + +Never work directly on `main`. Create a new branch: + +```bash +git checkout -b type/short-description +``` + +Branch types: + +- `feat/` - New features +- `fix/` - Bug fixes +- `docs/` - Documentation +- `refactor/` - Code refactoring +- `test/` - Adding/updating tests +- `chore/` - Maintenance tasks + +### Making Commits + +Keep commits atomic and descriptive: + +```bash +git add . +git commit -m "feat(profiles): add compatibility score display + +- Added compatibility score calculation +- Display score on profile cards +- Added tests for scoring algorithm" +``` + +See [Commit Message Guidelines](#commit-message-guidelines) for details. + +### Keeping Your Fork Updated + +```bash +# Fetch latest from upstream +git fetch upstream + +# Update main branch +git checkout main +git merge upstream/main + +# Rebase your feature branch +git checkout feat/your-feature +git rebase main +``` + +## Testing + +### Writing Tests + +#### Unit Tests + +Place tests in `tests/unit/` within each package: + +```typescript +// web/tests/unit/my-function.test.ts +import {myFunction} from '../my-function' + +describe('myFunction', () => { + it('should return correct output', () => { + expect(myFunction('input')).toBe('expected') + }) +}) +``` + +#### Integration Tests + +Place in `tests/integration/`: + +```typescript +// web/tests/integration/api.test.ts +import {render, screen} from '@testing-library/react' +import {MyComponent} from '../MyComponent' + +describe('MyComponent', () => { + it('renders correctly', () => { + render() + expect(screen.getByText('Hello')).toBeInTheDocument() + }) +}) +``` + +#### E2E Tests + +Place in `tests/e2e/` at the root: + +```typescript +// tests/e2e/web/specs/onboarding.spec.ts +import {test, expect} from '@playwright/test' + +test('onboarding flow', async ({page}) => { + await page.goto('/signup') + await page.fill('[name="email"]', 'test@example.com') + await page.click('button[type="submit"]') + await expect(page).toHaveURL('/onboarding') +}) +``` + +### Running Specific Tests + +```bash +# Run unit tests for web +yarn workspace web test + +# Run tests matching pattern +yarn test --testPathPattern="profile" + +# Run E2E tests +yarn test:e2e +``` + +### Test Coverage + +Aim for meaningful test coverage. Focus on: + +- Business logic +- User interactions +- Error handling +- Edge cases + +## Pull Request Guidelines + +### Before Submitting + +1. **Run all tests**: `yarn test` +2. **Run linter**: `yarn lint` +3. **Run type check**: `yarn typecheck` +4. **Update documentation** if needed +5. **Rebase on main** if necessary + +### Pull Request Format + +**Title**: Clear, descriptive title + +**Description**: + +```markdown +## Summary + +Brief description of changes + +## Changes + +- Added compatibility score to profile cards +- Updated search algorithm for better results + +## Testing + +- Added unit tests for scoring algorithm +- Tested manually with synthetic data + +## Screenshots (if UI changes) +``` + +### PR Checklist + +- [ ] Code follows style guidelines +- [ ] Tests added/updated and passing +- [ ] Documentation updated +- [ ] No console.log statements (except debugging) +- [ ] No debug code left behind + +### Review Process + +1. Maintainers review within 48 hours +2. Address feedback promptly +3. Do not open new PRs for changes - update existing one +4. Squash commits before merging + +## Commit Message Guidelines + +Follow [Conventional Commits](https://www.conventionalcommits.org/): + +``` +(): + +[optional body] + +[optional footer] +``` + +### Types + +- `feat`: New feature +- `fix`: Bug fix +- `docs`: Documentation +- `style`: Formatting +- `refactor`: Code restructuring +- `test`: Tests +- `chore`: Maintenance + +### Examples + ```text -fix(api): handle 500 error on invalid payload +feat(profiles): add compatibility scoring algorithm +fix(api): handle rate limiting gracefully +docs(readme): update installation instructions +refactor(auth): simplify token refresh logic +test(profiles): add unit tests for scoring ``` -Types include: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`. +## Documentation -## Test Everything +### Updating Documentation -If the project has tests, run them. If it doesn’t, write some. Do **not** submit code that hasn't been tested. +- Update relevant README files +- Add JSDoc comments to complex functions +- Update the `/docs` folder for architectural changes -```bash -# Example for Node.js -npm test -``` +### API Documentation -No exceptions. If you don't validate your changes, your PR will be closed. +API docs are auto-generated and available at: -## Lint & Format +- Production: https://api.compassmeet.com +- Local: http://localhost:3001 (when running locally) -Ensure code matches the project style. If the repo uses a linter or formatter, run them: +## Questions and Support -```bash -npm run lint -npm run format -``` +- **Discord**: https://discord.gg/8Vd7jzqjun +- **Email**: hello@compassmeet.com +- **GitHub Issues**: For bug reports and feature requests -Or whatever command is defined in the repo. +--- -## Write a Good Pull Request - -When opening a pull request: - -- **Title**: Describe what the PR does, clearly and specifically. -- **Description**: Explain the context. Link related issues (use `Fixes #123` if applicable). -- **Checklist**: - - [ ] My code is clean and follows the style guide - - [ ] I’ve added or updated tests - - [ ] I’ve run all tests and they pass - - [ ] I’ve documented my changes (if necessary) - -## Code Review Process - -- PRs are reviewed by maintainers or core contributors. -- If feedback is given, respond and push updates. Do **not** open new PRs for changes to an existing one. -- PRs that are incomplete, sloppy, or violate the above will be closed. - -## Don't Do This - -- Don’t commit directly to `main` -- Don’t submit multiple unrelated changes in a single PR -- Don’t ignore CI/test failures -- Don’t expect hand-holding—read the docs and the source first - -## Security Issues - -Do **not** open public issues for security vulnerabilities. Email the development team instead. - -## License - -By contributing, you agree that your code will be licensed under the same license as the rest of the project. +Thank you for contributing to Compass! Together we're building a platform for meaningful connections. diff --git a/backend/api/README.md b/backend/api/README.md index c2b91dba..604a179c 100644 --- a/backend/api/README.md +++ b/backend/api/README.md @@ -1,11 +1,67 @@ # Backend API -This is the code for the API running at https://api.compassmeet.com. -It runs in a docker inside a Google Cloud virtual machine. +Express.js REST API for Compass, running at https://api.compassmeet.com. -### Requirements +## Overview -You must have the `gcloud` CLI. +The API handles: + +- User authentication and management +- Profile CRUD operations +- Search and filtering +- Messaging +- Notifications +- Compatibility scoring +- Events management +- WebSocket connections for real-time features + +## Tech Stack + +- **Runtime**: Node.js 20+ +- **Framework**: Express.js 5.0 +- **Language**: TypeScript +- **Database**: PostgreSQL (via Supabase) +- **ORM**: pg-promise +- **Validation**: Zod +- **WebSocket**: ws library +- **API Docs**: Swagger/OpenAPI + +## Project Structure + +``` +backend/api/ +├── src/ +│ ├── app.ts # Express app setup +│ ├── routes.ts # Route definitions +│ ├── test.ts # Test utilities +│ ├── get-*.ts # GET endpoints +│ ├── create-*.ts # POST endpoints +│ ├── update-*.ts # PUT/PATCH endpoints +│ ├── delete-*.ts # DELETE endpoints +│ └── helpers/ # Shared utilities +├── tests/ +│ └── unit/ # Unit tests +├── package.json +├── tsconfig.json +└── README.md +``` + +## Getting Started + +### Prerequisites + +- Node.js 20.x or later +- Yarn +- Access to Supabase project (for database) + +### Installation + +```bash +# From root directory +yarn install +``` + +You must also have the `gcloud` CLI. On macOS: @@ -35,6 +91,356 @@ You also need `opentofu` and `docker`. Try running this (from root) on Linux or If it doesn't work, you can install them manually (google how to install `opentofu` and `docker` for your OS). +### Running Locally + +```bash +# Run all services (web + API) +yarn dev + +# Run API only (from backend/api) +cd backend/api +yarn serve +``` + +The API runs on http://localhost:3001 when running locally with the full stack. + +### Testing + +```bash +# Run unit tests +yarn test + +# Run with coverage +yarn test --coverage +``` + +### Linting + +```bash +# Check lint +yarn lint + +# Fix issues +yarn lint-fix +``` + +## API Endpoints + +### Authentication + +| Method | Endpoint | Description | +| ------ | ------------------- | --------------- | +| POST | `/auth/google` | Google Sign-In | +| POST | `/auth/create-user` | Create new user | + +### Users + +| Method | Endpoint | Description | +| ------ | ------------ | ------------------- | +| GET | `/get-me` | Get current user | +| PUT | `/update-me` | Update current user | +| DELETE | `/delete-me` | Delete account | + +### Profiles + +| Method | Endpoint | Description | +| ------ | ----------------- | ------------------ | +| GET | `/get-profiles` | List profiles | +| GET | `/get-profile` | Get single profile | +| POST | `/create-profile` | Create profile | +| PUT | `/update-profile` | Update profile | +| DELETE | `/delete-profile` | Delete profile | + +### Messaging + +| Method | Endpoint | Description | +| ------ | ------------------------------ | -------------- | +| GET | `/get-private-messages` | Get messages | +| POST | `/create-private-user-message` | Send message | +| PUT | `/edit-message` | Edit message | +| DELETE | `/delete-message` | Delete message | + +### Notifications + +| Method | Endpoint | Description | +| ------ | ----------------------- | ------------------ | +| GET | `/get-notifications` | List notifications | +| PUT | `/update-notif-setting` | Update settings | + +### Search + +| Method | Endpoint | Description | +| ------ | ------------------ | ------------------ | +| GET | `/search-users` | Search users | +| GET | `/search-location` | Search by location | + +### Compatibility + +| Method | Endpoint | Description | +| ------ | ------------------------------ | ----------------------- | +| GET | `/get-compatibility-questions` | List questions | +| POST | `/set-compatibility-answers` | Submit answers | +| GET | `/compatible-profiles` | Get compatible profiles | + +## Writing Endpoints + +### 1. Define Schema + +Add endpoint definition in `common/src/api/schema.ts`: + +```typescript +myEndpoint: { + method: 'POST', + authed +: + true, + returns +: + z.object({ + success: z.boolean(), + data: z.any() + }), + props +: + z.object({ + userId: z.string(), + option: z.string().optional() + }).strict() +} +``` + +### 2. Implement Handler + +Create handler file in `backend/api/src/`: + +```typescript +import {z} from 'zod' +import {APIHandler} from './helpers/endpoint' + +export const myEndpoint: APIHandler<'myEndpoint'> = async (props, auth) => { + const {userId, option} = props + + // Implementation + return { + success: true, + data: {userId}, + } +} +``` + +### 3. Register Route + +Add to `routes.ts`: + +```typescript +import {myEndpoint} from './my-endpoint' + +const handlers = { + myEndpoint, + // ... +} +``` + +## Authentication + +### Authenticated Endpoints + +Use the `authed: true` schema property. The auth object is passed to the handler: + +```typescript +export const getProfile: APIHandler<'get-profile'> = async (props, auth) => { + // auth.uid - user ID + // auth.creds - credentials type +} +``` + +### Auth Types + +- `firebase` - Firebase Auth token +- `session` - Session-based auth + +## Database Access + +### Using pg-promise + +```typescript +import {createSupabaseDirectClient} from 'shared/supabase/init' + +const pg = createSupabaseDirectClient() + +const result = await pg.oneOrNone('SELECT * FROM users WHERE id = $1', [userId]) +``` + +### Using Supabase Client + +```typescript +import {db} from 'web/lib/supabase/db' + +const {data, error} = await db.from('profiles').select('*').eq('user_id', userId) +``` + +## Rate Limiting + +The API includes built-in rate limiting: + +```typescript +export const myEndpoint: APIHandler<'myEndpoint'> = withRateLimit( + async (props, auth) => { + // Handler implementation + }, + { + name: 'my-endpoint', + limit: 100, + windowMs: 60 * 1000, // 1 minute + }, +) +``` + +## Error Handling + +Use `APIError` for consistent error responses: + +```typescript +import {APIError} from './helpers/endpoint' + +throw APIError(404, 'User not found') +throw APIError(400, 'Invalid input', {field: 'email'}) +``` + +Error codes: + +- `400` - Bad Request +- `401` - Unauthorized +- `403` - Forbidden +- `404` - Not Found +- `429` - Too Many Requests +- `500` - Internal Server Error + +## WebSocket + +WebSocket connections are handled for real-time features: + +```typescript +// Subscribe to updates +ws.subscribe('user/123', (data) => { + console.log('User updated:', data) +}) + +// Unsubscribe +ws.unsubscribe('user/123', callback) +``` + +Available topics: + +- `user/{userId}` - User updates +- `private-user/{userId}` - Private user updates +- `message/{channelId}` - New messages + +## Logging + +Use the shared logger: + +```typescript +import {log} from 'shared/monitoring/log' + +log.info('Processing request', {userId: auth.uid}) +log.error('Failed to process', error) +``` + +## Deployment + +### Production Deployment + +Deployments are automated via GitHub Actions. Push to main triggers deployment: + +```bash +# Increment version +# Update package.json version +git add package.json +git commit -m "chore: bump version" +git push origin main +``` + +### Manual Deployment + +```bash +cd backend/api +./deploy-api.sh prod +``` + +### Server Access + +Run in this directory to connect to the API server running as virtual machine in Google Cloud. You can access logs, +files, debug, etc. + +```bash +# SSH into production server +cd backend/api +./ssh-api.sh prod +``` + +Useful commands on server: + +```bash +sudo journalctl -u konlet-startup --no-pager -ef # View logs +sudo docker logs -f $(sudo docker ps -alq) # Container logs +docker exec -it $(sudo docker ps -alq) sh # Shell access +docker run -it --rm $(docker images -q | head -n 1) sh +docker rmi -f $(docker images -aq) +``` + +## Environment Variables + +Required secrets (set in Google Cloud Secrets Manager): + +| Variable | Description | +| ---------------------- | ---------------------------- | +| `DATABASE_URL` | PostgreSQL connection string | +| `FIREBASE_PROJECT_ID` | Firebase project ID | +| `FIREBASE_PRIVATE_KEY` | Firebase private key | +| `SUPABASE_SERVICE_KEY` | Supabase service role key | +| `JWT_SECRET` | JWT signing secret | + +## Testing + +### Writing Unit Tests + +```typescript +// tests/unit/my-endpoint.unit.test.ts +import {myEndpoint} from '../my-endpoint' + +describe('myEndpoint', () => { + it('should return success', async () => { + const result = await myEndpoint({userId: '123'}, mockAuth) + expect(result.success).toBe(true) + }) +}) +``` + +### Mocking Database + +```typescript +const mockPg = { + oneOrNone: jest.fn().mockResolvedValue({id: '123'}), +} +``` + +## API Documentation + +Full API docs available at: + +- Production: https://api.compassmeet.com +- Local: http://localhost:8088 (when running) + +Docs are generated from route definitions in `app.ts`. + +## See Also + +- [Main README](../../README.md) +- [Contributing Guide](../../CONTRIBUTING.md) +- [Shared Backend Utils](../shared/README.md) +- [Database Migrations](../../supabase/migrations) + ### Setup This section is only for the people who are creating a server from scratch, for instance for a forked project. @@ -155,48 +561,3 @@ in [Google Cloud Secrets manager](https://console.cloud.google.com/security/secr can access them. For Compass, the name of the secrets are in [secrets.ts](../../common/src/secrets.ts). - -### Run Locally - -In root directory, run the local api with hot reload, along with all the other backend and web code. - -```bash -./run_local.sh prod -``` - -### Deploy - -To deploy the backend code, simply increment the version number in [package.json](package.json) and push to the `main` branch. - -Or if you have access to the project on google cloud, run in this directory: - -```bash -./deploy-api.sh prod -``` - -### Connect to the server - -Run in this directory to connect to the API server running as virtual machine in Google Cloud. You can access logs, -files, debug, etc. - -```bash -./ssh-api.sh prod -``` - -Useful commands once inside the server: - -```bash -sudo journalctl -u konlet-startup --no-pager -efb -sudo docker logs -f $(sudo docker ps -alq) -docker exec -it $(sudo docker ps -alq) sh -docker run -it --rm $(docker images -q | head -n 1) sh -docker rmi -f $(docker images -aq) -``` - -### Documentation - -The API doc is available at https://api.compassmeet.com. It's dynamically prepared in [app.ts](src/app.ts). - -### Todo (Tests) - -- [ ] Finish get-supabase-token unit test when endpoint is implemented diff --git a/docs/TESTING.md b/docs/TESTING.md index 08bf5645..f1895eb4 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -17,7 +17,7 @@ What testing is not How we apply it here -- Unit and integration tests live in each package and run with Jest (see `jest.config.js`). +- Unit and integration tests live in each package and run with Jest (see `jest.config.ts`). - Critical user journeys are covered by Playwright E2E tests under `tests/e2e` (see `playwright.config.ts`). ### Test types at a glance @@ -25,18 +25,20 @@ How we apply it here This project uses three complementary test types. Use the right level for the job: - Unit tests + - Purpose: Verify a single function/module in isolation; fast, deterministic. - Where: Each package under `tests/unit` (e.g., `backend/api/tests/unit`, `web/tests/unit`, `common/tests/unit`, etc.). - - Runner: Jest (configured via root `jest.config.js`). + - Runner: Jest (configured via root `jest.config.ts`). - Naming: `*.unit.test.ts` (or `.tsx` for React in `web`). - When to use: Pure logic, utilities, hooks, reducers, small components with mocked dependencies. - Integration tests + - Purpose: Verify multiple units working together (e.g., function + DB/client, component + context/provider) without spinning up the full app. - Where: Each package under `tests/integration` (e.g., `backend/shared/tests/integration`, `web/tests/integration`). - - Runner: Jest (configured via root `jest.config.js`). + - Runner: Jest (configured via root `jest.config.ts`). - Naming: `*.integration.test.ts` (or `.tsx` for React in `web`). - When to use: Boundaries between modules, real serialization/parsing, API handlers with mocked network/DB, component trees with providers. @@ -62,7 +64,7 @@ yarn test:e2e ```filetree # Config -jest.config.js (for unit and integration tests) +jest.config.ts (for unit and integration tests) playwright.config.ts (for e2e tests) # Top-level End-to-End (Playwright) @@ -114,7 +116,7 @@ web/ - End-to-End tests live under `tests/e2e` and are executed by Playwright. The root `playwright.config.ts` sets `testDir` to `./tests/e2e`. - Unit and integration tests live in each package’s `tests` folder and are executed by Jest via the root - `jest.config.js` projects array. + `jest.config.ts` projects array. - Naming: - Unit: `*.unit.test.ts` (or `.tsx` for React in `web`) - Integration: `*.integration.test.ts` @@ -348,7 +350,6 @@ jest.mock('path/to/module') * This creates an object containing all named exports from ./path/to/module */ import * as mockModule from 'path/to/module' - ;(mockModule.module as jest.Mock).mockResolvedValue(mockReturnValue) ``` @@ -756,7 +757,7 @@ Firebase emulator supports multiple projects. You can spin up isolated project I too slow): ```js -// jest.config.js - per worker +// jest.config.ts - per worker projectId: `test-${process.env.JEST_WORKER_ID}` ``` diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 00000000..7e106859 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,385 @@ +# Architecture Documentation + +> [!WARNING] +> This document is a work in progress. Please help us improve it! + +## System Overview + +Compass is a monorepo containing a Next.js web application, Express API server, Capacitor Android app, and shared packages. The platform is designed for forming deep, authentic 1-on-1 connections. + +## High-Level Architecture + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Users │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Vercel (Frontend) │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ +│ │ Next.js │ │ Static │ │ API Routes │ │ +│ │ Web App │ │ Assets │ │ (Serverless) │ │ +│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ + │ HTTPS + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Google Cloud Platform (Backend) │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ +│ │ Express │ │ WebSocket │ │ Docker Container │ │ +│ │ API │ │ Server │ │ │ │ +│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ + │ Connection + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Supabase (PostgreSQL) │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ +│ │ Database │ │ Edge │ │ Realtime │ │ +│ │ (Postgres)│ │ Functions │ │ Subscriptions │ │ +│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Firebase │ +│ ┌─────────────┐ ┌─────────────┐ │ +│ │ Auth │ │ Storage │ │ +│ └─────────────┘ └─────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Monorepo Structure + +``` +Compass/ +├── web/ # Next.js web application +│ ├── components/ # React components +│ ├── hooks/ # Custom React hooks +│ ├── lib/ # Utilities & services +│ ├── pages/ # Next.js pages +│ ├── messages/ # i18n translations +│ └── tests/ # Unit & integration tests +│ +├── backend/ +│ ├── api/ # Express REST API +│ │ ├── src/ # Handler implementations +│ │ └── tests/ # Unit tests +│ ├── shared/ # Shared backend utilities +│ │ ├── src/ +│ │ │ ├── supabase/ # Database utilities +│ │ │ ├── monitoring/ # Logging +│ │ │ └── mobile/ # Push notifications +│ │ └── tests/ +│ ├── email/ # React email templates +│ └── scripts/ # Database migrations +│ +├── common/ # Shared types & utilities +│ └── src/ +│ ├── types/ # TypeScript definitions +│ ├── api/ # API schema definitions +│ └── constants/ # App constants +│ +├── supabase/ # Database migrations +│ └── migrations/ +│ +├── android/ # Capacitor Android app +│ +└── tests/ # E2E tests (Playwright) + └── e2e/ +``` + +## Technology Stack + +### Frontend (web) + +| Category | Technology | Version | +| ---------- | --------------------- | ------- | +| Framework | Next.js | 14.1.0 | +| UI Library | React | 18.2.0 | +| Language | TypeScript | 5.5.4 | +| Styling | Tailwind CSS | 3.3.3 | +| State | React Context + Hooks | - | +| Forms | React Hook Form | 7.65.0 | +| Rich Text | TipTap | 2.10.4 | +| i18n | Custom JSON | - | +| Testing | Jest | 29.3.1 | +| E2E | Playwright | 1.58.2 | + +### Backend (api) + +| Category | Technology | Version | +| ---------- | ---------- | ------- | +| Runtime | Node.js | 20+ | +| Framework | Express | 5.0.0 | +| Language | TypeScript | 5.5.4 | +| Database | PostgreSQL | - | +| ORM | pg-promise | - | +| Validation | Zod | - | +| WebSocket | ws | - | +| Testing | Jest | 29.3.1 | + +### Infrastructure + +| Service | Purpose | +| ---------------- | ------------------- | +| Vercel | Frontend hosting | +| Google Cloud | Backend hosting | +| Supabase | PostgreSQL database | +| Firebase Auth | User authentication | +| Firebase Storage | Media storage | +| PostHog | Analytics | + +## Data Flow + +### User Request Flow + +``` +1. User clicks button + │ + ▼ +2. React component handles event + │ + ▼ +3. useAPIGetter/useMutation hook called + │ + ▼ +4. API client sends HTTP request + │ + ▼ +5. Express API receives request + │ + ▼ +6. Auth middleware validates token + │ + ▼ +7. Handler processes request + │ + ▼ +8. Database query executed + │ + ▼ +9. Response returned to client + │ + ▼ +10. React state updated, UI re-renders +``` + +### Authentication Flow + +``` +User Sign-In: +┌──────────┐ ┌──────────┐ ┌──────────────┐ ┌────────────┐ +│ Client │───▶│ Firebase │───▶│ Auth Token │───▶│ Backend │ +└──────────┘ └──────────┘ │ (JWT) │ │ Validates │ + └──────────────┘ └────────────┘ + │ + ▼ + ┌────────────┐ + │ Session │ + │ Created │ + └────────────┘ +``` + +## Database Schema + +### Key Tables + +```sql +-- Users table +users ( + id UUID PRIMARY KEY, + username TEXT UNIQUE, + email TEXT, + created_at TIMESTAMP, + deleted_at TIMESTAMP +) +-- Profile information +profiles ( + id UUID PRIMARY KEY, + user_id UUID REFERENCES users, + name TEXT, + age INTEGER, + bio TEXT, + -- many more fields +) +-- Private user data +private_users ( + id UUID PRIMARY KEY, + user_id UUID REFERENCES users, + email TEXT, + notification_settings JSONB +) +-- Messages +private_user_messages ( + id UUID PRIMARY KEY, + from_user_id UUID, + to_user_id UUID, + content TEXT, + created_at TIMESTAMP +) +``` + +See `supabase/migrations/` for full schema. + +## API Design + +### REST Principles + +- Resource-based URLs: `/get-profiles`, `/create-profile` +- HTTP methods: GET (read), POST (create), PUT (update), DELETE (delete) +- JSON request/response format +- Authentication via Bearer tokens + +### Endpoint Structure + +``` +/{action} POST - Perform action +``` + +### Request Format + +```typescript +{ + // Endpoint-specific parameters +} +``` + +### Response Format + +```typescript +// Success +{ + // Response data +} + +// Error +{ + error: { + status: 400, + message: "Error description" + } +} +``` + +## State Management + +### Frontend State + +1. **Server State**: React Query-style hooks (`useAPIGetter`, `useMutation`) +2. **Client State**: React `useState`, `useReducer` +3. **Persisted State**: `usePersistentLocalState`, `usePersistentInMemoryState` +4. **Global State**: React Context (`AuthProvider`, `I18nProvider`) + +### State Persistence + +```typescript +// In-memory (lost on refresh) +const [state, setState] = useState(initialValue) + +// Local storage (persists) +const [state, setState] = usePersistentLocalState(initialValue, 'key') + +// Session storage (persists until tab closed) +const [state, setState] = usePersistentInMemoryState(initialValue, 'key') +``` + +## Security + +### Authentication + +- Firebase Auth for user authentication +- JWT tokens for API requests +- Session-based auth for web + +### Authorization + +- Role-based access (user, moderator, admin) +- User ID verification on protected endpoints + +### Data Protection + +- Row-level security in PostgreSQL +- Environment-based secrets +- Input validation with Zod + +## Performance Optimizations + +### Frontend + +- Next.js static generation for public pages +- Image optimization with `next/image` +- Code splitting per route +- Memoization with `useMemo`, `useCallback` +- Virtualized lists for large datasets + +### Backend + +- Database connection pooling +- Query optimization (indexes) +- Caching strategies +- Rate limiting + +## Monitoring + +### Logging + +- Structured logging with context +- Different log levels: debug, info, warn, error +- Environment-aware (development vs production) + +### Error Tracking + +- Error boundaries in React +- API error handling +- Server-side error logging + +### Analytics + +- PostHog for user analytics +- Custom event tracking + +## Deployment + +### CI/CD Pipeline + +``` +GitHub Push + │ + ▼ +┌─────────────┐ +│ CI Tests │ ──▶ Lint, TypeCheck, Unit Tests +└─────────────┘ + │ + ▼ +┌─────────────┐ +│ CD Deploy │ ──▶ Vercel (Web), GCP (API) +└─────────────┘ +``` + +### Environments + +| Environment | URL | Purpose | +| ----------- | --------------- | ----------------- | +| Development | localhost | Local development | +| Staging | - | Testing changes | +| Production | compassmeet.com | Live users | + +## Development Workflow + +1. **Create branch**: `feat/description` +2. **Make changes**: Implement feature/fix +3. **Test locally**: `yarn dev` +4. **Run tests**: `yarn test` +5. **Submit PR**: Code review +6. **Merge**: Automated deployment + +## See Also + +- [Knowledge Base](knowledge.md) +- [Development Guide](development.md) +- [Testing Guide](TESTING.md) +- [Next.js Documentation](Next.js.md) diff --git a/web/README.md b/web/README.md index dee7b146..7b66f0de 100644 --- a/web/README.md +++ b/web/README.md @@ -1,12 +1,353 @@ -# Web +# Web Application -This is the folder for the web application. +The Compass web application built with Next.js, React, and TypeScript. -### Information +## Overview -##### Setup +This is the frontend of the Compass platform, a transparent platform for forming deep, authentic 1-on-1 connections. -This is the setup for deployment on Vercel, which you only need to do if you create a new platform from scratch, not if you are contributing to Compass +## Tech Stack + +- **Framework**: Next.js 14.1.0 +- **Language**: TypeScript +- **UI Library**: React 18.2.0 +- **Styling**: Tailwind CSS 3.3.3 +- **State Management**: React Context + Custom Hooks +- **Forms**: React Hook Form +- **Rich Text**: TipTap (ProseMirror) +- **Charts**: Recharts +- **i18n**: Custom solution with JSON message files + +## Project Structure + +``` +web/ +├── components/ # React components +│ ├── auth-context.tsx # Authentication state +│ ├── buttons/ # Button components +│ ├── chat/ # Chat/messaging components +│ ├── comments/ # Comment components +│ ├── editor/ # Rich text editor +│ ├── events/ # Event components +│ ├── filters/ # Search filters +│ ├── matches/ # Match components +│ ├── nav/ # Navigation components +│ ├── profile/ # Profile components +│ └── widgets/ # Reusable widgets +├── hooks/ # Custom React hooks (50+) +├── lib/ # Utilities and services +│ ├── api.ts # API client +│ ├── firebase/ # Firebase configuration +│ ├── locale/ # Internationalization +│ ├── service/ # Analytics, push notifications +│ ├── supabase/ # Supabase client +│ └── logger.ts # Structured logging +├── pages/ # Next.js pages +│ ├── api/ # API routes +│ ├── _app.tsx # App wrapper +│ ├── _document.tsx # Document setup +│ └── [username].tsx # Dynamic routes +├── messages/ # Translation JSON files +├── public/ # Static assets +├── styles/ # Global CSS +├── tests/ +│ ├── unit/ # Unit tests +│ └── integration/ # Integration tests +└── types/ # TypeScript type definitions +``` + +## Getting Started + +### Prerequisites + +- Node.js 20.x or later +- Yarn 1.x + +### Installation + +```bash +# From root directory +yarn install +``` + +### Development + +```bash +# Run web app with hot reload +yarn dev + +# Or from web directory +cd web +yarn serve +``` + +Visit http://localhost:3000 + +### Build + +```bash +# Production build +yarn build + +# Start production server +yarn start +``` + +### Testing + +```bash +# Run tests +yarn test + +# Run with coverage +yarn test --coverage + +# Watch mode +yarn test --watch +``` + +### Linting + +```bash +# Check lint +yarn lint + +# Fix lint issues +yarn lint-fix +``` + +## Key Concepts + +### Components + +Components are organized by feature in `/components`. Reusable widgets are in `/components/widgets`. + +Example component: + +```tsx +// components/profile/profile-card.tsx +import {User} from 'common/src/user' + +interface ProfileCardProps { + user: User + onLike?: (userId: string) => void +} + +export function ProfileCard({user, onLike}: ProfileCardProps) { + return ( +
+ {user.name} +

{user.name}

+ +
+ ) +} +``` + +### Hooks + +Use custom hooks for stateful logic. Common hooks: + +- `useUser()` - Get current user +- `useAPIGetter()` - Fetch API data with caching +- `useMutation()` - Handle form submissions +- `usePersistentInMemoryState()` - Cache state across pages + +```tsx +import {useAPIGetter} from 'web/hooks/use-api-getter' + +function ProfileList() { + const {data, refresh} = useAPIGetter('get-profiles', {}) + + if (!data) return + + return ( +
+ {data.profiles.map((profile) => ( + + ))} + +
+ ) +} +``` + +### API Calls + +Backend API is called through the `api` helper: + +```tsx +import {api} from 'web/lib/api' + +// Server-side (getStaticProps, getServerSideProps) +const profiles = await api('get-profiles', {}) + +// Client-side - use hooks +const {data} = useAPIGetter('get-profiles', {}) +``` + +### Internationalization + +Translation files are in `/messages` (e.g., `en.json`, `fr.json`). + +```tsx +import {useT} from 'web/lib/locale' + +function MyComponent() { + const t = useT() + + return

{t('welcome', 'Welcome to Compass')}

+} +``` + +### Styling + +Tailwind CSS is used for styling. Use utility classes: + +```tsx +
+ Content +
+``` + +## Accessibility + +The app includes several accessibility features: + +### Error Boundary + +Catches React errors and shows user-friendly message: + +```tsx +import {ErrorBoundary} from 'web/components/error-boundary' + +; + + +``` + +### Live Region + +Announces dynamic content changes to screen readers: + +```tsx +import {useLiveRegion} from 'web/components/live-region' + +const {announce} = useLiveRegion() + +// Announce status changes +announce('Profile liked', 'polite') +``` + +Priority levels: + +- `polite` - Waits for screen reader to finish (default) +- `assertive` - Interrupts immediately + +### Skip Links + +Keyboard users can skip to main content: + +```tsx +import {SkipLink, MainContent} from 'web/components/skip-link' + +;<> + + ... + +``` + +## Logging + +Use the structured logger for debug logging that's filtered out in production: + +```tsx +import {debug, logApiError} from 'common/logger' + +// Simple logging +debug('User logged in', {userId: '123'}) + +// API errors with context +try { + await api('endpoint', {}) +} catch (err) { + logApiError('get-profiles', err, {userId: '123'}) +} +``` + +## Environment Variables + +Key environment variables for the web app: + +| Variable | Description | +| ------------------------------- | --------------------- | +| `NEXT_PUBLIC_SUPABASE_URL` | Supabase project URL | +| `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Supabase anon key | +| `NEXT_PUBLIC_FIREBASE_API_KEY` | Firebase API key | +| `NEXT_PUBLIC_POSTHOG_KEY` | PostHog analytics key | +| `NEXT_PUBLIC_VERCEL_ENV` | Vercel environment | + +## Common Tasks + +### Adding a New Page + +1. Create file in `/pages/`: + +```tsx +// pages/new-page.tsx +import {Page} from 'web/components/page-base' + +export default function NewPage() { + return ( + +

New Page

+
+ ) +} +``` + +### Adding a Component + +1. Create file in appropriate `/components` subdirectory +2. Export the component +3. Add to parent component + +### Adding a Hook + +1. Create file in `/hooks/` +2. Follow naming convention:\*.ts` + +### `use- Adding Translations + +1. Add key to `/messages/en.json` +2. Add translations to other locale files + +## Troubleshooting + +### Slow local development + +Running `yarn dev:isolated` uses local emulators and is faster. + +### Type errors + +Run `yarn typecheck` to see all type errors. + +### Build failures + +Check `yarn lint` first, as linting issues can cause build failures. + +## See Also + +- [Main README](../README.md) +- [Contributing Guide](../CONTRIBUTING.md) +- [Development Docs](../docs/development.md) +- [Testing Guide](../docs/TESTING.md) +- [Architecture Docs](../docs/knowledge.md) + +## Setup + +This is the setup for deployment on Vercel, which you only need to do if you create a new platform from scratch, not if +you are contributing to Compass Set up a Vercel account and link it to your GitHub repository. @@ -16,9 +357,10 @@ Add the following environment variables and the ones in `.env` in the Vercel das NEXT_PUBLIC_VERCEL=1 ``` -##### `next` version +## `next` version -The `next` version is 14.1.0, as we get the following error with 15.1.2 and above when accessing `/[username]` pages on Vercel: +The `next` version is 14.1.0, as we get the following error with 15.1.2 and above when accessing `/[username]` pages on +Vercel: ``` Cannot find module 'next/dist/compiled/source-map'