Skip to content

Commit ff0dc8a

Browse files
Merge branch 'main' into feat/redis-task-store
2 parents 16f285b + 66d2a28 commit ff0dc8a

132 files changed

Lines changed: 12559 additions & 826 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/dependabot.yml

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,65 @@
1-
# Dependabot version updates are intentionally disabled on this repository.
2-
#
3-
# The Dependabot configuration schema requires at least one entry under
4-
# `updates`. The minimum-viable disable below uses the GitHub Actions
5-
# ecosystem with `open-pull-requests-limit: 0` so that Dependabot cannot
6-
# open any pull request, and by listing only one ecosystem here we ensure
7-
# that no other ecosystem (npm, pip, cargo, etc.) will be scanned at all.
8-
#
9-
# To re-enable Dependabot in the future, replace this file with a full
10-
# configuration generated from the official options reference:
11-
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
12-
#
13-
# Note: this file only governs Dependabot *version* updates. To also
14-
# disable Dependabot *security* updates, toggle the repo setting
15-
# "Dependabot security updates" off under
16-
# Settings -> Code security and analysis on GitHub.
171
version: 2
182
updates:
3+
- package-ecosystem: "npm"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
open-pull-requests-limit: 10
8+
labels:
9+
- "dependencies"
10+
- "npm"
11+
commit-message:
12+
prefix: "chore(npm)"
13+
include: "scope"
14+
groups:
15+
npm-dependencies:
16+
patterns:
17+
- "*"
18+
19+
- package-ecosystem: "cargo"
20+
directory: "/app/onchain"
21+
schedule:
22+
interval: "weekly"
23+
open-pull-requests-limit: 10
24+
labels:
25+
- "dependencies"
26+
- "cargo"
27+
commit-message:
28+
prefix: "chore(cargo)"
29+
include: "scope"
30+
groups:
31+
cargo-dependencies:
32+
patterns:
33+
- "*"
34+
35+
- package-ecosystem: "pip"
36+
directory: "/"
37+
schedule:
38+
interval: "weekly"
39+
open-pull-requests-limit: 10
40+
labels:
41+
- "dependencies"
42+
- "pip"
43+
commit-message:
44+
prefix: "chore(pip)"
45+
include: "scope"
46+
groups:
47+
pip-dependencies:
48+
patterns:
49+
- "*"
50+
1951
- package-ecosystem: "github-actions"
2052
directory: "/"
2153
schedule:
2254
interval: "weekly"
23-
open-pull-requests-limit: 0
55+
open-pull-requests-limit: 10
56+
labels:
57+
- "dependencies"
58+
- "github-actions"
59+
commit-message:
60+
prefix: "chore(actions)"
61+
include: "scope"
62+
groups:
63+
github-actions-dependencies:
64+
patterns:
65+
- "*"

.github/renovate.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
3+
"extends": [
4+
"config:recommended",
5+
"docker:pinDigests",
6+
"helpers:pinGitHubActionDigests"
7+
],
8+
"packageRules": [
9+
{
10+
"matchManagers": ["npm"],
11+
"groupName": "npm dependencies",
12+
"commitMessagePrefix": "chore(npm):",
13+
"schedule": ["before 5am on monday"]
14+
},
15+
{
16+
"matchManagers": ["cargo"],
17+
"groupName": "cargo dependencies",
18+
"commitMessagePrefix": "chore(cargo):",
19+
"schedule": ["before 5am on monday"]
20+
},
21+
{
22+
"matchManagers": ["pip_requirements"],
23+
"groupName": "pip dependencies",
24+
"commitMessagePrefix": "chore(pip):",
25+
"schedule": ["before 5am on monday"]
26+
},
27+
{
28+
"matchManagers": ["github-actions"],
29+
"groupName": "github-actions dependencies",
30+
"commitMessagePrefix": "chore(actions):",
31+
"schedule": ["before 5am on monday"]
32+
}
33+
],
34+
"prHourlyLimit": 0,
35+
"prConcurrentLimit": 5,
36+
"labels": ["dependencies"],
37+
"commitMessagePrefix": "chore(deps):"
38+
}

.github/workflows/backend-ci.yml

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,37 @@ on:
1313
jobs:
1414
build-and-test:
1515
runs-on: ubuntu-latest
16+
services:
17+
postgres:
18+
image: postgres:16-alpine
19+
env:
20+
POSTGRES_DB: chainforge_test
21+
POSTGRES_PASSWORD: postgres
22+
POSTGRES_USER: postgres
23+
ports:
24+
- 5432:5432
25+
options: >-
26+
--health-cmd "pg_isready -U postgres -d chainforge_test"
27+
--health-interval 10s
28+
--health-timeout 5s
29+
--health-retries 5
30+
redis:
31+
image: redis:7-alpine
32+
ports:
33+
- 6379:6379
34+
options: >-
35+
--health-cmd "redis-cli ping"
36+
--health-interval 10s
37+
--health-timeout 5s
38+
--health-retries 5
1639
1740
steps:
1841
- uses: actions/checkout@v4
1942

43+
- name: Validate package.json files
44+
run: |
45+
node -e "const fs=require('fs'); require('child_process').execSync('git ls-files \"*package.json\"',{encoding:'utf8'}).trim().split('\\n').filter(Boolean).forEach(p=>{JSON.parse(fs.readFileSync(p,'utf8')); console.log('OK',p)})"
46+
2047
- name: Install pnpm
2148
uses: pnpm/action-setup@v2
2249
with:
@@ -34,19 +61,34 @@ jobs:
3461
- name: Lint
3562
run: pnpm --filter backend run lint
3663

37-
- name: Test
38-
run: pnpm --filter backend run test
64+
- name: Prepare coverage database
65+
working-directory: app/backend
66+
env:
67+
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/chainforge_test?schema=public
68+
run: pnpm exec prisma db push --skip-generate
69+
70+
- name: Test with coverage
71+
env:
72+
API_KEY: test-api-key-123
73+
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/chainforge_test?schema=public
74+
NODE_ENV: test
75+
REDIS_HOST: 127.0.0.1
76+
REDIS_PORT: '6379'
77+
run: pnpm --filter backend run test:cov
3978

4079
- name: Build
4180
run: pnpm --filter backend run build
4281

4382
- name: Export OpenAPI spec
4483
working-directory: app/backend
4584
env:
46-
DATABASE_URL: file:./prisma/dev.db
85+
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/chainforge_test?schema=public
4786
NODE_ENV: development
4887
run: npm run spec:export
4988

89+
- name: Check for Prisma schema without migration
90+
run: chmod +x app/backend/scripts/check-prisma-migration.sh && app/backend/scripts/check-prisma-migration.sh
91+
5092
- name: Check for OpenAPI spec drift
5193
run: |
5294
git diff --exit-code app/frontend/openapi.json || \

.github/workflows/codeql.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: "CodeQL"
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
pull_request:
7+
branches: [ "main" ]
8+
9+
jobs:
10+
analyze:
11+
name: Analyze
12+
runs-on: ubuntu-latest
13+
permissions:
14+
actions: read
15+
contents: read
16+
security-events: write
17+
18+
strategy:
19+
fail-fast: false
20+
matrix:
21+
language: [ 'javascript-typescript', 'rust', 'python' ]
22+
23+
steps:
24+
- name: Checkout repository
25+
uses: actions/checkout@v4
26+
27+
- name: Initialize CodeQL
28+
uses: github/codeql-action/init@v3
29+
with:
30+
languages: ${{ matrix.language }}
31+
32+
- name: Autobuild
33+
uses: github/codeql-action/autobuild@v3
34+
35+
- name: Perform CodeQL Analysis
36+
uses: github/codeql-action/analyze@v3
37+
with:
38+
category: "/language:${{matrix.language}}"

.github/workflows/contract-ci.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,19 @@ jobs:
3333
with:
3434
workspaces: "app/onchain"
3535

36+
- name: Enforce locked dependencies
37+
run: cargo check --locked
38+
39+
- name: Ensure Cargo.lock is updated when Cargo.toml changes
40+
if: github.event_name == 'pull_request'
41+
run: |
42+
git fetch origin "${{ github.base_ref }}" --depth=1
43+
changed_files="$(git diff --name-only "origin/${{ github.base_ref }}...HEAD" -- app/onchain/Cargo.toml app/onchain/Cargo.lock)"
44+
if echo "$changed_files" | grep -q '^app/onchain/Cargo.toml$' && ! echo "$changed_files" | grep -q '^app/onchain/Cargo.lock$'; then
45+
echo "Cargo.toml changed without updating Cargo.lock."
46+
exit 1
47+
fi
48+
3649
- name: Check formatting
3750
run: cargo fmt --all -- --check
3851

.github/workflows/frontend-ci.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Frontend CI
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
paths:
7+
- 'app/frontend/**'
8+
- '.github/workflows/frontend-ci.yml'
9+
pull_request:
10+
branches: [ "main" ]
11+
paths:
12+
- 'app/frontend/**'
13+
- '.github/workflows/frontend-ci.yml'
14+
15+
jobs:
16+
lint-and-test:
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- name: Install pnpm
23+
uses: pnpm/action-setup@v2
24+
with:
25+
version: 9
26+
27+
- name: Use Node.js
28+
uses: actions/setup-node@v4
29+
with:
30+
node-version: '20'
31+
cache: 'pnpm'
32+
33+
- name: Install dependencies
34+
run: pnpm install --no-frozen-lockfile --engine-strict=false
35+
36+
# Non-blocking until the pre-existing lint errors on main are fixed
37+
# (tracked in docs/accessibility/audit-2026.md ticket backlog).
38+
- name: Lint
39+
continue-on-error: true
40+
run: pnpm --filter chainforge-frontend run lint
41+
42+
- name: Type check
43+
run: pnpm --filter chainforge-frontend run type-check
44+
45+
- name: Test (includes axe accessibility suite)
46+
run: pnpm --filter chainforge-frontend run test

.github/workflows/testnet-smoke.yml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,29 @@ on:
1313
- 'release/**'
1414

1515
jobs:
16+
check-configuration:
17+
runs-on: ubuntu-latest
18+
outputs:
19+
configured: ${{ steps.check.outputs.configured }}
20+
steps:
21+
- name: Check testnet configuration
22+
id: check
23+
env:
24+
SOROBAN_CONTRACT_ID: ${{ secrets.SOROBAN_CONTRACT_ID }}
25+
SOROBAN_RPC_URL: ${{ secrets.SOROBAN_RPC_URL }}
26+
run: |
27+
if [[ -n "$SOROBAN_CONTRACT_ID" && -n "$SOROBAN_RPC_URL" ]]; then
28+
echo "configured=true" >> "$GITHUB_OUTPUT"
29+
else
30+
echo "configured=false" >> "$GITHUB_OUTPUT"
31+
fi
32+
1633
integration-harness:
1734
name: Testnet Integration Harness
1835
runs-on: ubuntu-latest
36+
needs: check-configuration
1937
if: >
20-
github.event_name == 'workflow_dispatch' || (secrets.SOROBAN_CONTRACT_ID != '' && secrets.SOROBAN_RPC_URL != '')
38+
github.event_name == 'workflow_dispatch' || needs.check-configuration.outputs.configured == 'true'
2139
steps:
2240
- name: Checkout
2341
uses: actions/checkout@v4

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,5 +154,6 @@ GEMINI.md
154154
# Local planning/spec docs (not committed)
155155
docs/superpowers/
156156
plan.md
157+
tasks/
157158
.playwright-mcp/
158159
dump.rdb

PR_DESCRIPTION.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## Problem
2+
Resolves #295
3+
4+
Field operators using assistive technology may miss status updates because there are no `aria-live` regions set up in the app. Status transitions in campaigns and claim receipts need to be explicitly announced to screen readers.
5+
6+
## What was implemented
7+
- Created a `<LiveRegion>` component in `app/frontend/src/components/LiveRegion.tsx` that uses `aria-live="polite"` and `role="status"` to announce message changes. It includes a small debounce queue (50ms) to ensure consecutive rapid updates are announced clearly.
8+
- Created `getStatusTransitionMessage` utility in `app/frontend/src/lib/status-messages.ts` to map raw status values to verbose, human-readable text (e.g. "Campaign status changed from Active to Paused.").
9+
- Integrated `<LiveRegion>` into `app/frontend/src/app/[locale]/campaigns/page.tsx` and `app/frontend/src/app/[locale]/claim-receipt/page.tsx`, storing previous state with a `useRef` and detecting status transitions to trigger announcements.
10+
- Added `jest-axe` tests for `<LiveRegion>` in `app/frontend/test/live-region.spec.tsx` to verify standard accessibility compliance and ensure text transitions correctly.
11+
12+
## Assumptions made during Phase 1
13+
- `claim-receipt/page.tsx` is the intended target for the "claim-status / claim detail page" mentioned in the requirements, as it's the primary location for viewing a claim's status.
14+
- Campaign transitions happen via optimistic mutation and derive status from the local component list, so `useRef` was used to detect status changes cleanly without modifying the global store or mutation logic.
15+
16+
## How to manually verify
17+
1. Run the application (`pnpm run dev`).
18+
2. Turn on a screen reader (VoiceOver, NVDA, or JAWS).
19+
3. Navigate to the NGO Campaigns page and perform an action like "Pause" or "Resume" on a campaign. The screen reader should announce "Campaign status changed from Active to Paused."
20+
4. Inspect the DOM to verify the visually hidden `aria-live` region updates its text content.
21+
22+
## Follow-up work recommended
23+
- Extend this pattern to other dynamic status indicators in the application (like `VerificationReviewPage` queues or `ActivityCenter` toasts) to ensure universal accessibility coverage.

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,11 @@ cd app/onchain && make test
144144

145145
## Contributing
146146

147-
We welcome contributions that make humanitarian aid delivery more transparent and efficient. When submitting changes:
147+
We welcome contributions that make humanitarian aid delivery more transparent and efficient.
148+
149+
Please read our [End-to-End Contributor Journey](docs/contributing/journey.md) for a complete walk-through of finding an issue, local setup, PR conventions, CI expectations, and the merge process.
150+
151+
When submitting changes:
148152

149153
1. Open an issue to discuss the proposed change before implementing
150154
2. Keep pull requests small and focused on a single concern

0 commit comments

Comments
 (0)