diff --git a/.env.dev b/.env.dev index a0f1e2eb7..372407f3c 100644 --- a/.env.dev +++ b/.env.dev @@ -21,8 +21,12 @@ SECRET_KEY='secret' DEBUG='1' ACTIVIST_EMAIL="noreply@activist.org" -EMAIL_HOST="smtp.activist.org" -EMAIL_PORT="587" -EMAIL_HOST_USER="activist@activist.org" -EMAIL_HOST_PASSWORD="activist123!?" -EMAIL_USE_TLS="True" +EMAIL_BACKEND="django.core.mail.backends.smtp.EmailBackend" +EMAIL_HOST="mailhog" +EMAIL_PORT="1025" +EMAIL_HOST_USER="" +EMAIL_HOST_PASSWORD="" +EMAIL_USE_TLS="False" + +NUXT_SESSION_PASSWORD="password-with-at-least-32-characters" +VITE_BACKEND_URL_PROXY="http://backend:8000" diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index c631429de..e2fda1cbe 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -55,7 +55,7 @@ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. +representative at an online or physical event. ## Enforcement diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a9169253f..025c0b18a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -14,15 +14,22 @@ Thank you for your pull request! 🚀 ### Description +Description of the proposed change... + ### Related issue - + - #ISSUE_NUMBER diff --git a/.github/workflows/check_dependency_updates.yaml b/.github/workflows/check_dependency_updates.yaml index c61486e49..d71bc1a9b 100644 --- a/.github/workflows/check_dependency_updates.yaml +++ b/.github/workflows/check_dependency_updates.yaml @@ -1,7 +1,7 @@ name: check_dependency_updates on: schedule: - - cron: '0 0 15 */2 *' + - cron: "0 0 15 */2 *" workflow_dispatch: jobs: @@ -26,10 +26,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Node Environment - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 20 @@ -39,9 +39,9 @@ jobs: echo "## Available Update ⚙️" >> reports.md - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: - python-version: '3.11' + python-version: "3.12" - name: Setup Yarn working-directory: ./frontend diff --git a/.github/workflows/pr_ci_backend.yaml b/.github/workflows/ci_backend_pytest.yaml similarity index 53% rename from .github/workflows/pr_ci_backend.yaml rename to .github/workflows/ci_backend_pytest.yaml index fa0831b47..53c3ebf92 100644 --- a/.github/workflows/pr_ci_backend.yaml +++ b/.github/workflows/ci_backend_pytest.yaml @@ -1,4 +1,4 @@ -name: pr_ci_backend +name: ci_backend_pytest on: workflow_dispatch: pull_request: @@ -25,7 +25,7 @@ env: DATABASE_PASSWORD: postgres jobs: - backend: + backend_tests: services: postgres: image: postgres:15 @@ -42,45 +42,32 @@ jobs: checks: write pull-requests: write - name: Run PR Backend Check + name: Run PR Backend Tests runs-on: ubuntu-latest + defaults: + run: + working-directory: ./backend steps: - name: Checkout Project - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python Environment - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: - python-version: "3.11" - - - name: Create Environment and Install Dependencies - run: | - python -m pip install --upgrade uv - uv venv - . .venv/bin/activate - echo PATH=$PATH >> $GITHUB_ENV - uv pip install -r backend/requirements-dev.txt - - - name: Run Ruff Format - Formatting Check - run: ruff format ./backend + python-version: "3.13" - - name: Run Ruff - Linting and Import Sorting Check - if: always() - run: ruff check ./backend + - name: Install uv + uses: astral-sh/setup-uv@v7 - - name: Run mypy - Static Type Checking - if: always() - run: mypy ./backend --config-file ./backend/pyproject.toml + - name: Install Dependencies + run: uv sync --frozen --all-extras - name: Run Django Migrations - Database Migrations Check - if: always() run: | - . .venv/bin/activate - python ./backend/manage.py makemigrations - python ./backend/manage.py migrate + uv run manage.py makemigrations + uv run manage.py migrate - name: Run pytest - Unit Tests if: always() - working-directory: ./backend run: | - pytest . --cov=. --cov-report=term-missing --cov-fail-under=90 --cov-config=./pyproject.toml -vv + uv run pytest . --cov=. --cov-report=term-missing --cov-fail-under=90 --cov-config=./pyproject.toml -vv diff --git a/.github/workflows/ci_backend_static_analysis.yaml b/.github/workflows/ci_backend_static_analysis.yaml new file mode 100644 index 000000000..5af28b061 --- /dev/null +++ b/.github/workflows/ci_backend_static_analysis.yaml @@ -0,0 +1,50 @@ +name: ci_backend_static_analysis +on: + workflow_dispatch: + pull_request: + branches: + - main + types: + - opened + - reopened + - synchronize + paths: + - "backend/**" + push: + branches: + - main + paths: + - "backend/**" + +jobs: + backend_static_analysis: + name: Run PR Backend Static Check + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./backend + steps: + - name: Checkout Project + uses: actions/checkout@v6 + + - name: Set up Python Environment + uses: actions/setup-python@v6 + with: + python-version: "3.13" + + - name: Install uv + uses: astral-sh/setup-uv@v7 + + - name: Install Dependencies + run: uv sync --frozen --all-extras + + - name: Run Ruff Format - Formatting Check + run: uv run ruff format . + + - name: Run Ruff - Linting and Import Sorting Check + if: always() + run: uv run ruff check . + + - name: Run mypy - Static Type Checking + if: always() + run: uv run mypy . --config-file ./pyproject.toml diff --git a/.github/workflows/pr_ci_playwright_e2e.yaml b/.github/workflows/ci_e2e_playwright_desktop.yaml similarity index 56% rename from .github/workflows/pr_ci_playwright_e2e.yaml rename to .github/workflows/ci_e2e_playwright_desktop.yaml index 2fce581e8..d2b42adb8 100644 --- a/.github/workflows/pr_ci_playwright_e2e.yaml +++ b/.github/workflows/ci_e2e_playwright_desktop.yaml @@ -1,19 +1,46 @@ -name: pr_ci_playwright_e2e +name: ci_e2e_playwright_desktop on: workflow_dispatch: + pull_request: + branches: + - main + types: + - opened + - reopened + - synchronize + paths: + # Note: We run only the desktop e2e tests for backend changes to catch regressions. + - "backend/**" + - "!backend/**/tests/**/*.py" + - "frontend/**" + - "!frontend/test/**" + - "!frontend/i18n/**" + - ".github/workflows/ci_e2e_playwright_desktop.yaml" + - ".github/workflows/ci_e2e_playwright_mobile.yaml" + push: + branches: + - main + paths: + # Note: We run only the desktop e2e tests for backend changes to catch regressions. + - "backend/**" + - "!backend/**/tests/**/*.py" + - "frontend/**" + - "!frontend/test/**" + - "!frontend/i18n/**" + - ".github/workflows/ci_e2e_playwright_desktop.yaml" + - ".github/workflows/ci_e2e_playwright_mobile.yaml" jobs: - frontend: - name: Run PR Frontend E2E Check + frontend-e2e-desktop: + name: E2E Desktop Chrome runs-on: ubuntu-latest - environment: dev steps: - name: Cleanup Old Checkout run: chmod +w -R ${GITHUB_WORKSPACE}; rm -rf ${GITHUB_WORKSPACE}/*; - name: Checkout Project - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Clean Any Existing Containers run: | @@ -35,10 +62,10 @@ jobs: - name: Wait for Backend run: | - timeout 90 bash -c 'until curl -s http://localhost:8000 >/dev/null; do sleep 2; done' + timeout 180 bash -c 'until curl -s http://localhost:8000/v1/auth/sign_in -o /dev/null -w "%{http_code}" | grep -qE "^(200|405)"; do sleep 3; done' - name: Setup Node Environment - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 24 @@ -49,16 +76,18 @@ jobs: - name: Install Dependencies and Build working-directory: ./frontend env: + USE_PREVIEW: true VITE_FRONTEND_URL: http://localhost:3000 VITE_BACKEND_URL: http://localhost:8000 VITE_API_URL: http://localhost:8000/v1 + VITE_BACKEND_URL_PROXY: http://localhost:8000 run: | sudo corepack enable sudo yarn install sudo -E yarn build - if [ ! -f "dist/index.html" ]; then - echo "Build failed: dist/index.html not found" + if [ ! -d ".output" ]; then + echo "Build failed: .output directory not found" exit 1 fi @@ -71,13 +100,18 @@ jobs: sudo -E yarn playwright install --with-deps chromium sudo chmod -R 755 /opt/playwright-browsers - - name: Start Static Server + - name: Start Preview Server working-directory: ./frontend + env: + NUXT_SESSION_PASSWORD: "password-with-at-least-32-characters" + VITE_BACKEND_URL: http://localhost:8000 + VITE_API_URL: http://localhost:8000/v1 + VITE_BACKEND_URL_PROXY: http://localhost:8000 + PORT: 3000 run: | - npm install -g serve - nohup serve dist -l 3000 > server.log 2>&1 & + nohup sudo -E yarn preview --port 3000 > server.log 2>&1 & echo $! > server.pid - sleep 3 + sleep 5 if ! ps -p $(cat server.pid) > /dev/null; then echo "Server failed to start:" @@ -102,18 +136,22 @@ jobs: curl -s http://localhost:8000/v1/entities/events/ > /dev/null || true sleep 3 - - name: Run Playwright Tests + - name: Run Playwright Tests (Desktop Chrome) working-directory: ./frontend env: - FAST_TESTS: true # only Desktop Chrome + Mobile Chrome - SKIP_WEBSERVER: true # Server already started manually + FAST_TESTS: true + SKIP_WEBSERVER: true PLAYWRIGHT_BROWSERS_PATH: /opt/playwright-browsers - run: sudo -E yarn playwright test + NUXT_SESSION_PASSWORD: "password-with-at-least-32-characters" + VITE_BACKEND_URL: http://localhost:8000 + VITE_API_URL: http://localhost:8000/v1 + VITE_BACKEND_URL_PROXY: http://localhost:8000 + run: sudo -E yarn playwright test --project="Desktop Chrome" - name: Upload Playwright Report if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: - name: playwright-report + name: playwright-report-desktop path: frontend/playwright-report/ retention-days: 30 diff --git a/.github/workflows/ci_e2e_playwright_mobile.yaml b/.github/workflows/ci_e2e_playwright_mobile.yaml new file mode 100644 index 000000000..e0c77006c --- /dev/null +++ b/.github/workflows/ci_e2e_playwright_mobile.yaml @@ -0,0 +1,157 @@ +name: ci_e2e_playwright_mobile +on: + workflow_dispatch: + pull_request: + branches: + - main + types: + - opened + - reopened + - synchronize + paths: + # Note: We run only the desktop e2e tests for backend changes to catch regressions. + # - "backend/**" + # - "!backend/**/tests/**/*.py" + - "frontend/**" + - "!frontend/test/**" + - "!frontend/i18n/**" + - ".github/workflows/ci_e2e_playwright_desktop.yaml" + - ".github/workflows/ci_e2e_playwright_mobile.yaml" + push: + branches: + - main + paths: + # Note: We run only the desktop e2e tests for backend changes to catch regressions. + # - "backend/**" + # - "!backend/**/tests/**/*.py" + - "frontend/**" + - "!frontend/test/**" + - "!frontend/i18n/**" + - ".github/workflows/ci_e2e_playwright_desktop.yaml" + - ".github/workflows/ci_e2e_playwright_mobile.yaml" + +jobs: + frontend-e2e-mobile: + name: E2E Mobile Chrome + runs-on: ubuntu-latest + + steps: + - name: Cleanup Old Checkout + run: chmod +w -R ${GITHUB_WORKSPACE}; rm -rf ${GITHUB_WORKSPACE}/*; + + - name: Checkout Project + uses: actions/checkout@v6 + + - name: Clean Any Existing Containers + run: | + docker stop $(docker ps -aq) || true + docker rm $(docker ps -aq) || true + + - name: Check Port Availability + run: | + ! nc -z localhost 3000 && \ + ! nc -z localhost 8000 && \ + ! nc -z localhost 5432 + + - name: Run Docker Compose + run: docker compose --env-file .env.dev up --build -d backend db + + - name: Wait for Database + run: | + timeout 60 bash -c 'until docker compose --env-file .env.dev exec -T db pg_isready -U postgres; do sleep 2; done' + + - name: Wait for Backend + run: | + timeout 180 bash -c 'until curl -s http://localhost:8000/v1/auth/sign_in -o /dev/null -w "%{http_code}" | grep -qE "^(200|405)"; do sleep 3; done' + + - name: Setup Node Environment + uses: actions/setup-node@v5 + with: + node-version: 24 + + - uses: c-py/action-dotenv-to-setenv@v5 + with: + env-file: .env.dev + + - name: Install Dependencies and Build + working-directory: ./frontend + env: + USE_PREVIEW: true + VITE_FRONTEND_URL: http://localhost:3000 + VITE_BACKEND_URL: http://localhost:8000 + VITE_API_URL: http://localhost:8000/v1 + VITE_BACKEND_URL_PROXY: http://localhost:8000 + run: | + sudo corepack enable + sudo yarn install + sudo -E yarn build + + if [ ! -d ".output" ]; then + echo "Build failed: .output directory not found" + exit 1 + fi + + - name: Install Playwright Browsers + working-directory: ./frontend + env: + PLAYWRIGHT_BROWSERS_PATH: /opt/playwright-browsers + run: | + sudo mkdir -p /opt/playwright-browsers + sudo -E yarn playwright install --with-deps chromium + sudo chmod -R 755 /opt/playwright-browsers + + - name: Start Preview Server + working-directory: ./frontend + env: + NUXT_SESSION_PASSWORD: "password-with-at-least-32-characters" + VITE_BACKEND_URL: http://localhost:8000 + VITE_API_URL: http://localhost:8000/v1 + VITE_BACKEND_URL_PROXY: http://localhost:8000 + PORT: 3000 + run: | + nohup sudo -E yarn preview --port 3000 > server.log 2>&1 & + echo $! > server.pid + sleep 5 + + if ! ps -p $(cat server.pid) > /dev/null; then + echo "Server failed to start:" + cat server.log + exit 1 + fi + + - name: Wait for Frontend + working-directory: ./frontend + run: | + yarn wait-on http://localhost:3000 --timeout 60000 || { + echo "Frontend server not responding:" + cat server.log + exit 1 + } + + - name: Warm Up Backend + run: | + curl -s -X OPTIONS http://localhost:8000/v1/auth/sign_in > /dev/null || true + curl -s http://localhost:8000/v1/entities/users/ > /dev/null || true + curl -s http://localhost:8000/v1/entities/organizations/ > /dev/null || true + curl -s http://localhost:8000/v1/entities/events/ > /dev/null || true + sleep 3 + + - name: Run Playwright Tests (Mobile Chrome) + working-directory: ./frontend + env: + FAST_TESTS: true + SKIP_WEBSERVER: true + PLAYWRIGHT_BROWSERS_PATH: /opt/playwright-browsers + NUXT_SESSION_PASSWORD: "password-with-at-least-32-characters" + VITE_BACKEND_URL: http://localhost:8000 + VITE_API_URL: http://localhost:8000/v1 + VITE_BACKEND_URL_PROXY: http://localhost:8000 + run: sudo -E yarn playwright test --project="Mobile Chrome" + + - name: Upload Playwright Report + if: always() + uses: actions/upload-artifact@v6 + with: + name: playwright-report-mobile + path: frontend/playwright-report/ + retention-days: 30 diff --git a/.github/workflows/pr_ci_frontend.yaml b/.github/workflows/ci_frontend_static_analysis.yaml similarity index 70% rename from .github/workflows/pr_ci_frontend.yaml rename to .github/workflows/ci_frontend_static_analysis.yaml index 90cfff807..85c787121 100644 --- a/.github/workflows/pr_ci_frontend.yaml +++ b/.github/workflows/ci_frontend_static_analysis.yaml @@ -1,4 +1,4 @@ -name: pr_ci_frontend +name: ci_frontend_static_analysis on: workflow_dispatch: pull_request: @@ -17,15 +17,15 @@ on: - "frontend/**" jobs: - frontend: - name: Run PR Frontend Check + frontend_static_analysis: + name: Run PR Frontend Static Check runs-on: ubuntu-latest steps: - name: Checkout Project - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Node environment - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 - name: Install dependencies via Yarn working-directory: ./frontend @@ -33,10 +33,6 @@ jobs: corepack enable sudo yarn install - - name: Install Prettier - working-directory: ./frontend - run: sudo yarn add prettier - - name: Run Prettier - Formatting Check working-directory: ./frontend run: | @@ -51,8 +47,3 @@ jobs: if: always() working-directory: ./frontend run: sudo yarn lint - - - name: Run Vitest - Component Testing - if: always() - working-directory: ./frontend - run: sudo yarn test --coverage --silent diff --git a/.github/workflows/ci_frontend_vitest.yaml b/.github/workflows/ci_frontend_vitest.yaml new file mode 100644 index 000000000..d9931cff5 --- /dev/null +++ b/.github/workflows/ci_frontend_vitest.yaml @@ -0,0 +1,40 @@ +name: ci_frontend_vitest +on: + workflow_dispatch: + pull_request: + branches: + - main + types: + - opened + - reopened + - synchronize + paths: + - "frontend/**" + - "!frontend/test-e2e" + push: + branches: + - main + paths: + - "frontend/**" + - "!frontend/test-e2e" + +jobs: + frontend_tests: + name: Run PR Frontend Tests + runs-on: ubuntu-latest + steps: + - name: Checkout Project + uses: actions/checkout@v6 + + - name: Setup Node environment + uses: actions/setup-node@v5 + + - name: Install dependencies via Yarn + working-directory: ./frontend + run: | + corepack enable + sudo yarn install + + - name: Run Vitest - Component Testing + working-directory: ./frontend + run: sudo yarn test --coverage --silent diff --git a/.github/workflows/ci_i18n_check.yaml b/.github/workflows/ci_i18n_check.yaml new file mode 100644 index 000000000..4665d46bf --- /dev/null +++ b/.github/workflows/ci_i18n_check.yaml @@ -0,0 +1,39 @@ +name: ci_i18n_check +on: + workflow_dispatch: + pull_request: + branches: + - main + types: + - opened + - reopened + - synchronize + paths: + - "frontend/**" + push: + branches: + - main + paths: + - "frontend/**" + +jobs: + i18n_check: + runs-on: ubuntu-latest + steps: + - name: Checkout Project + uses: actions/checkout@v6 + + - name: Setup Python + uses: actions/setup-python@v6 + with: + python-version: "3.13" + + - name: Install uv + uses: astral-sh/setup-uv@v7 + + - name: Install Dependencies + run: uv sync --frozen --all-extras + working-directory: ./backend + + - name: Execute All i18n-check Key-Value Checks + run: uv run --project ./backend i18n-check -a diff --git a/.github/workflows/pr_ci_license_header_check.yaml b/.github/workflows/ci_license_header_check.yaml similarity index 84% rename from .github/workflows/pr_ci_license_header_check.yaml rename to .github/workflows/ci_license_header_check.yaml index f4e37913c..41c7166e4 100644 --- a/.github/workflows/pr_ci_license_header_check.yaml +++ b/.github/workflows/ci_license_header_check.yaml @@ -1,4 +1,4 @@ -name: pr_ci_license_header_check +name: ci_license_header_check on: workflow_dispatch: pull_request: @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Project - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Verify License Headers uses: apache/skywalking-eyes/header@main diff --git a/.github/workflows/ci_ts_backend_check.yaml b/.github/workflows/ci_ts_backend_check.yaml new file mode 100644 index 000000000..b27a51fe1 --- /dev/null +++ b/.github/workflows/ci_ts_backend_check.yaml @@ -0,0 +1,42 @@ +name: ci_ts_backend_check +on: + workflow_dispatch: + pull_request: + branches: + - main + types: + - opened + - reopened + - synchronize + paths: + - "backend/**/model.py" + - "frontend/shared/types/**/*.{ts, d.ts}" + push: + branches: + - main + paths: + - "backend/**/model.py" + - "frontend/shared/types/**/*.{ts, d.ts}" + +jobs: + ts_backend_check: + runs-on: ubuntu-latest + steps: + - name: Checkout Project + uses: actions/checkout@v6 + + - name: Setup Python + uses: actions/setup-python@v6 + with: + python-version: "3.13" + + - name: Install uv + uses: astral-sh/setup-uv@v7 + + - name: Install Dependencies + run: uv sync --frozen --all-extras + working-directory: ./backend + + - name: Check Django Models Against TypeScript Interfaces + run: | + # ts-backend-check -a diff --git a/.github/workflows/owasp_zap_full_scan.yaml b/.github/workflows/owasp_zap_full_scan.yaml index eb7f58826..6c7250ce1 100644 --- a/.github/workflows/owasp_zap_full_scan.yaml +++ b/.github/workflows/owasp_zap_full_scan.yaml @@ -2,7 +2,7 @@ name: OWASP ZAP Optimized Security Scan on: workflow_dispatch: schedule: - - cron: '0 2 * * 1' # Run weekly on Mondays at 2 AM UTC + - cron: "0 2 * * 1" # Run weekly on Mondays at 2 AM UTC jobs: zap_scan: @@ -10,7 +10,7 @@ jobs: name: Security Scan with OWASP ZAP steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Create reports directory with proper permissions run: | @@ -32,7 +32,7 @@ jobs: ls -la zap-reports/ - name: Upload ZAP Scan Results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: zap-scan-results path: zap-reports/ diff --git a/.github/workflows/pr_ci_i18n.yaml b/.github/workflows/pr_ci_i18n.yaml deleted file mode 100644 index 98b5ae278..000000000 --- a/.github/workflows/pr_ci_i18n.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: pr_ci_i18n -on: - workflow_dispatch: - pull_request: - branches: - - main - types: - - opened - - reopened - - synchronize - paths: - - "frontend/**" - push: - branches: - - main - paths: - - "frontend/**" - -jobs: - i18n_check: - runs-on: ubuntu-latest - steps: - - name: Checkout Project - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Create Environment and Install Dependencies - run: | - python -m pip install --upgrade uv - uv venv - . .venv/bin/activate - uv pip install -r backend/requirements-dev.txt - echo "$PWD/.venv/bin" >> $GITHUB_PATH - - - name: Execute All i18n-check Key-Value Checks - run: | - i18n-check -a diff --git a/.github/workflows/pr_ci_ts_backend_check.yaml b/.github/workflows/pr_ci_ts_backend_check.yaml deleted file mode 100644 index d109a5ccb..000000000 --- a/.github/workflows/pr_ci_ts_backend_check.yaml +++ /dev/null @@ -1,46 +0,0 @@ -name: pr_ci_ts_backend_check -on: - workflow_dispatch: - pull_request: - branches: - - main - types: - - opened - - reopened - - synchronize - paths: - - "backend/**/model.py" - - "frontend/types/**/*.{ts, d.ts}" - push: - branches: - - main - paths: - - "backend/**/model.py" - - "frontend/types/**/*.{ts, d.ts}" - -jobs: - ts_backend_check: - runs-on: ubuntu-latest - steps: - - name: Checkout Project - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Create Environment and Install Dependencies - run: | - python -m pip install --upgrade uv - uv venv - . .venv/bin/activate - echo PATH=$PATH >> $GITHUB_ENV - uv pip install -r backend/requirements-dev.txt - - - name: Check Django Models Against TypeScript Interfaces - run: | - # ts-backend-check -bmf backend/authentication/models.py -tsf frontend/types/auth/user.d.ts - # ts-backend-check -bmf backend/communities/groups/models.py -tsf frontend/types/communities/groups.d.ts - # ts-backend-check -bmf backend/communities/organizations/models.py -tsf frontend/types/communities/organizations.d.ts - # ts-backend-check -bmf backend/events/models.py -tsf frontend/types/events/events.d.ts diff --git a/.github/workflows/pr_maintainer_checklist.yaml b/.github/workflows/pr_maintainer_checklist.yaml index f8f189a02..922642d59 100644 --- a/.github/workflows/pr_maintainer_checklist.yaml +++ b/.github/workflows/pr_maintainer_checklist.yaml @@ -14,25 +14,32 @@ jobs: pull-requests: write steps: - name: Thank You Message - uses: thollander/actions-comment-pull-request@v2 + uses: thollander/actions-comment-pull-request@v3 with: message: | ## Thank you for the pull request! ❤️ - The activist team will do our best to address your contribution as soon as we can. If you're not already a member of our [public Matrix community](https://matrix.to/#/#activist_community:matrix.org), please consider joining! We'd suggest that you use the [Element](https://element.io/) client as well as [Element X](https://element.io/app) for a mobile app, and definitely join the `General` and `Development` rooms once you're in. Also consider attending our [bi-weekly Saturday developer syncs](https://etherpad.wikimedia.org/p/activist-dev-sync)! It'd be great to meet you 😊 + The activist team will do our best to address your contribution as soon as we can. The following are some important points: + - Those interested in developing their skills and expanding their role in the community should read the [mentorship and growth section of the contribution guide](CONTRIBUTING.md#mentorship-and-growth-) + - If you're not already a member of our [public Matrix community](https://matrix.to/#/#activist_community:matrix.org), please consider joining! + - We'd suggest that you use the [Element](https://element.io/) client as well as [Element X](https://element.io/app) for a mobile app + - Join the `General` and `Development` rooms once you're in + - Also consider attending our bi-weekly Saturday developer syncs! + - Details are shared in the `Development` room on Matrix each Wednesday before the sync + - It would be great to meet you 😊 > [!NOTE] > activist uses [Conventional Comments](https://conventionalcomments.org/) in reviews to make sure that communication is as clear as possible. - name: Add Checklist - uses: thollander/actions-comment-pull-request@v2 + uses: thollander/actions-comment-pull-request@v3 with: message: | ## Maintainer Checklist The following is a checklist for maintainers to make sure this process goes as well as possible. Feel free to address the points below yourself in further commits if you realize that actions are needed :) - - [ ] The TypeScript, pytest and formatting workflows within the [PR checks](https://github.com/activist-org/activist/pull/${{ github.event.pull_request.number }}/checks) do not indicate new errors in the files changed + - [ ] Tests for changes have been written and the TypeScript, pytest and formatting workflows within the [PR checks](https://github.com/activist-org/activist/pull/${{ github.event.pull_request.number }}/checks) do not indicate new errors in the files changed - [ ] The Playwright end to end and Zap penetration tests have been ran and are passing (if necessary) diff --git a/.gitignore b/.gitignore index 1a496bfe5..e4c8310fc 100644 --- a/.gitignore +++ b/.gitignore @@ -65,6 +65,7 @@ frontend/!.yarn/plugins frontend/!.yarn/releases frontend/!.yarn/sdks frontend/!.yarn/versions +**/package-lock.json # Media backend/media/images/* @@ -79,3 +80,6 @@ backend/media/images/* # ZAP Security Reports zap-reports/ frontend/test-e2e/.auth/ + +# Snyk Security Extension +.cursor/rules/snyk_rules.mdc diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5a96a9643..6a19b36a2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -28,21 +28,12 @@ repos: files: ^backend/ exclude: ^backend/(.*/?(tests(/.*)?|views\.py|__init__\.py))$ - - repo: https://github.com/to-sta/spdx-checker-pre-commit - rev: 0.1.3 - hooks: - - id: spdx-license-checker - name: run spdx-checker license check - exclude: ^(?:.*/)?__init__\.py$ - args: [-l, AGPL-3.0-or-later] - types_or: [python, ts, javascript, vue, css, html] - - repo: local hooks: - id: mypy-check name: run mypy static type checking files: ^backend/ - entry: mypy ./backend --config-file ./backend/pyproject.toml + entry: uv run mypy ./backend --config-file ./backend/pyproject.toml language: python types: [python] pass_filenames: false @@ -57,8 +48,17 @@ repos: - id: run-i18n-check name: run i18n-check key-value checks files: ^frontend/ - entry: i18n-check -a + entry: uv run i18n-check -a language: python pass_filenames: false additional_dependencies: - i18n-check + + - repo: https://github.com/to-sta/spdx-checker-pre-commit + rev: 0.1.7 + hooks: + - id: spdx-license-checker + name: run spdx-checker license check + exclude: ^(?:.*/)?__init__\.py$ + args: [-l, AGPL-3.0-or-later, --fix, --continue-on-error] + types_or: [python, ts, javascript, vue, css, html] diff --git a/.prettierignore b/.prettierignore index 90b5b4b4d..9bc57f501 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,6 +4,7 @@ node_modules/ venv/ dist/ +coverage/ playwright-report/ tests-examples/ test-results/ diff --git a/BACKEND_TESTING.md b/BACKEND_TESTING.md index d93f0c0d6..54daf3f6c 100644 --- a/BACKEND_TESTING.md +++ b/BACKEND_TESTING.md @@ -1,16 +1,14 @@ + + # Backend Testing This documentation details standards for writing pytest based backend testing files. - - -## **Contents** +## Contents - [Standards](#standards-) - - -## Standards [`⇧`](#contents) +## Standards - All tests for backend applications should be in a `tests` sub directory - Testing files should be named `test_ENTITY_{MODEL_SUB_CLASS}_CRUD_METHOD`, with the `MODEL_SUB_CLASS` being optional @@ -30,3 +28,5 @@ This documentation details standards for writing pytest based backend testing fi - Start with the name of the file - End with the response code that is being tested if there is only one - If there is only one API endpoint used in a testing file, it should be defined as a `SCREAMING_SNAKE_CASE` variable at the top of the file + +Back to top. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 231cc566e..0ec4e2ef0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,38 +1,36 @@ + + # Contributing to activist.org Thank you for contributing to activist! Please take a moment to review this document in order to make the contribution process easy and effective for everyone involved. -Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open-source project. In return, and in accordance with this project's [code of conduct](.github/CODE_OF_CONDUCT.md), other contributors will reciprocate that respect in addressing your issue or assessing patches and features. +Following this guide helps to communicate that you respect the time of the developers managing and developing this open-source project. In return, and in accordance with this project's [code of conduct](.github/CODE_OF_CONDUCT.md), other contributors will reciprocate that respect in addressing your issue or assessing patches and features. If you have questions or would like to communicate with the team, please [join us in our public Matrix chat rooms](https://matrix.to/#/#activist_community:matrix.org). We'd be happy to hear from you! - - -## **Contents** - -- [First steps as a contributor](#first-steps-) -- [Tech stack](#tech-stack-) -- [Learning the tech stack](#learning-the-tech-stack-) -- [Development environment](#dev-env-) -- [Style guide](#style-guide-) -- [Linting](#linting-) -- [Testing](#testing-) -- [Issues and projects](#issues-projects-) -- [Bug reports](#bug-reports-) -- [Feature requests](#feature-requests-) -- [Pull requests](#pull-requests-) -- [Localization](#localization-) -- [Documentation](#documentation-) -- [Accessibility](#accessibility-) -- [Internationalization](#internationalization-) -- [Design](#design-) -- [Troubleshooting](#troubleshooting-) - - - -## First steps as a contributor [`⇧`](#contents) +## Contents + +- [First steps as a contributor](#first-steps-as-a-contributor) +- [Mentorship and growth](#mentorship-and-growth) +- [Tech stack](#tech-stack) +- [Learning the tech stack](#learning-the-tech-stack) +- [Development environment](#development-environment) +- [Style guide](#style-guide) +- [Linting](#linting) +- [Testing](#testing) +- [Issues and projects](#issues-and-projects) +- [Bug reports](#bug-reports) +- [Feature requests](#feature-requests) +- [Pull requests](#pull-requests) +- [Internationalization](#internationalization) +- [Documentation](#documentation) +- [Accessibility](#accessibility) +- [Design](#design) +- [Troubleshooting](#troubleshooting) + +## First steps as a contributor Thank you for your interest in contributing to activist.org! We look forward to welcoming you to the community and working with you to build a global platform for political action :) The following are some suggested steps for people interested in joining our community: @@ -44,11 +42,23 @@ Thank you for your interest in contributing to activist.org! We look forward to - Read through this contributing guide and the [style guide](STYLEGUIDE.md) for all the information you need to contribute - Look into issues marked [`good first issue`](https://github.com/activist-org/activist/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) and the [Projects board](https://github.com/orgs/activist-org/projects/1) to get a better understanding of what you can work on - Check out our [public designs on Figma](https://www.figma.com/file/I9McFfaLu1RiiWp5IP3YjE/activist_public_designs?type=design&node-id=10%3A18&mode=design&t=tdQyOtl5lU1n7oLN-1) to understand activist's goals and direction -- Consider joining our [bi-weekly developer sync](https://etherpad.wikimedia.org/p/activist-dev-sync)! +- Consider joining our bi-weekly developer sync — new joiners are always welcome! + +Back to top. - +## Mentorship and growth -## Tech Stack [`⇧`](#contents) +Onboarding and mentoring new members are integral parts of any healthy open-source community. We need those who are onboarded to gain new skills and take on greater roles of triaging issues, reviewing contributions and maintaining the project. We also need them to help those who follow do the same. Please let us know if you have such goals and we'll work with you to achieve them. + +The above includes expectations on the behavior of those who want to grow with us. Mentorship is earned, not given. To be blunt, those who are mainly sending AI generated contributions are not demonstrating an interest in growing their skills and are not helping to develop the project. This is not to say that all uses of AI for contributions are bad, but it should be a tool, not the contributor itself. + +Continued constructive contributions, new open issues and communication that provides context for maintainers help them do their work immensely. We would be happy to help such community members expand their skills and take on further responsibilities. + +If the above resonates with you, then we look forward to working with you! + +Back to top. + +## Tech stack The following are the current and planned technologies for [activist.org](https://activist.org): @@ -62,7 +72,11 @@ The following are the current and planned technologies for [activist.org](https: ### Deployment -- [Docker](https://www.docker.com) • [Netlify](https://www.netlify.com) • [Vitest](https://vitest.dev/) +- [Docker](https://www.docker.com) • [Netlify](https://www.netlify.com) + +### Deployment + +[pytest](https://docs.pytest.org/en/stable/) (backend) • [Vitest](https://vitest.dev/) (frontend) • [Playwright](https://playwright.dev/) (end to end) ### Localization @@ -75,9 +89,9 @@ The following are the current and planned technologies for [activist.org](https: > [!NOTE] > Those new to any frameworks or technologies who want to work on their skills are more than welcome to contribute! - +Back to top. -## Learning the tech stack [`⇧`](#contents) +## Learning the tech stack activist is very open to contributions from people in the early stages of their coding journey! The following is a select list of documentation pages to help you understand the technologies we use. @@ -123,9 +137,9 @@ activist is very open to contributions from people in the early stages of their
- +Back to top. -## Development environment [`⇧`](#contents) +## Development environment > [!NOTE] > Windows users should be aware that Docker development requires [Windows Subsystem for Linux (WSL)](https://learn.microsoft.com/windows/wsl/) version 2 or higher. The community would suggest that you clone the repository directly into your WSL environment. @@ -196,20 +210,19 @@ git remote add upstream https://github.com/activist-org/activist.git - `origin` (forked repository) - `upstream` (activist repository) -4. Create a virtual environment for the backend (Python `>=3.11`), activate it and install dependencies: +> [!NOTE] +> First, install `uv` if you don't already have it by following the [official installation guide](https://docs.astral.sh/uv/getting-started/installation/). + +4. Create a virtual environment for the backend (Python `>=3.12`), activate it and install dependencies: ```bash - python3 -m venv venv + cd backend && uv sync --all-extras # create .venv and install all dependencies from uv.lock - # Unix or MacOS: - source venv/bin/activate + # Unix or macOS: + source .venv/bin/activate # Windows: - venv\Scripts\activate.bat - - # After activating venv: - pip install --upgrade pip - pip install -r backend/requirements-dev.txt + .venv\Scripts\activate.bat # .venv\Scripts\activate.ps1 (PowerShell) ``` 5. Start your docker images with the following: @@ -231,8 +244,6 @@ git remote add upstream https://github.com/activist-org/activist.git > [!NOTE] > Feel free to contact the team in the [Development room on Matrix](https://matrix.to/#/!CRgLpGeOBNwxYCtqmK:matrix.org?via=matrix.org&via=acter.global&via=chat.0x7cd.xyz) if you're having problems getting your environment setup! - - ### Using Yarn or Python Dockerized environments are resource intensive - specifically for some Windows users - and may take a very long time to load. If you would like to get just the frontend or backend up and running, please follow the steps below: @@ -249,6 +260,9 @@ cd frontend # Set the environment variables: set -a && source ../.env.dev && set +a +# Install corepack on your machine globally: +npm install -g corepack + # Install and run the project: corepack enable yarn install @@ -292,22 +306,13 @@ From here we need the project's dependencies, with the practice being to create On Unix or MacOS, run: ```bash -python3 -m venv venv # make an environment named venv -source venv/bin/activate # activate the environment -``` +cd backend && uv sync --all-extras # create .venv and install all dependencies from uv.lock -On Windows (using Command Prompt), run: +# Unix or macOS: +source .venv/bin/activate -```bash -python -m venv venv -venv\Scripts\activate.bat -``` - -After activating the virtual environment, install the required dependencies by running: - -```bash -pip install --upgrade pip # make sure that pip is at the latest version -pip install -r backend/requirements-dev.txt # install dependencies +# Windows: +.venv\Scripts\activate.bat # .venv\Scripts\activate.ps1 (PowerShell) ``` Now you can apply the database migrations and fixtures, populate it with sample data, and start the local development server. @@ -335,9 +340,7 @@ You can then visit
-
+Documentation is an invaluable way to contribute to coding projects as it allows others to more easily understand the project structure and contribute. Issues related to documentation are marked with the [`documentation`](https://github.com/activist-org/activist/labels/documentation) label in the [issues](https://github.com/activist-org/activist/issues).
-Localization for activist happens on our [public localization project on Weblate](https://hosted.weblate.org/projects/activist/activist). Join us there if you'd like to help bring activist to other languages!
+### Backend Function Docstrings
-To find issues related to localization, please see the [`localization`](https://github.com/activist-org/activist/issues?q=is%3Aopen+is%3Aissue+label%3Alocalization) label in the [issues](https://github.com/activist-org/activist/issues), and to report a localization issue use the [localization issue form](https://github.com/activist-org/activist/issues/new?assignees=&labels=localization&projects=activist-org%2F1&template=localization.yml). Please also see the [style guide](STYLEGUIDE.md) for more information on how to create new localization keys.
+activist follows [numpydoc conventions](https://numpydoc.readthedocs.io/en/latest/format.html) for documenting functions and Python code.
-> [!IMPORTANT]
-> If you're having issues with the vue/nuxt i18n `$t` local property not being picked up by TypeScript and being reported as invalid/not existing across the codebase, then please add the following file at `frontend/types/vue-i18n.d.ts`:
->
-> ```ts
-> // frontend/types/vue-i18n.d.ts
-> // Attn: Fixes Property '$t' does not exist on type ... errors.
-> // Note: This file is git ignored, but can be used as a local fix for excessive TypeScript errors.
-> declare module "vue" {
-> interface ComponentCustomProperties {
-> $t: (key: string) => string;
-> }
-> }
-> ```
+You can use [prek](https://prek.j178.dev/) to run the numpydoc docstring linting:
+
+```bash
+prek run numpydoc-validation --all-files
+```
-
+Function docstrings should have this format:
-## Documentation [`⇧`](#contents)
+```py
+def example_function(argument: argument_type) -> return_type:
+ """
+ An example docstring for a function so others understand your work.
-Documentation is an invaluable way to contribute to coding projects as it allows others to more easily understand the project structure and contribute. Issues related to documentation are marked with the [`documentation`](https://github.com/activist-org/activist/labels/documentation) label in the [issues](https://github.com/activist-org/activist/issues).
+ Parameters
+ ----------
+ argument : argument_type
+ Description of your argument.
-
+ Returns
+ -------
+ return_value : return_type
+ Description of your return value.
-## Accessibility [`⇧`](#contents)
+ Raises
+ ------
+ ErrorType
+ Description of the error and the condition that raises it.
+ """
+
+ ...
+
+ return return_value
+```
+
+Back to top.
+
+## Accessibility
Thank you for your interest in improving activist's accessibility. We want our platform to not only be usable for all people, but also to provide a welcoming environment within the development community for all. This section lists a few points to account for when checking accessibility constraints during development:
@@ -717,31 +736,51 @@ Tab focusing sadly doesn't work out of the box for many browsers. Chrome works g
Once the above steps are finished you should be able to use tab to navigate web pages :)
-
+Back to top.
+
+## Internationalization
+
+### Weblate
+
+
+
+
+
+Localization for activist happens on our [public localization project on Weblate](https://hosted.weblate.org/projects/activist/activist). Join us there if you'd like to help bring activist to other languages!
+
+To find issues related to localization, please see the [`localization`](https://github.com/activist-org/activist/issues?q=is%3Aopen+is%3Aissue+label%3Alocalization) label in the [issues](https://github.com/activist-org/activist/issues), and to report a localization issue use the [localization issue form](https://github.com/activist-org/activist/issues/new?assignees=&labels=localization&projects=activist-org%2F1&template=localization.yml). Please also see the [style guide](STYLEGUIDE.md) for more information on how to create new localization keys.
+
+> [!IMPORTANT]
+> If you're having issues with the vue/nuxt i18n `$t` local property not being picked up by TypeScript and being reported as invalid/not existing across the codebase, then please add the following file at `frontend/types/vue-i18n.d.ts`:
+>
+> ```ts
+> // frontend/types/vue-i18n.d.ts
+> // Attn: Fixes Property '$t' does not exist on type ... errors.
+> // Note: This file is git ignored, but can be used as a local fix for excessive TypeScript errors.
+> declare module "vue" {
+> interface ComponentCustomProperties {
+> $t: (key: string) => string;
+> }
+> }
+> ```
-## Internationalization [`⇧`](#contents)
+### i18n-check
activist uses [i18n-check](https://github.com/activist-org/i18n-check) to validate our internationalization key-value pairs. The basic commands to check the i18n keys and values are:
```bash
-# Note: You need to have installed the backend/requirements-dev.txt file in your virtual environment.
+# Note: You need to have installed the uv.lock file in your virtual environment.
+i18n-check -h # see the help
i18n-check -a # run all checks
-i18n-check -ki # run key identifiers check
-i18n-check -ik # run invalid keys check
-i18n-check -uk # run unused keys check
-i18n-check -nsk # run non-source keys check
-i18n-check -rk # run repeat keys check
-i18n-check -rv # run repeat values check
-i18n-check -nk # run nested keys check
```
You can also run individual checks. Please see the [documentation for i18n-check](https://i18n-check.readthedocs.io/en/latest/) to learn more.
If you do need to edit the directories and files skipped by certain checks, then these edits can be made in the [.i18n-check.yaml](./.i18n-check.yaml) file. If you're having issues using `i18n-check`, please feel free to contact the team for support!
-
+Back to top.
-## Design [`⇧`](#contents)
+## Design
@@ -753,9 +792,9 @@ Note that the linked Figma file above is the [public facing designs](https://www
All branding elements such as logos, icons, colors and fonts should follow those that are set out in [activist-org/Organization](https://github.com/activist-org/Organization). As the project is fully open source, these elements are also open for discussion. Your efforts in making activist products professional with a distinct and cohesive identity are much appreciated.
-
+Back to top.
-## Troubleshooting [`⇧`](#contents)
+## Troubleshooting
### Nuxt Auto Import Errors
@@ -811,8 +850,10 @@ brew services stop postgresql
2. Locate **PostgreSQL** in the list
3. Right-click and choose **Stop**
-Once stopped, you can safely run Docker services like the Docker Compose commands in the [Development Environment](#dev-env-) section.
+Once stopped, you can safely run Docker services like the Docker Compose commands in the [Development Environment](#development-environment) section.
### Still experiencing problems?
Please feel free to reach out to the team in the [Development room on Matrix](https://matrix.to/#/!CRgLpGeOBNwxYCtqmK:matrix.org?via=matrix.org&via=systemli.org&via=librezo.fr) if you have a question!
+
+Back to top.
diff --git a/FRONTEND_TESTING.md b/FRONTEND_TESTING.md
index a2f30f321..4adbc3511 100644
--- a/FRONTEND_TESTING.md
+++ b/FRONTEND_TESTING.md
@@ -1,14 +1,17 @@
-# Frontend Testing
+
-
+# Frontend Testing
-## **Contents**
-- [End to End Tests](#end-to-end-tests-)
-- [Component and Unit Tests](#component-and-unit-tests-)
+## Contents
-
+- [End to End Tests](#end-to-end-tests)
+ - [What to Test](#what-to-test)
+ - [Where to Write Tests](#where-to-write-tests)
+ - [Best Practices](#best-practices)
+ - [Checking E2E coverage](#checking-e2e-coverage)
+- [Component and Unit Tests](#component-and-unit-tests)
-## End to End Tests [`⇧`](#contents)
+## End to End Tests
End to End Tests (E2E) are used to ensure that the whole application (frontend, backend, database, etc.) functions together correctly. E2E tests are very useful, but they have some important drawbacks:
@@ -29,6 +32,8 @@ Not every test belongs in the E2E test suite. Tests that should go in the E2E te
- Putting a url in the user's clipboard
4. Browser-specific bugs
+Back to top.
+
### Where to write tests
Write your tests under `frontend/test-e2e/specs`. Inside this folder are more folders based on the environment the tests are meant to run in:
@@ -51,11 +56,13 @@ test.describe("Home Page", { tag: ["@desktop"] }, () => {
});
```
-### Best practices
+Back to top.
+
+### Best Practices
We recommend following [playwright's best practices](https://playwright.dev/docs/best-practices) and locating UI elements by their accessible names when possible.
-### Avoid complicated design patterns
+#### Avoid complicated design patterns
We want the E2E test suite to be as easy to read as possible. That means most of the logic of a test should be in the test itself, and not hidden in classes or methods.
@@ -80,9 +87,35 @@ The steps to do this are:
2. Move that function into a file in `frontend/test-e2e/actions` and name it based on the action being performed
3. Import the function into the test files where you use it
-
+Back to top.
+
+### Checking E2E coverage
+
+To see which application routes are covered by the E2E test suite, run the coverage script from the `frontend/` directory:
+
+```bash
+# Terminal output (colored, with coverage summary):
+node test-e2e/scripts/e2e-coverage.mjs
+
+# GitHub-flavored markdown (for pasting into issues or PRs):
+node test-e2e/scripts/e2e-coverage.mjs --markdown
+
+# Only show uncovered testable routes:
+node test-e2e/scripts/e2e-coverage.mjs --uncovered
-## Component and Unit Tests [`⇧`](#contents)
+# Machine-readable JSON output:
+node test-e2e/scripts/e2e-coverage.mjs --json
+```
+
+The script distinguishes between:
+
+- **Covered routes** — routes with at least one `goto`, `waitForURL`, or `toHaveURL` assertion in specs, actions, or page objects
+- **Stub routes** — pages marked `:underDevelopment="true"` with no implemented UI (excluded from the testable coverage calculation)
+- **Uncovered testable routes** — implemented routes that have no E2E coverage yet
+
+Back to top.
+
+## Component and Unit Tests
For component and unit tests we are using Vitest and Vue Testing Library. For a general overview on how to write these tests, see the documentation for the [Testing Library Frameworks](https://testing-library.com/docs/).
@@ -109,3 +142,190 @@ We recommend using mocking for dependencies that are unreliable and/or slow, lik
* We provide a global mock for `useColorMode`. This is necessary because `useColorMode` currently does not work in Vitest. See example use in [useColor.spec.ts](frontend/test/composables/useColor.spec.ts).
* Nuxt provides a `registerEndpoint` function to mock network requests. See example use in [sign-in.spec.ts](frontend/test/pages/auth/sign-in.spec.ts).
+
+### 4. Mocking Composables
+
+When testing components or composables that use Nuxt composables (like `useRoute`, `useRouter`, `useLocalePath`, `useAuth`, etc.), we use a factory-based mocking approach to make test dependencies explicit and maintainable.
+
+#### Factory Functions
+
+All composable mock factories are located in [`frontend/test/mocks/composableMocks.ts`](frontend/test/mocks/composableMocks.ts). These factories allow tests to explicitly define their mock needs using reusable functions.
+
+**Available factories:**
+- `createUseRouteMock()` - For mocking `useRoute()`
+- `createUseRouterMock()` - For mocking `useRouter()`
+- `createUseLocalePathMock()` - For mocking `useLocalePath()`
+- `createUseAuthMock()` - For mocking `useAuth()`
+- `createUseUserMock()` - For mocking `useUser()`
+- `createUseDeviceMock()` - For mocking `useDevice()`
+- `createUseColorModeSpy()` - For mocking `useColorMode()` (returns a spy function)
+- `createUseSidebarSpy()` - For mocking `useSidebar()` (returns a spy function)
+- And more...
+
+#### Mocking Patterns
+
+We use five main patterns for mocking composables:
+
+##### Pattern 1: Use Auto-Mock (Default Behavior)
+
+When a composable doesn't affect your test behavior, you can rely on the automatic `{}` mock provided by `setupAutoImportMocks()`. This is the simplest approach and requires no explicit setup.
+
+**When to use:** The composable is used by the component but doesn't affect test assertions.
+
+**Example:**
+```typescript
+// No explicit mock needed - auto-mock {} is sufficient.
+describe("MyComponent", () => {
+ it("renders correctly", async () => {
+ await render(MyComponent);
+ // Component uses useRoute() internally, but test doesn't check route behavior.
+ });
+});
+```
+
+##### Pattern 2: Import Factory and Use It
+
+When you need specific return values but don't need to track calls, use the factory functions directly.
+
+**When to use:** You need specific mock data (e.g., route params, user data) but don't need to verify calls.
+
+**Example:**
+```typescript
+import { createUseRouteMock } from "../../mocks/composableMocks";
+
+// Set up useRoute with specific params.
+globalThis.useRoute = createUseRouteMock(
+ { id: "123" }, // params
+ { filter: "active" }, // query
+ "/events/123", // path
+ "events-id" // name (optional)
+);
+
+describe("MyComponent", () => {
+ it("displays event ID from route", async () => {
+ await render(MyComponent);
+ expect(screen.getByText("123")).toBeTruthy();
+ });
+});
+```
+
+**Real example:** See [ModalBase.spec.ts](frontend/test/components/modal/ModalBase.spec.ts)
+
+##### Pattern 3: Override with Spy for Call Tracking
+
+When you need to verify that a composable was called with specific arguments, use `vi.stubGlobal()` with a spy function.
+
+**When to use:** You need to assert that a composable was called with specific parameters.
+
+**Example:**
+```typescript
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+describe("BtnRouteInternal", () => {
+ const mockLocalePath = vi.fn((path: string) => `/en${path}`);
+
+ beforeEach(() => {
+ vi.stubGlobal("useLocalePath", () => mockLocalePath);
+ mockLocalePath.mockClear();
+ });
+
+ it("calls useLocalePath with correct path", async () => {
+ await render(BtnRouteInternal, { props: { linkTo: "/test" } });
+ expect(mockLocalePath).toHaveBeenCalledWith("/test");
+ });
+});
+```
+
+**Real example:** See [BtnRouteInternal.spec.ts](frontend/test/components/btn/route/BtnRouteInternal.spec.ts)
+
+##### Pattern 4: Use mockImplementation() on Spy Functions
+
+When a composable is set up as a spy function in `setup.ts` (like `useColorMode`), you can use `mockImplementation()` to change return values per test.
+
+**When to use:** You need different return values for different test cases, and the composable is already set up as a spy.
+
+**Example:**
+```typescript
+describe("useColor", () => {
+ it("handles light mode", () => {
+ globalThis.useColorModeMock.mockImplementation(() => ({
+ preference: "light",
+ value: "light",
+ }));
+
+ const { getColorModeImages } = useColor();
+ expect(getColorModeImages("/path/to/image")).toEqual("/path/to/image_light.png");
+ });
+
+ it("handles dark mode", () => {
+ globalThis.useColorModeMock.mockImplementation(() => ({
+ preference: "dark",
+ value: "dark",
+ }));
+
+ const { getColorModeImages } = useColor();
+ expect(getColorModeImages("/path/to/image")).toEqual("/path/to/image_dark.png");
+ });
+});
+```
+
+**Real example:** See [useColor.spec.ts](frontend/test/composables/useColor.spec.ts)
+
+##### Pattern 5: Set Defaults in beforeEach, Override Per-Test
+
+Combine factory functions in `beforeEach` with per-test overrides when needed.
+
+**When to use:** Most tests need the same mock, but some tests need different values.
+
+**Example:**
+```typescript
+import { createUseRouteMock } from "../../mocks/composableMocks";
+
+describe("MyComponent", () => {
+ beforeEach(() => {
+ // Default setup for most tests.
+ globalThis.useRoute = createUseRouteMock({}, {}, "/default");
+ });
+
+ it("handles default route", async () => {
+ await render(MyComponent);
+ // Uses default mock.
+ });
+
+ it("handles specific route params", async () => {
+ // Override for this specific test.
+ globalThis.useRoute = createUseRouteMock({ id: "456" }, {}, "/specific");
+ await render(MyComponent);
+ // Uses specific mock.
+ });
+});
+```
+
+#### Decision Guide
+
+**Which pattern should I use?**
+
+1. **Pattern 1 (Auto-mock)**: Composable doesn't affect test behavior
+2. **Pattern 2 (Factory)**: Need specific mock data, no call tracking needed
+3. **Pattern 3 (Spy)**: Need to verify composable was called with specific args
+4. **Pattern 4 (mockImplementation)**: Composable is already a spy, need different values per test
+5. **Pattern 5 (beforeEach + override)**: Most tests share defaults, some need overrides
+
+#### Best Practices
+
+- **Make dependencies explicit**: If a composable affects your test, explicitly mock it using a factory
+- **Use factories for reusability**: Import from `composableMocks.ts` rather than creating inline mocks
+- **Keep it simple**: Use Pattern 1 when defaults are sufficient
+- **Document your choice**: Add a comment explaining why you chose a specific pattern if it's not obvious
+
+#### Infrastructure-Dependent Mocks
+
+Some composables are set up globally in `setup.ts` because they require infrastructure setup:
+- `useI18n` - Requires i18n instance
+- `useColorMode` - Set up as spy for per-test overrides
+- `useSidebar` - Set up as spy for per-test overrides
+- `useAuthState` - Requires global data reference
+
+These don't need explicit setup in individual tests unless you need to override their behavior.
+
+Back to top.
diff --git a/README.md b/README.md
index a384b3eea..62d247443 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+
+
@@ -16,47 +18,58 @@
[](https://matrix.to/#/#activist_community:matrix.org)
[](https://github.com/activist-org/activist/actions)
-[](https://github.com/activist-org/activist/actions/workflows/pr_ci_backend.yaml)
-[](https://github.com/activist-org/activist/actions/workflows/pr_ci_frontend.yaml)
-[](https://github.com/activist-org/activist/actions/workflows/pr_ci_i18n.yaml)
-
-
-
-### An open-source activism platform
+[](https://github.com/activist-org/activist/actions/workflows/ci_e2e_playwright_desktop.yaml)
+[](https://github.com/activist-org/activist/actions/workflows/ci_e2e_playwright_mobile.yaml)
+[](https://github.com/activist-org/activist/actions/workflows/ci_backend_static_analysis.yaml)
+[](https://github.com/activist-org/activist/actions/workflows/ci_backend_pytest.yaml)
+[](https://github.com/activist-org/activist/actions/workflows/ci_frontend_static_analysis.yaml)
+[](https://github.com/activist-org/activist/actions/workflows/ci_frontend_vitest.yaml)
+[](https://github.com/activist-org/activist/actions/workflows/ci_i18n_check.yaml)
+
+# Contents
+
+- [About activist](#about-activist)
+- [Our Mission](#our-mission)
+- [Topics](#topics)
+- [Features](#features)
+- [Preview Video](#preview-video)
+- [Design and Accessibility](#design-and-accessibility)
+- [Securely Hosted](#securely-hosted)
+- [Community Governance](#community-governance)
+- [Localization](#localization)
+- [Contributing](#contributing)
+- [Supporters and Partners](#supporters-and-partners)
+- [Disclosure](#disclosure)
-[**activist.org**](https://activist.org) is a platform that enables more people to safely engage in activism by making it easy to discover organizations and events, as well as coordinate and collaborate on political action. We want to enable activists to learn proven and novel strategies from each other for social and ecological change. Free, open-source, privacy-focused and governed by our community.
+# About activist
-
+> [!IMPORTANT]
+> Before you contribute, read the [contributing guide](CONTRIBUTING.md).
-> [!NOTE]
-> The [contributing](#contributing) section has information for those interested.
+[activist.org](https://activist.org) is a platform that makes it easy and safe to:
-
+- Engage in activism.
+- Discover organizations and events.
+- Coordinate and collaborate on political action.
-# **Contents**
+Our mission is to help activists connect and share strategies for social and ecological change.
-- [Our goals](#our-goals)
-- [Preview video](#preview-video)
-- [Contributing](#contributing)
-- [Environment setup](#environment-setup)
-- [Design and accessibility](#design-a11y)
-- [Platform features](#platform-features)
-- [Securely hosted](#securely-hosted)
-- [Community governance](#community-governance)
-- [Localization](#localization)
-- [Supporters and partners](#supporters-partners)
+activist is:
-
+- Free.
+- Open-source.
+- Privacy-focused.
+- Governed by our community.
-# Our goals [`⇧`](#contents)
+# Our Mission
-The activist community is creating a global platform where movements grow and people are inspired to join in political actions. We want to update how power is distributed in our society by removing barriers and enabling more people to safely engage in activism.
+We're creating a global platform where movements grow and people are inspired to join in political action.
-
+We want to change how power is distributed in society by removing barriers and enabling more people to safely engage in activism.
-## Topics [`⇧`](#contents)
+# Topics
-The following are the working topics that activist could include:
+These are some of the topics that activist includes:
| | | |
| :-------------------------- | :--------------------- | :----------------------- |
@@ -66,341 +79,221 @@ The following are the working topics that activist could include:
| LGBTQIA+ | Peace and Resolution | Racial Justice |
| Refugees and Migration | Technology and Privacy | Women's Rights |
-
+## Events
-activist uses [Matrix](https://matrix.org/) for internal communication. You're more than welcome to [join us in our public chat rooms](https://matrix.to/#/#activist_community:matrix.org) to share ideas, ask questions or just say hi to the team :) We'd suggest that you use the [Element](https://element.io/) client and [Element X](https://element.io/app) for a mobile app.
+_Collaborative event pages made for activists and their needs._
-Please see the [contribution guidelines](CONTRIBUTING.md) and [style guide](STYLEGUIDE.md) if you are interested in contributing. Work that is in progress or could be implemented is tracked in the [issues](https://github.com/activist-org/activist/issues) and [projects](https://github.com/activist-org/activist/projects).
+Create flexible event pages for two event types:
-> [!NOTE]
-> Just because an issue is assigned on GitHub doesn't mean the team isn't open to your contribution! Feel free to write [in the issues](https://github.com/activist-org/activist/issues) and we can potentially reassign it to you.
+**Learn**
-Also check the [`-next release-`](https://github.com/activist-org/activist/labels/-next%20release-) and [`-priority-`](https://github.com/activist-org/activist/labels/-priority-) labels in the [issues](https://github.com/activist-org/activist/issues) for those that are most important, as well as those marked [`good first issue`](https://github.com/activist-org/activist/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) that are tailored for first-time contributors. For those new to coding or our tech stack, we've collected [links to helpful documentation pages](CONTRIBUTING.md#learning-the-tech-stack-) in the [contribution guidelines](CONTRIBUTING.md).
+- Seminars
+- Meetings
+- Panel discussions
-We would be happy to discuss granting you further rights as a contributor after your first pull requests, with a maintainer role then being possible after continued interest in the project. activist seeks to be an inclusive, diverse and supportive organization. We'd love to have you on the team!
+**Action**
-
+- Protests
+- Volunteering
+- Canvassing
-## How you can help [`⇧`](#contents)
+Also:
-- [Reporting bugs](https://github.com/activist-org/activist/issues/new?assignees=&labels=bug&template=bug_report.yml) as they're found 🐞
-- Working with us on [new features](https://github.com/activist-org/activist/issues?q=is%3Aissue+is%3Aopen+label%3Afeature) ✨
-- [Localizing](https://github.com/activist-org/activist/issues?q=is%3Aissue+is%3Aopen+label%3Alocalization) content for the platform 🌐
- - Please join our [public localization project on Weblate](https://hosted.weblate.org/projects/activist/activist)!
-- [Documentation](https://github.com/activist-org/activist/issues?q=is%3Aissue+is%3Aopen+label%3Adocumentation) for onboarding and project cohesion 📝
-- [Sharing activist.org](https://github.com/activist-org/activist/issues/23) with others! 🚀
+- A feed for organizers to share real-time information with participants.
+- Event templates that organizations can create and share them with allies.
+- Transform event pages into flyers or posters and link them via QR codes.
+- Add legal notes to warn participants of the risks involved.
-
+## Resources
-# Environment setup [`⇧`](#contents)
+_A simple link hub for organizations._
-1. First and foremost, please see the suggested IDE setup in the dropdown below to make sure that your editor is ready for development.
+- Saved under organizations, their working groups and events.
+- Keep important links in one place.
+- Private by default.
+- Make public to share information and best practices.
-> [!IMPORTANT]
->
-> -> -> VS Code -> -> Install the following extensions: -> -> - [batisteo.vscode-django](https://marketplace.visualstudio.com/items?itemName=batisteo.vscode-django) -> - [bradlc.vscode-tailwindcss](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) -> - [charliermarsh.ruff](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff) -> - [esbenp.prettier-vscode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) -> - [ms-playwright.playwright](https://marketplace.visualstudio.com/items?itemName=ms-playwright.playwright) -> - [streetsidesoftware.code-spell-checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) -> - [Vue.volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) -> -> WebStorm -> -> - Check out the [Vue.js development docs](https://www.jetbrains.com/help/webstorm/vue-js.html) -> - Make sure a [local Node.js interpreter](https://www.jetbrains.com/help/webstorm/developing-node-js-applications.html#ws_node_configure_local_node_interpreter) is configured in your project -> - Make sure the [Vue.js plugin](https://github.com/JetBrains/intellij-plugins/tree/master/vuejs) and [JavaScript Debugger](https://www.jetbrains.com/help/webstorm/configuring-javascript-debugger.html) are enabled in the plugins page of the settings -> ->
->
->
-> Alternatively to using HTTPS as in the instructions below, consider SSH to interact with GitHub from the terminal. SSH allows you to connect without a user-pass authentication flow.
->
-> To run git commands with SSH, remember then to substitute the HTTPS URL, `https://github.com/...`, with the SSH one, `git@github.com:...`.
->
-> - e.g. Cloning now becomes `git clone git@github.com:
-The [designs for activist](https://www.figma.com/file/I9McFfaLu1RiiWp5IP3YjE/activist_designs?node-id=805%3A231) are made using [Figma](https://www.figma.com). You can use the [issues](https://github.com/activist-org/activist/issues) to make suggestions for improvements. Design related issues are marked with the [`design`](https://github.com/activist-org/activist/issues?q=is%3Aopen+is%3Aissue+label%3Adesign) label.
-
-We want our tools to look great, feel easy to use and function flawlessly on any device while at the same time including good security practices wherever possible. We also consistently make decisions that put a11y at the center of what we’re building.
-
-> [!NOTE]
-> Please contact the team on GitHub or via the email on the [designs welcome page](https://www.figma.com/file/I9McFfaLu1RiiWp5IP3YjE/activist_designs?node-id=805%3A231) if you're interested in contributing. We'd love to see a sample of your work and if everything looks good we'll schedule a time to get connected!
-
-
-
-# Platform features [`⇧`](#contents)
-
-The [project board](https://github.com/orgs/activist-org/projects/1) is where we organize our work and plan out what's next. The following sections give a general overview of the various planned features of [activist.org](https://activist.org).
-
-### Organizations profiles [`⇧`](#contents)
-
-> Easy-to-use microsites for organizations of all sizes with multiple subpages.
-
-Describe your organization’s aims and structure as well as answer frequently asked questions. Explain how your groups collaborate and safely onboard new people to the team.
-
-### Events [`⇧`](#contents)
-
-> Collaborative event pages made for activists and their needs.
-
-Organizations can create flexible event pages for different formats of events. There are two types of events:
-
-- **Learn**: seminars, meetings, panel discussions
-- **Action**: protests, volunteering, canvassing
-
-Other event features include:
-
-- A feed will allow organizers to share information in real time with participants
-- Organizations can create event templates and share them with allies
-- Event pages can be transformed into flyers or posters and linked to via QR codes
-- Legal notes can be added to warn participants of the risks involved
-
-### Resources [`⇧`](#contents)
-
-> A simple link hub for organizations.
-
-Organizations can keep important links (chats, articles, pads, etc.) in one place and are split into working groups to present structure. Private by default, resources can also be made public to share information and best practices.
-
-### Onboarding [`⇧`](#contents)
-
-> Safe methods to onboard new members.
-
-We are working on a conversational onboarding interface based on the [Matrix protocol](https://matrix.org/) that operates across messengers without compromising data sovereignty for organizations or individuals. Organizations will also have the option to include their existing processes if preferred.
-
-### Search [`⇧`](#contents)
-
-> Easily find, filter and share.
-
-Display search results in list, map and calendar views. Users can also save searches for later or set up notifications for newly published events, resources, and discussions.
+We want our tools to look great, be easy to use, and function on any device, while including good security practices. We also consistently put accessibility at the center of what we build.
-### Discussions [`⇧`](#contents)
+We make the [designs for activist](https://www.figma.com/file/I9McFfaLu1RiiWp5IP3YjE/activist_designs?node-id=805%3A231) using [Figma](https://www.figma.com).
-> Dedicated forums for organizations and their events.
+You can use the [issues](https://github.com/activist-org/activist/issues) to suggest improvements. We mark design-related issues with the [`design`](https://github.com/activist-org/activist/issues?q=is%3Aopen+is%3Aissue+label%3Adesign) label.
-Discussions will also allow organizations, groups and events to send notifications to supporters. Included features for democratic decision making will further enable asynchronous planning.
+Back to top.
-### Tasks [`⇧`](#contents)
+# Securely Hosted
-> Kanban boards for organizing the work to be done.
+We host our data in Iceland with [FlokiNET](https://flokinet.is/), a reputable hosting provider trusted by whistleblowers, activists, and investigative journalists.
-Users will be able to attach kanban boards to every organization, group and event. This will allow those involved to easily plan and keep an overview of progress while templates guide organizers with best practices from our community.
+Iceland is a strong supporter for net neutrality with strict privacy protection laws and freedom of the press. These factors have contributed to making Iceland a preferred destination for data centers.
-### Affiliates [`⇧`](#contents)
+You can learn more about FlokiNET on [their blog](https://blog.flokinet.is).
-> Relationships between organizations, people and events.
+Back to top.
-Organizations and users can give support to each other as well as events:
+# Community Governance
-- **Supporter**: a one-way relationship of support
-- **Ally**: a relationship of mutual support
+We not only value, but _need_ open discourse. Our initial feature set was developed together with our growing community of activists.
-Relationships between organizations will help users find similar organizations or easily connect with actions when they’re in a new place. Affiliations will also determine notifications and access to restricted content.
+Our aim is to secure a progressive community by design, while putting platform health before platform growth.
-### Votes [`⇧`](#contents)
+Only organizations that are already on activist will be able to vouch for new organizations that apply to join. Together with experienced activists, we're selecting an initial group of organizations that have a proven track record of inclusivity and elevating underrepresented groups.
-> Linking events and organizations to decision making.
+We are still developing our operating principles and will always update them based on community decisions. Processes for flagging, banning, guidelines, and rules will always be determined collectively.
-Users will be able to subscribe for updates on events and organizations that work in relation to legislation and elections. This feature will be based on data from [Wikidata](https://www.wikidata.org), with open data generating the vote pages that our community then maintains.
+Back to top.
-
+# Localization
-# Securely hosted [`⇧`](#contents)
+
+
+
-We are hosting our data in Iceland with a reputable hosting provider that is trusted by whistleblowers, activists and investigative journalists: [FlokiNET](https://flokinet.is/).
+> [!IMPORTANT]
+> Want to join our translators working group? Join us in the [localization project on Weblate](https://hosted.weblate.org/projects/activist/activist) and the [Localization channel on Matrix](https://matrix.to/#/!DzbdYyfhjinQBWXgQe:matrix.org?via=matrix.org) to get involved!
+>
+> See the [localization guide](LOCALIZATION.md) for information on how to get started.
-Iceland is a strong supporter for net neutrality with strict privacy protection laws and freedom of the press. All these factors have contributed to making Iceland a preferred destination for data centers.
+In order to mobilize larger and more diverse coalitions, we need to break down language barriers.
-> You can learn more about FlokiNET on [their blog](https://blog.flokinet.is).
+We're growing our network of volunteer contributors to facilitate translation requests for these parts of the platform:
-
+- Organization profiles
+- Events
+- Resources
-# Community governance [`⇧`](#contents)
+We use [Weblate](https://weblate.org) for localization.
-We not only value, but need open discourse. Our initial feature set for the MVP and future releases was developed together with our growing community of activists.
+## Localization Coverage
-Our aim is to secure a progressive community by design while putting platform health before platform growth. Only organizations that are already on activist will be able to vouch for new organizations that apply to join. Together with experienced activists we are selecting an initial group of organizations that have a proven track record of inclusivity and elevating underrepresented groups.
+
+
-
-
-
+activist uses [Matrix](https://matrix.org/) for internal communication. You're more than welcome to [join us in our public chat rooms](https://matrix.to/#/#activist_community:matrix.org) to share ideas, ask questions or just say hi to the team :) We'd suggest that you use the [Element](https://element.io/) client and [Element X](https://element.io/app) for a mobile app.
-We need to break down language barriers in order to mobilize larger and more diverse coalitions. Translation requests will be available for several assets on the platform - organization profiles, events and resources - and we are growing our network of volunteer contributors to facilitate this.
+Please see the [contribution guide](CONTRIBUTING.md) and [style guide](STYLEGUIDE.md) if you are interested in contributing. Work that is in progress or could be implemented is tracked in the [issues](https://github.com/activist-org/activist/issues) and [projects](https://github.com/activist-org/activist/projects).
> [!NOTE]
-> Want to join our translators working group? Please join us in the [localization project on Weblate](https://hosted.weblate.org/projects/activist/activist) and the [Localization channel on Matrix](https://matrix.to/#/!DzbdYyfhjinQBWXgQe:matrix.org?via=matrix.org) to get involved!
+> Just because an issue is assigned on GitHub doesn't mean the team isn't open to your contribution! Feel free to write [in the issues](https://github.com/activist-org/activist/issues) and we can potentially reassign it to you.
-Localization of activist is done via [Weblate](https://weblate.org). Please see the [localization guide](LOCALIZATION.md) for information on how to get started!
+Also check the [`-next release-`](https://github.com/activist-org/activist/labels/-next%20release-) and [`-priority-`](https://github.com/activist-org/activist/labels/-priority-) labels in the [issues](https://github.com/activist-org/activist/issues) for those that are most important, as well as those marked [`good first issue`](https://github.com/activist-org/activist/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) that are tailored for first-time contributors. For those new to coding or our tech stack, we've collected [links to helpful documentation pages](CONTRIBUTING.md#learning-the-tech-stack-) in the [contribution guide](CONTRIBUTING.md).
-### Localization coverage [`⇧`](#contents)
+We would be happy to discuss granting you further rights as a contributor after your first pull requests, with a maintainer role then being possible after continued interest in the project. activist seeks to be an inclusive, diverse and supportive organization. We'd love to have you on the team! Please see the [mentorship and growth section of the contribution guide](CONTRIBUTING.md#mentorship-and-growth-) for further information.
-
-
{{ donationPrompt }}
diff --git a/frontend/app/components/card/CardFAQEntry.vue b/frontend/app/components/card/CardFAQEntry.vue
index dea0554b9..82a5e6451 100644
--- a/frontend/app/components/card/CardFAQEntry.vue
+++ b/frontend/app/components/card/CardFAQEntry.vue
@@ -1,7 +1,7 @@
-
- {{ $t("i18n.components.footer.flex._global.activist_tagline") }}
-
- {{ $t("i18n.components._global.connect") }}
-
- {{ $t("i18n._global.resources") }}
-
-
- {{ $t("i18n._global.organization") }}
-
-
- {{
- $t("i18n.components.footer.flex._global.copyright", {
- year: new Date().getFullYear(),
- })
- }}
-
{{ props.message }}
-