diff --git a/.aiassistant/rules/guidelines.md b/.aiassistant/rules/guidelines.md index 766db60b..ffda053e 100644 --- a/.aiassistant/rules/guidelines.md +++ b/.aiassistant/rules/guidelines.md @@ -528,7 +528,6 @@ 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.). @@ -537,7 +536,6 @@ This project uses three complementary test types. Use the right level for the jo - 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`). diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 68dfb155..c36cfd0e 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -30,4 +30,4 @@ runs: - name: Post-install if: steps.cache-node-modules.outputs.cache-hit == 'true' run: yarn postinstall - shell: bash \ No newline at end of file + shell: bash diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c9967d72..6272f8b1 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -522,7 +522,6 @@ 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.). @@ -531,7 +530,6 @@ This project uses three complementary test types. Use the right level for the jo - 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`). diff --git a/.github/workflows/cd-android-live-update.yml b/.github/workflows/cd-android-live-update.yml index 5ce33a8f..3ec3b55f 100644 --- a/.github/workflows/cd-android-live-update.yml +++ b/.github/workflows/cd-android-live-update.yml @@ -1,7 +1,7 @@ name: CD Android Live Update on: push: - branches: [ main, master ] + branches: [main, master] paths: - 'android/capawesome.json' - '.github/workflows/cd-android-live-update.yml' diff --git a/.github/workflows/cd-api.yml b/.github/workflows/cd-api.yml index 5a311032..f862e776 100644 --- a/.github/workflows/cd-api.yml +++ b/.github/workflows/cd-api.yml @@ -1,7 +1,7 @@ name: API Release on: push: - branches: [ main, master ] + branches: [main, master] paths: - 'backend/api/package.json' - '.github/workflows/cd-api.yml' diff --git a/.github/workflows/ci-e2e.yml b/.github/workflows/ci-e2e.yml index 9dc2a979..a38d69d8 100644 --- a/.github/workflows/ci-e2e.yml +++ b/.github/workflows/ci-e2e.yml @@ -2,9 +2,9 @@ name: E2E Tests on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] jobs: e2e: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c4e479f9..7149d46d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] jobs: lint: diff --git a/.junie/guidelines.md b/.junie/guidelines.md index c9967d72..6272f8b1 100644 --- a/.junie/guidelines.md +++ b/.junie/guidelines.md @@ -522,7 +522,6 @@ 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.). @@ -531,7 +530,6 @@ This project uses three complementary test types. Use the right level for the jo - 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`). diff --git a/.prettierrc b/.prettierrc index cfbc2803..32a18673 100644 --- a/.prettierrc +++ b/.prettierrc @@ -7,7 +7,7 @@ "bracketSpacing": false, "printWidth": 100, "trailingComma": "all", - "plugins": ["prettier-plugin-sql"], + "plugins": ["prettier-plugin-sql", "prettier-plugin-packagejson"], "overrides": [ { "files": "*.sql", diff --git a/backend/api/package.json b/backend/api/package.json index 53ca3f8c..8483ff98 100644 --- a/backend/api/package.json +++ b/backend/api/package.json @@ -1,66 +1,44 @@ { "name": "@compass/api", - "description": "Backend API endpoints", "version": "1.19.0", "private": true, + "description": "Backend API endpoints", + "main": "src/serve.ts", "scripts": { - "watch:serve": "tsx watch src/serve.ts", - "watch:compile": "npx concurrently \"tsc -b --watch --preserveWatchOutput\" \"(cd ../../common && tsc-alias --watch)\" \"(cd ../shared && tsc-alias --watch)\" \"(cd ../email && tsc-alias --watch)\" \"tsc-alias --watch\"", - "dev": "yarn watch:serve", - "prod": "npx concurrently -n COMPILE,SERVER -c cyan,green \"yarn watch:compile\" \"yarn watch:serve\"", "build": "yarn compile && yarn dist:clean && yarn dist:copy", "build:fast": "yarn compile && yarn dist:copy", "clean": "rm -rf lib && (cd ../../common && rm -rf lib) && (cd ../shared && rm -rf lib) && (cd ../email && rm -rf lib)", "compile": "tsc -b && tsc-alias && (cd ../../common && tsc-alias) && (cd ../shared && tsc-alias) && (cd ../email && tsc-alias) && cp -r src/public/ lib/", "debug": "nodemon -r tsconfig-paths/register --watch src -e ts --watch ../../common/src --watch ../shared/src --exec \"yarn build && node --inspect-brk src/serve.ts\"", + "dev": "yarn watch:serve", "dist": "yarn dist:clean && yarn dist:copy", "dist:clean": "rm -rf dist && mkdir -p dist/common/lib dist/backend/shared/lib dist/backend/api/lib dist/backend/email/lib", "dist:copy": "rsync -a --delete ../../common/lib/ dist/common/lib && rsync -a ../../common/messages/ dist/common/messages/ && rsync -a --delete ../shared/lib/ dist/backend/shared/lib && rsync -a --delete ../email/lib/ dist/backend/email/lib && rsync -a --delete ./lib/* dist/backend/api/lib && cp ../../yarn.lock dist && cp package.json dist && cp package.json dist/backend/api && cp metadata.json dist && cp metadata.json dist/backend/api", - "watch": "tsc -w", "lint": "npx eslint . --max-warnings 0", "lint-fix": "npx eslint . --fix", - "typecheck": "yarn build && npx tsc --noEmit", + "prod": "npx concurrently -n COMPILE,SERVER -c cyan,green \"yarn watch:compile\" \"yarn watch:serve\"", "regen-types": "cd ../supabase && make ENV=prod regen-types", "regen-types-dev": "cd ../supabase && make ENV=dev regen-types-dev", "test": "jest --config jest.config.ts", - "test:coverage": "jest --config jest.config.ts --coverage" + "test:coverage": "jest --config jest.config.ts --coverage", + "typecheck": "yarn build && npx tsc --noEmit", + "watch:compile": "npx concurrently \"tsc -b --watch --preserveWatchOutput\" \"(cd ../../common && tsc-alias --watch)\" \"(cd ../shared && tsc-alias --watch)\" \"(cd ../email && tsc-alias --watch)\" \"tsc-alias --watch\"", + "watch:serve": "tsx watch src/serve.ts" }, - "engines": { - "node": ">=20.0.0" - }, - "main": "src/serve.ts", "dependencies": { "@google-cloud/monitoring": "4.0.0", "@google-cloud/secret-manager": "4.2.1", - "@react-email/components": "0.0.33", - "@supabase/supabase-js": "2.38.5", "@tiptap/core": "2.10.4", - "@tiptap/extension-blockquote": "2.10.4", - "@tiptap/extension-bold": "2.10.4", - "@tiptap/extension-bubble-menu": "2.10.4", - "@tiptap/extension-floating-menu": "2.10.4", - "@tiptap/extension-image": "2.10.4", - "@tiptap/extension-link": "2.10.4", - "@tiptap/extension-mention": "2.10.4", - "@tiptap/html": "2.10.4", - "@tiptap/pm": "2.10.4", - "@tiptap/starter-kit": "2.10.4", - "@tiptap/suggestion": "2.10.4", - "colors": "1.4.0", "cors": "2.8.5", - "dayjs": "1.11.4", + "dayjs": "1.11.19", "express": "5.0.0", "firebase-admin": "13.5.0", "gcp-metadata": "6.1.0", "jsonwebtoken": "9.0.0", "lodash": "4.17.23", "openapi-types": "12.1.3", - "pg-promise": "11.5.5", + "pg-promise": "12.6.1", "posthog-node": "4.11.0", - "react": "18.2.0", - "react-dom": "18.2.0", - "resend": "4.1.2", - "string-similarity": "4.0.4", "swagger-jsdoc": "6.2.8", "swagger-ui-express": "5.0.1", "tsconfig-paths": "4.2.0", @@ -71,10 +49,13 @@ }, "devDependencies": { "@types/cors": "2.8.17", - "@types/react": "18.3.5", - "@types/react-dom": "18.3.0", + "@types/jsonwebtoken": "^9.0.0", + "@types/lodash": "^4.17.0", "@types/swagger-ui-express": "4.1.8", "@types/web-push": "3.6.4", "@types/ws": "8.5.10" + }, + "engines": { + "node": ">=20.9.0" } } diff --git a/backend/email/package.json b/backend/email/package.json index 3986f2df..a849fc6b 100644 --- a/backend/email/package.json +++ b/backend/email/package.json @@ -3,24 +3,24 @@ "version": "1.0.0", "private": true, "scripts": { - "dev": "email dev --port 3001", "build": "tsc -b", - "test": "jest --config jest.config.ts --passWithNoTests", + "dev": "email dev --port 3001", "lint": "npx eslint . --max-warnings 0", "lint-fix": "npx eslint . --fix", + "test": "jest --config jest.config.ts --passWithNoTests", "typecheck": "npx tsc --noEmit" }, "dependencies": { - "@react-email/components": "0.0.33", + "@react-email/components": "1.0.8", + "react": "19.2.3", + "react-dom": "19.2.3", "react-icons": "5.5.0", - "resend": "4.1.2", - "react": "18.2.0", - "react-dom": "18.2.0" + "resend": "4.1.2" }, "devDependencies": { "@types/html-to-text": "9.0.4", "@types/prismjs": "1.26.5", - "@types/react": "18.3.5", - "@types/react-dom": "18.3.0" + "@types/react": "19.2.3", + "@types/react-dom": "19.2.3" } } diff --git a/backend/shared/package.json b/backend/shared/package.json index 819c6aa2..de9310f1 100644 --- a/backend/shared/package.json +++ b/backend/shared/package.json @@ -2,22 +2,20 @@ "name": "shared", "version": "1.0.0", "private": true, + "sideEffects": false, "scripts": { "build": "tsc -b && yarn --cwd=../../common tsc-alias && tsc-alias", "compile": "tsc -b", "lint": "npx eslint . --max-warnings 0", "lint-fix": "npx eslint . --fix", - "typecheck": "npx tsc --noEmit", - "test": "jest --config jest.config.ts --passWithNoTests" + "test": "jest --config jest.config.ts --passWithNoTests", + "typecheck": "npx tsc --noEmit" }, - "sideEffects": false, "dependencies": { "@google-cloud/monitoring": "4.0.0", "@google-cloud/secret-manager": "4.2.1", - "@tiptap/core": "2.10.4", - "@tiptap/html": "2.10.4", - "colors": "1.4.0", - "dayjs": "1.11.4", + "colorette": "2.0.20", + "dayjs": "1.11.19", "firebase-admin": "13.5.0", "gcp-metadata": "6.1.0", "lodash": "4.17.23", @@ -25,5 +23,11 @@ "pg-query-stream": "4.12.0", "posthog-node": "4.11.0", "string-similarity": "4.0.4" + }, + "devDependencies": { + "@types/jest": "^29", + "@types/lodash": "^4.17.0", + "jest": "^29", + "ts-jest": "29.4.6" } } diff --git a/backend/shared/src/monitoring/log.ts b/backend/shared/src/monitoring/log.ts index b142eb75..afe57246 100644 --- a/backend/shared/src/monitoring/log.ts +++ b/backend/shared/src/monitoring/log.ts @@ -1,6 +1,6 @@ import {format} from 'node:util' -import {dim, red, yellow} from 'colors/safe' +import {dim, red, yellow} from 'colorette' import {IS_GOOGLE_CLOUD} from 'common/hosting/constants' import {isError, omit, pick} from 'lodash' diff --git a/common/package.json b/common/package.json index 8fcab82a..88b38f46 100644 --- a/common/package.json +++ b/common/package.json @@ -2,17 +2,17 @@ "name": "common", "version": "1.0.0", "private": true, + "sideEffects": false, "scripts": { "build": "tsc -b && tsc-alias", "compile": "tsc -b", "lint": "npx eslint . --max-warnings 0", "lint-fix": "npx eslint . --fix", - "typecheck": "npx tsc --noEmit", - "test": "jest --config jest.config.ts --passWithNoTests" + "test": "jest --config jest.config.ts --passWithNoTests", + "typecheck": "npx tsc --noEmit" }, - "sideEffects": false, "dependencies": { - "@supabase/supabase-js": "2.38.5", + "@supabase/supabase-js": "2.98.0", "@tiptap/core": "2.10.4", "@tiptap/extension-image": "2.10.4", "@tiptap/extension-link": "2.10.4", @@ -20,17 +20,16 @@ "@tiptap/pm": "2.10.4", "@tiptap/starter-kit": "2.10.4", "@tiptap/suggestion": "2.10.4", - "dayjs": "1.11.4", + "dayjs": "1.11.19", "lodash": "4.17.23", "string-similarity": "4.0.4", "zod": "3.22.3" }, "devDependencies": { - "@types/jest": "29.2.4", - "@types/lodash": "4.14.178", + "@types/jest": "^29", + "@types/lodash": "^4.17.0", "@types/string-similarity": "4.0.0", - "jest": "29.3.1", - "supabase": "2.15.8", + "jest": "^29", "ts-jest": "29.4.6" } } diff --git a/common/src/supabase/utils.ts b/common/src/supabase/utils.ts index d6080565..7afa79a7 100644 --- a/common/src/supabase/utils.ts +++ b/common/src/supabase/utils.ts @@ -22,7 +22,7 @@ export type Row = T extends TableName : never export type Column = keyof Row & string -export type SupabaseClient = SupabaseClientGeneric +export type SupabaseClient = SupabaseClientGeneric export function createClient( instanceIdOrUrl: string, diff --git a/docs/TESTING.md b/docs/TESTING.md index f1895eb4..bf6a58aa 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -25,7 +25,6 @@ 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.). @@ -34,7 +33,6 @@ This project uses three complementary test types. Use the right level for the jo - 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`). diff --git a/docs/architecture.md b/docs/architecture.md index b46f9b41..73d0771d 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -92,7 +92,7 @@ Compass/ | Category | Technology | Version | | ---------- | --------------------- | ------- | | Framework | Next.js | 14.1.0 | -| UI Library | React | 18.2.0 | +| UI Library | React | 19.2.3 | | Language | TypeScript | 5.5.4 | | Styling | Tailwind CSS | 3.3.3 | | State | React Context + Hooks | - | @@ -183,37 +183,40 @@ User Sign-In: ```sql -- Users table -users ( +CREATE TABLE users ( id UUID PRIMARY KEY, username TEXT UNIQUE, email TEXT, created_at TIMESTAMP, deleted_at TIMESTAMP -) +); + -- Profile information -profiles ( +CREATE TABLE profiles ( id UUID PRIMARY KEY, user_id UUID REFERENCES users, name TEXT, age INTEGER, - bio TEXT, + bio TEXT -- many more fields -) +); + -- Private user data -private_users ( +CREATE TABLE private_users ( id UUID PRIMARY KEY, user_id UUID REFERENCES users, email TEXT, notification_settings JSONB -) +); + -- Messages -private_user_messages ( +CREATE TABLE 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. @@ -245,18 +248,16 @@ See `supabase/migrations/` for full schema. ```typescript // Success -{ - // Response data +return { + // Response data } // Error -{ - error: { - status: 400, - message - : - "Error description" - } +return { + error: { + status: 400, + message: 'Error description', + }, } ``` @@ -271,14 +272,21 @@ See `supabase/migrations/` for full schema. ### State Persistence +In-memory (lost on refresh) + ```typescript -// In-memory (lost on refresh) const [state, setState] = useState(initialValue) +``` -// Local storage (persists) +Local storage (persists) + +```typescript const [state, setState] = usePersistentLocalState(initialValue, 'key') +``` -// Session storage (persists until tab closed) +Session storage (persists until tab closed) + +```typescript const [state, setState] = usePersistentInMemoryState(initialValue, 'key') ``` diff --git a/package.json b/package.json index 6c863ea7..06c4ca1d 100644 --- a/package.json +++ b/package.json @@ -11,95 +11,40 @@ "web" ], "scripts": { - "lint": "yarn --cwd=web lint; yarn --cwd=common lint; yarn --cwd=backend/api lint; yarn --cwd=backend/shared lint; yarn --cwd=backend/email lint", - "lint-fix": "yarn --cwd=web lint-fix; yarn --cwd=common lint-fix; yarn --cwd=backend/api lint-fix; yarn --cwd=backend/shared lint-fix; yarn --cwd=backend/email lint-fix", - "typecheck": "yarn --cwd=web typecheck; yarn --cwd=backend/api typecheck; yarn --cwd=common typecheck; yarn --cwd=backend/shared typecheck; yarn --cwd=backend/email typecheck", - "prettier": "prettier --write .", - "prettier:check": "prettier --check .", + "android-live-update": "./scripts/android_live_update.sh", + "build-sync-android": "./scripts/build_sync_android.sh", + "build-web-view": "./scripts/build_web_view.sh", + "clean-install": "./scripts/install.sh", "dev": "./scripts/run_local.sh dev", "dev:isolated": "./scripts/run_local_isolated.sh", - "prod": "./scripts/run_local.sh prod", - "clean-install": "./scripts/install.sh", - "build-web-view": "./scripts/build_web_view.sh", - "build-sync-android": "./scripts/build_sync_android.sh", - "android-live-update": "./scripts/android_live_update.sh", - "sync-android": "./scripts/sync_android.sh", + "emulate": "firebase emulators:start --only auth,storage --project compass-57c3c", + "postinstall": "./scripts/post_install.sh", + "lint": "yarn --cwd=web lint; yarn --cwd=common lint; yarn --cwd=backend/api lint; yarn --cwd=backend/shared lint; yarn --cwd=backend/email lint", + "lint-fix": "yarn --cwd=web lint-fix; yarn --cwd=common lint-fix; yarn --cwd=backend/api lint-fix; yarn --cwd=backend/shared lint-fix; yarn --cwd=backend/email lint-fix", "migrate": "./scripts/migrate.sh", - "test": "yarn workspaces run test", - "test:coverage": "yarn workspaces run test --coverage", - "test:watch": "yarn workspaces run test --watch", - "test:update": "yarn workspaces run test --updateSnapshot", - "test:e2e": "./scripts/e2e.sh", - "test:e2e:dev": "./scripts/e2e-dev.sh", - "test:e2e:ui": "./scripts/e2e.sh --ui", - "test:e2e:debug": "./scripts/e2e.sh --debug", - "test:e2e:services": "./scripts/e2e_services.sh", - "test:db:reset": "./scripts/test_db_reset.sh", - "test:db:reset-postgres": "docker compose -f scripts/docker-compose.test.yml down -v && docker compose -f scripts/docker-compose.test.yml up -d", - "test:db:migrate": "./scripts/test_db_migration.sh", - "test:db:seed": "./scripts/seed.sh", "playwright": "playwright test", - "playwright:ui": "playwright test --ui", "playwright:debug": "playwright test --debug", "playwright:report": "npx playwright show-report tests/reports/playwright-report", - "postinstall": "./scripts/post_install.sh", - "emulate": "firebase emulators:start --only auth,storage --project compass-57c3c", - "prepare": "npx husky" - }, - "dependencies": { - "@capacitor/app": "7.1.0", - "@capacitor/core": "7.4.4", - "@capacitor/keyboard": "7.0.3", - "@capacitor/push-notifications": "7.0.3", - "@capacitor/status-bar": "7.0.3", - "@capawesome/capacitor-live-update": "7.2.2", - "@capgo/capacitor-social-login": "7.14.9", - "colorette": "^2.0.20", - "prismjs": "^1.30.0", - "react": "18.2.0", - "react-dom": "18.2.0", - "react-markdown": "10.1.0", - "supabase": "2.76.9", - "wait-on": "9.0.4" - }, - "devDependencies": { - "@capacitor/android": "7.4.4", - "@capacitor/assets": "3.0.5", - "@capacitor/cli": "7.4.4", - "@faker-js/faker": "10.1.0", - "@playwright/test": "1.58.2", - "@testing-library/dom": "^10.0.0", - "@testing-library/jest-dom": "^6.6.4", - "@testing-library/react": "^16.3.0", - "@testing-library/user-event": "^14.6.1", - "@types/jest": "29.2.4", - "@types/node": "20.12.11", - "@eslint/js": "^9.39.0", - "typescript-eslint": "^8.32.0", - "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-config-prettier": "^10.1.5", - "@next/eslint-plugin-next": "^15.3.3", - "chalk": "5.6.2", - "concurrently": "8.2.2", - "dotenv-cli": "10.0.0", - "eslint": "9.39.3", - "eslint-plugin-lodash": "7.4.0", - "eslint-plugin-simple-import-sort": "12.1.1", - "eslint-plugin-unused-imports": "4.1.4", - "firebase-tools": "14.27.0", - "husky": "9.1.7", - "jest": "29.3.1", - "nodemon": "2.0.20", - "prettier": "3.6.2", - "prettier-plugin-sql": "0.19.2", - "prettier-plugin-tailwindcss": "0.2.8", - "ts-jest": "29.4.6", - "ts-node": "10.9.1", - "tsc-alias": "1.8.2", - "tsconfig-paths": "4.2.0", - "tsx": "4.20.6", - "typescript": "5.5.4" + "playwright:ui": "playwright test --ui", + "prepare": "npx husky", + "prettier": "prettier --write .", + "prettier:check": "prettier --check .", + "prod": "./scripts/run_local.sh prod", + "sync-android": "./scripts/sync_android.sh", + "test": "yarn workspaces run test", + "test:coverage": "yarn workspaces run test --coverage", + "test:db:migrate": "./scripts/test_db_migration.sh", + "test:db:reset": "./scripts/test_db_reset.sh", + "test:db:reset-postgres": "docker compose -f scripts/docker-compose.test.yml down -v && docker compose -f scripts/docker-compose.test.yml up -d", + "test:db:seed": "./scripts/seed.sh", + "test:e2e": "./scripts/e2e.sh", + "test:e2e:debug": "./scripts/e2e.sh --debug", + "test:e2e:dev": "./scripts/e2e-dev.sh", + "test:e2e:services": "./scripts/e2e_services.sh", + "test:e2e:ui": "./scripts/e2e.sh --ui", + "test:update": "yarn workspaces run test --updateSnapshot", + "test:watch": "yarn workspaces run test --watch", + "typecheck": "yarn --cwd=web typecheck; yarn --cwd=backend/api typecheck; yarn --cwd=common typecheck; yarn --cwd=backend/shared typecheck; yarn --cwd=backend/email typecheck" }, "resolutions": { "@tiptap/core": "2.10.4", @@ -107,19 +52,62 @@ "@tiptap/extension-bold": "2.10.4", "@tiptap/extension-bubble-menu": "2.10.4", "@tiptap/extension-floating-menu": "2.10.4", + "@tiptap/extension-horizontal-rule": "2.10.4", "@tiptap/extension-image": "2.10.4", "@tiptap/extension-link": "2.10.4", "@tiptap/extension-mention": "2.10.4", - "@tiptap/extension-horizontal-rule": "2.10.4", "@tiptap/html": "2.10.4", "@tiptap/pm": "2.10.4", "@tiptap/starter-kit": "2.10.4", "@tiptap/suggestion": "2.10.4", - "@types/react": "18.3.5", - "@types/react-dom": "18.3.0", + "@types/jest": "^29", + "@types/node": "20.19.35", + "@types/react": "19.2.3", + "@types/react-dom": "19.2.3", + "jest": "^29", + "lodash": "4.17.23", + "pg-query-stream/pg": "8.x", "prosemirror-model": "1.x", - "react": "18.2.0", - "react-dom": "18.2.0", - "pg-query-stream/pg": "8.x" + "react": "19.2.3", + "react-dom": "19.2.3", + "zod": "3.22.3" + }, + "devDependencies": { + "@eslint/js": "^9.39.0", + "@faker-js/faker": "10.1.0", + "@next/eslint-plugin-next": "16.1.6", + "@playwright/test": "1.58.2", + "@testing-library/dom": "^10.0.0", + "@testing-library/jest-dom": "^6.6.4", + "@testing-library/react": "^16.3.0", + "@testing-library/user-event": "^14.6.1", + "@types/jest": "^29", + "@types/node": "20.19.35", + "concurrently": "8.2.2", + "dotenv-cli": "10.0.0", + "eslint": "9.39.3", + "eslint-config-prettier": "^10.1.5", + "eslint-plugin-lodash": "7.4.0", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-simple-import-sort": "12.1.1", + "eslint-plugin-unused-imports": "4.1.4", + "firebase-tools": "14.27.0", + "husky": "9.1.7", + "jest": "^29", + "nodemon": "3.1.14", + "prettier": "3.6.2", + "prettier-plugin-packagejson": "3.0.0", + "prettier-plugin-sql": "0.19.2", + "prettier-plugin-tailwindcss": "0.2.8", + "supabase": "2.76.9", + "ts-jest": "29.4.6", + "ts-node": "10.9.1", + "tsc-alias": "1.8.2", + "tsconfig-paths": "4.2.0", + "tsx": "4.20.6", + "typescript": "5.5.4", + "typescript-eslint": "^8.32.0", + "wait-on": "9.0.4" } } diff --git a/web/README.md b/web/README.md index 8e0ee91d..304ce1c4 100644 --- a/web/README.md +++ b/web/README.md @@ -10,7 +10,7 @@ This is the frontend of the Compass platform, a transparent platform for forming - **Framework**: Next.js 14.1.0 - **Language**: TypeScript -- **UI Library**: React 18.2.0 +- **UI Library**: React 19.2.3 - **Styling**: Tailwind CSS 3.3.3 - **State Management**: React Context + Custom Hooks - **Forms**: React Hook Form @@ -220,7 +220,6 @@ Catches React errors and shows user-friendly message: ```tsx import {ErrorBoundary} from 'web/components/error-boundary' - ; @@ -250,7 +249,6 @@ Keyboard users can skip to main content: ```tsx import {SkipLink, MainContent} from 'web/components/skip-link' - ;<> ... diff --git a/web/components/answers/add-compatibility-question-button.tsx b/web/components/answers/add-compatibility-question-button.tsx index 4c28725a..75a1acce 100644 --- a/web/components/answers/add-compatibility-question-button.tsx +++ b/web/components/answers/add-compatibility-question-button.tsx @@ -1,4 +1,4 @@ -import {PlusIcon, XIcon} from '@heroicons/react/outline' +import {PlusIcon, XMarkIcon} from '@heroicons/react/24/outline' import {MAX_ANSWER_LENGTH} from 'common/envs/constants' import {debug} from 'common/logger' import {MAX_COMPATIBILITY_QUESTION_LENGTH} from 'common/profiles/constants' @@ -156,7 +156,9 @@ function CreateCompatibilityModalContent(props: { setQuestion(e.target.value || '')} + onChange={(e: React.ChangeEvent) => + setQuestion(e.target.value || '') + } /> @@ -169,7 +171,9 @@ function CreateCompatibilityModalContent(props: {
onOptionChange(index, e.target.value)} + onChange={(e: React.ChangeEvent) => + onOptionChange(index, e.target.value) + } className="w-full" placeholder={t('answers.add.option_placeholder', 'Option {n}', { n: String(index + 1), @@ -182,7 +186,7 @@ function CreateCompatibilityModalContent(props: { className="bg-ink-400 text-ink-0 hover:bg-ink-600 transition-color absolute -right-1.5 -top-1.5 rounded-full p-0.5" onClick={() => deleteOption(index)} > - + )}
diff --git a/web/components/answers/answer-compatibility-question-content.tsx b/web/components/answers/answer-compatibility-question-content.tsx index afcbd752..eb3b0c30 100644 --- a/web/components/answers/answer-compatibility-question-content.tsx +++ b/web/components/answers/answer-compatibility-question-content.tsx @@ -1,5 +1,5 @@ import {RadioGroup} from '@headlessui/react' -import {UserIcon} from '@heroicons/react/solid' +import {UserIcon} from '@heroicons/react/24/solid' import clsx from 'clsx' import {Row as rowFor} from 'common/supabase/utils' import {User} from 'common/user' @@ -221,7 +221,9 @@ export function AnswerCompatibilityQuestionContent(props: { className={'w-full'} rows={3} value={answer.explanation ?? ''} - onChange={(e) => setAnswer({...answer, explanation: e.target.value})} + onChange={(e: React.ChangeEvent) => + setAnswer({...answer, explanation: e.target.value}) + } /> diff --git a/web/components/answers/compatibility-question-preferred-list.tsx b/web/components/answers/compatibility-question-preferred-list.tsx index 7e7cbc1f..9b1b5a80 100644 --- a/web/components/answers/compatibility-question-preferred-list.tsx +++ b/web/components/answers/compatibility-question-preferred-list.tsx @@ -1,4 +1,4 @@ -import {CheckCircleIcon, XCircleIcon} from '@heroicons/react/outline' +import {CheckCircleIcon, XCircleIcon} from '@heroicons/react/24/outline' import clsx from 'clsx' import {Row as rowFor} from 'common/supabase/utils' import {User} from 'common/user' diff --git a/web/components/answers/compatibility-questions-display.tsx b/web/components/answers/compatibility-questions-display.tsx index 0e5627c3..999276b6 100644 --- a/web/components/answers/compatibility-questions-display.tsx +++ b/web/components/answers/compatibility-questions-display.tsx @@ -1,4 +1,4 @@ -import {PencilIcon, TrashIcon} from '@heroicons/react/outline' +import {PencilIcon, TrashIcon} from '@heroicons/react/24/outline' import clsx from 'clsx' import { getAnswerCompatibility, diff --git a/web/components/answers/free-response-add-question.tsx b/web/components/answers/free-response-add-question.tsx index 003dc297..f901eaed 100644 --- a/web/components/answers/free-response-add-question.tsx +++ b/web/components/answers/free-response-add-question.tsx @@ -1,4 +1,4 @@ -import {ArrowLeftIcon, PlusIcon} from '@heroicons/react/outline' +import {ArrowLeftIcon, PlusIcon} from '@heroicons/react/24/outline' import clsx from 'clsx' import {User} from 'common/user' import {TbMessage} from 'react-icons/tb' diff --git a/web/components/answers/free-response-display.tsx b/web/components/answers/free-response-display.tsx index b46d0279..96425f75 100644 --- a/web/components/answers/free-response-display.tsx +++ b/web/components/answers/free-response-display.tsx @@ -1,4 +1,4 @@ -import {PencilIcon, XIcon} from '@heroicons/react/outline' +import {PencilIcon, XMarkIcon} from '@heroicons/react/24/outline' import {Profile} from 'common/profiles/profile' import {Row as rowFor} from 'common/supabase/utils' import {User} from 'common/user' @@ -122,7 +122,7 @@ function AnswerBlock(props: { }, { name: t('answers.menu.delete', 'Delete'), - icon: , + icon: , onClick: () => deleteAnswer(answer, user.id).then(() => refreshAnswers()), }, { diff --git a/web/components/answers/opinion-scale-display.tsx b/web/components/answers/opinion-scale-display.tsx index 167da38e..60c9306f 100644 --- a/web/components/answers/opinion-scale-display.tsx +++ b/web/components/answers/opinion-scale-display.tsx @@ -1,4 +1,4 @@ -import {PencilIcon} from '@heroicons/react/outline' +import {PencilIcon} from '@heroicons/react/24/outline' import clsx from 'clsx' import {Row as rowFor} from 'common/supabase/utils' import {capitalize, orderBy} from 'lodash' diff --git a/web/components/back-button.tsx b/web/components/back-button.tsx index 713a9efc..2d57f1d7 100644 --- a/web/components/back-button.tsx +++ b/web/components/back-button.tsx @@ -1,4 +1,4 @@ -import {ArrowLeftIcon} from '@heroicons/react/solid' +import {ArrowLeftIcon} from '@heroicons/react/24/solid' import clsx from 'clsx' import {useRouter} from 'next/navigation' import {useEffect, useState} from 'react' diff --git a/web/components/bio/profile-bio-block.tsx b/web/components/bio/profile-bio-block.tsx index e5bafe3e..d90c679a 100644 --- a/web/components/bio/profile-bio-block.tsx +++ b/web/components/bio/profile-bio-block.tsx @@ -1,4 +1,4 @@ -import {PencilIcon, XIcon} from '@heroicons/react/outline' +import {PencilIcon, XMarkIcon} from '@heroicons/react/24/outline' import {JSONContent} from '@tiptap/core' import clsx from 'clsx' import {Profile} from 'common/profiles/profile' @@ -61,7 +61,7 @@ export function BioBlock(props: { }, { name: t('profile.bio.delete', 'Delete'), - icon: , + icon: , onClick: async () => { const {error} = await tryCatch(updateProfile({bio: null})) if (error) console.error(error) diff --git a/web/components/bio/profile-bio.tsx b/web/components/bio/profile-bio.tsx index a320bf1a..f74269cf 100644 --- a/web/components/bio/profile-bio.tsx +++ b/web/components/bio/profile-bio.tsx @@ -1,4 +1,4 @@ -import {QuestionMarkCircleIcon} from '@heroicons/react/outline' +import {QuestionMarkCircleIcon} from '@heroicons/react/24/outline' import {JSONContent} from '@tiptap/core' import {MAX_INT, MIN_BIO_LENGTH} from 'common/constants' import {Profile} from 'common/profiles/profile' diff --git a/web/components/browse-matches-button.tsx b/web/components/browse-matches-button.tsx index e431c1fa..2841039c 100644 --- a/web/components/browse-matches-button.tsx +++ b/web/components/browse-matches-button.tsx @@ -141,7 +141,7 @@ // className={'!h-10 max-w-[200px] self-end text-sm'} // value={query} // placeholder={'Search name'} -// onChange={(e) => { +// onChange={(e: React.ChangeEvent) => { // setQuery(e.target.value) // }} // /> diff --git a/web/components/buttons/button.tsx b/web/components/buttons/button.tsx index f6c079da..7ff54681 100644 --- a/web/components/buttons/button.tsx +++ b/web/components/buttons/button.tsx @@ -1,5 +1,5 @@ import clsx from 'clsx' -import {forwardRef, MouseEventHandler, ReactNode, Ref} from 'react' +import {ComponentPropsWithoutRef, forwardRef, MouseEventHandler, ReactNode, Ref} from 'react' import {LoadingIndicator} from 'web/components/widgets/loading-indicator' export type SizeType = '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' @@ -75,7 +75,7 @@ export const Button = forwardRef(function Button( color?: ColorType | null type?: 'button' | 'reset' | 'submit' loading?: boolean - } & JSX.IntrinsicElements['button'], + } & ComponentPropsWithoutRef<'button'>, ref: Ref, ) { const { diff --git a/web/components/buttons/confirmation-button.tsx b/web/components/buttons/confirmation-button.tsx index 8180b18e..ffc8edf9 100644 --- a/web/components/buttons/confirmation-button.tsx +++ b/web/components/buttons/confirmation-button.tsx @@ -1,5 +1,5 @@ import clsx from 'clsx' -import {ReactNode, useState} from 'react' +import {ReactElement, ReactNode, useState} from 'react' import {Col} from '../layout/col' import {Modal} from '../layout/modal' @@ -9,7 +9,7 @@ import {Button, ColorType, SizeType} from './button' export function ConfirmationButton(props: { openModalBtn: { label: string - icon?: JSX.Element + icon?: ReactElement className?: string color?: ColorType size?: SizeType @@ -84,7 +84,7 @@ export function ConfirmationButton(props: { @@ -152,7 +156,7 @@ export function SimpleCopyTextButton(props: { noTap placement="bottom" > -