Skip to content

Commit f43bf64

Browse files
authored
Merge branch 'main' into feat/policy-beneficiary
2 parents 3f631fd + d763edd commit f43bf64

182 files changed

Lines changed: 12868 additions & 466 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.

.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Copy this file to .env and fill in values.
22
# .env is gitignored — never commit secrets.
3+
#
4+
# CONVENTION:
5+
# NEXT_PUBLIC_* → safe to expose in the browser bundle
6+
# (no prefix) → server-only; NEVER import in client components
7+
# use `import '@/lib/server-guard'` to enforce this
38

49
# ── Redis ─────────────────────────────────────────────────────────────────────
510
REDIS_HOST=127.0.0.1

.github/workflows/ci.yml

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,34 @@ permissions:
1212
contents: read
1313

1414
jobs:
15+
# ── Frontend quality gate ─────────────────────────────────────────────────
16+
frontend:
17+
name: Frontend (lint → typecheck → build)
18+
runs-on: ubuntu-latest
19+
defaults:
20+
run:
21+
working-directory: frontend
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- uses: actions/setup-node@v4
26+
with:
27+
node-version-file: .nvmrc
28+
cache: npm
29+
cache-dependency-path: frontend/package-lock.json
30+
31+
- name: Install dependencies
32+
run: npm ci
33+
34+
- name: Lint (fail on warnings)
35+
run: npm run lint -- --max-warnings=0
36+
37+
- name: Typecheck
38+
run: npm run typecheck
39+
40+
- name: Build
41+
run: npm run build
42+
1543
# ── Soroban ABI golden-vector drift guard ────────────────────────────────
1644
golden-vectors:
1745
name: Soroban ABI golden vectors
@@ -148,7 +176,7 @@ jobs:
148176
e2e-tests:
149177
name: Playwright E2E tests
150178
runs-on: ubuntu-latest
151-
needs: quality-build
179+
needs: frontend
152180
steps:
153181
- uses: actions/checkout@v4
154182
- uses: actions/setup-node@v4
@@ -167,7 +195,69 @@ jobs:
167195
with:
168196
name: playwright-failure-${{ github.run_id }}
169197
path: |
198+
feat/accessibility-audit
199+
sbom-backend.json
200+
sbom-frontend.json
201+
retention-days: 90
202+
203+
# ── Frontend ──────────────────────────────────────────────────────────────
204+
frontend:
205+
name: Frontend (Next.js / TypeScript)
206+
runs-on: ubuntu-latest
207+
defaults:
208+
run:
209+
working-directory: frontend
210+
steps:
211+
- uses: actions/checkout@v4
212+
213+
- uses: actions/setup-node@v4
214+
with:
215+
node-version: 22
216+
cache: npm
217+
cache-dependency-path: frontend/package-lock.json
218+
219+
- run: npm ci
220+
- run: npm run lint
221+
- run: npm run check-docs
222+
- run: npm run build
223+
- run: npm test
224+
225+
# ── Accessibility (axe) ───────────────────────────────────────────────────
226+
accessibility:
227+
name: Accessibility (axe / Playwright)
228+
runs-on: ubuntu-latest
229+
defaults:
230+
run:
231+
working-directory: frontend
232+
steps:
233+
- uses: actions/checkout@v4
234+
235+
- uses: actions/setup-node@v4
236+
with:
237+
node-version: 22
238+
cache: npm
239+
cache-dependency-path: frontend/package-lock.json
240+
241+
- run: npm ci
242+
- run: npm run build
243+
244+
- name: Install Playwright browsers
245+
run: npx playwright install --with-deps chromium
246+
247+
- name: Run axe accessibility checks
248+
run: npx playwright test tests/accessibility.spec.ts --reporter=list
249+
env:
250+
BASE_URL: http://localhost:3000
251+
252+
- uses: actions/upload-artifact@v4
253+
if: failure()
254+
with:
255+
name: axe-report-${{ github.sha }}
256+
path: frontend/playwright-report/
257+
retention-days: 14
258+
170259
test-results
171260
playwright-report
172261
traces
173262
.playwright/traces
263+

.github/workflows/load-tests.yml

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
name: Load Tests (Staging)
2+
3+
# Runs on a schedule against staging, or manually via workflow_dispatch.
4+
# NEVER targets production endpoints.
5+
#
6+
# Secrets required (set in GitHub repo settings → Secrets):
7+
# STAGING_BASE_URL — e.g. https://staging.niffyinsur.com/api
8+
# STAGING_TEST_JWT — short-lived JWT for authenticated write flows
9+
# (see backend/loadtests/README.md for generation)
10+
#
11+
# Failure alerts: the job fails when k6 thresholds are breached.
12+
# GitHub will send a notification to the repo watchers.
13+
# For Slack/PagerDuty alerts, add a notification step after the k6 run.
14+
15+
on:
16+
# Run every Monday at 08:00 UTC
17+
schedule:
18+
- cron: '0 8 * * 1'
19+
# Allow manual trigger from the Actions tab
20+
workflow_dispatch:
21+
inputs:
22+
target_url:
23+
description: 'Override staging base URL (default: STAGING_BASE_URL secret)'
24+
required: false
25+
type: string
26+
27+
jobs:
28+
load-test:
29+
name: k6 Load Tests
30+
runs-on: ubuntu-latest
31+
# Only run on the default branch to avoid accidental staging hammering from PRs
32+
if: github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'
33+
34+
steps:
35+
- uses: actions/checkout@v4
36+
37+
- name: Install k6
38+
run: |
39+
sudo gpg -k
40+
sudo gpg --no-default-keyring \
41+
--keyring /usr/share/keyrings/k6-archive-keyring.gpg \
42+
--keyserver hkp://keyserver.ubuntu.com:80 \
43+
--recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
44+
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] \
45+
https://dl.k6.io/deb stable main" \
46+
| sudo tee /etc/apt/sources.list.d/k6.list
47+
sudo apt-get update -qq
48+
sudo apt-get install -y k6
49+
50+
- name: Set target URL
51+
id: url
52+
run: |
53+
URL="${{ github.event.inputs.target_url || secrets.STAGING_BASE_URL }}"
54+
if [ -z "$URL" ]; then
55+
echo "::error::STAGING_BASE_URL secret is not set. Aborting."
56+
exit 1
57+
fi
58+
echo "base_url=$URL" >> "$GITHUB_OUTPUT"
59+
60+
- name: Smoke test (sanity check before load)
61+
env:
62+
BASE_URL: ${{ steps.url.outputs.base_url }}
63+
run: k6 run --vus 2 --duration 30s backend/loadtests/smoke.js
64+
65+
- name: Load test — claims list (read-heavy)
66+
env:
67+
BASE_URL: ${{ steps.url.outputs.base_url }}
68+
run: |
69+
k6 run \
70+
--out json=backend/docs/perf/$(date +%Y-%m-%d)-claims-list.json \
71+
backend/loadtests/claims-list.js
72+
73+
- name: Load test — health and quotes
74+
env:
75+
BASE_URL: ${{ steps.url.outputs.base_url }}
76+
run: |
77+
k6 run \
78+
--out json=backend/docs/perf/$(date +%Y-%m-%d)-health-quotes.json \
79+
backend/loadtests/health-and-quotes.js
80+
81+
- name: Load test — authenticated write flow
82+
env:
83+
BASE_URL: ${{ steps.url.outputs.base_url }}
84+
TEST_JWT: ${{ secrets.STAGING_TEST_JWT }}
85+
# Only run if the secret is available (skip on forks)
86+
if: env.TEST_JWT != ''
87+
run: |
88+
k6 run \
89+
--out json=backend/docs/perf/$(date +%Y-%m-%d)-claim-submit.json \
90+
backend/loadtests/claim-submit.js
91+
92+
- name: Upload k6 reports
93+
if: always()
94+
uses: actions/upload-artifact@v4
95+
with:
96+
name: k6-reports-${{ github.run_id }}
97+
path: backend/docs/perf/*.json
98+
retention-days: 90
99+
100+
# Optional: post a Slack notification on threshold breach
101+
# Uncomment and configure SLACK_WEBHOOK_URL secret to enable.
102+
# - name: Notify Slack on failure
103+
# if: failure()
104+
# uses: slackapi/slack-github-action@v1
105+
# with:
106+
# payload: |
107+
# {"text": "⚠️ Load test thresholds breached on staging. Check the run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"}
108+
# env:
109+
# SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
22

CONTRIBUTING.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,86 @@
1+
feat/accessibility-audit
2+
# Contributing to NiffyInsur
3+
4+
## Accessibility Testing
5+
6+
Accessibility is a first-class requirement. Every PR that touches UI must pass the checks below before merge.
7+
8+
### Automated axe checks (CI)
9+
10+
The `accessibility` CI job runs `@axe-core/playwright` against the quote, policy, claims, and vote routes. **No critical violations are permitted.** The job uploads a Playwright report as an artifact on failure.
11+
12+
Run locally:
13+
14+
```bash
15+
cd frontend
16+
npm install
17+
npm run build
18+
npx playwright test tests/accessibility.spec.ts
19+
```
20+
21+
### Manual axe spot-check
22+
23+
1. Install the [axe DevTools browser extension](https://www.deque.com/axe/devtools/).
24+
2. Open each targeted route: `/quote`, `/policy`, `/claims`, `/claims/<id>`.
25+
3. Run the full-page scan. Resolve any **critical** or **serious** violations before opening a PR.
26+
27+
### Keyboard-only walkthrough
28+
29+
Verify these flows using only the keyboard (no mouse):
30+
31+
| Flow | Steps |
32+
|------|-------|
33+
| Get a quote | Tab through all form fields → submit → confirm quote preview updates |
34+
| Purchase policy | Complete all 4 wizard steps using Tab / Shift+Tab / Enter / Space |
35+
| File a claim | Complete all 4 wizard steps; confirm focus moves to new step heading on advance |
36+
| Cast a vote | Tab to Approve / Reject buttons → Enter to open confirm modal → Tab within modal → confirm or cancel |
37+
| Connect wallet | Tab to "Connect Wallet" button → Enter → confirm status announced |
38+
39+
Focus must always be visible. After a modal opens, focus must move inside it. After a modal closes, focus must return to the trigger.
40+
41+
### Screen reader spot-check (per major release)
42+
43+
Test at minimum one major flow per release with a screen reader:
44+
45+
- **macOS / iOS**: VoiceOver (`Cmd+F5` to toggle)
46+
- **Windows**: NVDA (free) or Narrator
47+
- **Android**: TalkBack
48+
49+
Checklist:
50+
- [ ] Transaction status updates are announced (aria-live regions on wizard and policy pages)
51+
- [ ] Step changes in wizards are announced (focus moves to hidden `<h2>` with step name)
52+
- [ ] Quote preview updates are announced on the quote page
53+
- [ ] Vote tally countdown is announced via `aria-live="polite"`
54+
- [ ] Modal title is read when dialog opens
55+
- [ ] Icon-only buttons have accessible names (aria-label or sr-only text)
56+
- [ ] Claim status badges convey outcome via text/shape, not color alone
57+
58+
### Reduced-motion
59+
60+
Verify that setting `prefers-reduced-motion: reduce` (OS accessibility setting or DevTools emulation) stops all non-essential animations. Loading spinners should become static; slide/fade transitions should be instant.
61+
62+
### Heading hierarchy
63+
64+
Each page must have exactly one `<h1>`. Use the browser Accessibility Tree panel (DevTools → Accessibility) or the [HeadingsMap extension](https://rumoroso.bitbucket.io/headingsmap/) to verify a logical heading order with no skipped levels.
65+
66+
### Landmarks
67+
68+
Every page must have at minimum: `<main>`, `<nav>` (if navigation present), and `<footer>` (if present). Verify with the Accessibility Tree or axe.
69+
70+
### Color contrast
71+
72+
All text must meet WCAG AA contrast ratios (4.5:1 normal text, 3:1 large text). Use the axe scan or the browser color-contrast checker. Claim outcomes (Approved / Rejected / Pending) must not rely on color alone — shape indicators and text labels are required.
73+
74+
### Adding new UI
75+
76+
When adding new interactive components:
77+
78+
1. Icon-only controls **must** have `aria-label` or a visually hidden label.
79+
2. Async state changes (transactions, loading) **must** update an `aria-live` region.
80+
3. Multi-step wizards **must** move focus to a step heading on step change.
81+
4. Modals **must** trap focus and return it to the trigger on close (Radix Dialog handles this automatically).
82+
5. Animations **must** respect `prefers-reduced-motion` via the global CSS rule in `globals.css`.
83+
184
# Contributing
285

386
## Soroban ABI golden vectors
@@ -48,3 +131,4 @@ Before tagging a release:
48131
- **Never** commit real private keys (Stellar secret keys start with `S`).
49132
- Use only placeholder G-addresses and C-addresses in vector `inputs`.
50133
- The CI job checks for secret-key patterns and will fail if any are found.
134+
main

README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# niff-Stellar-shurance
2+
3+
Decentralized insurance platform built on the Stellar/Soroban blockchain.
4+
5+
## Setup
6+
7+
```bash
8+
# 1. Clone
9+
git clone https://github.com/your-org/niff-Stellar-shurance.git && cd niff-Stellar-shurance
10+
11+
# 2. Install
12+
cp frontend/.env.example frontend/.env.local # fill in values
13+
cd frontend && npm install
14+
15+
# 3. Run
16+
npm run dev
17+
```
18+
19+
Open [http://localhost:3000](http://localhost:3000).
20+
21+
## Requirements
22+
23+
- Node.js `>=22` (see `.nvmrc`)
24+
- npm `>=10`
25+
26+
## Project Structure
27+
28+
```
29+
frontend/src/
30+
├── app/ # Next.js App Router routes & layouts
31+
├── features/ # Feature modules: policies/, claims/, wallet/
32+
│ └── <feature>/{components,hooks,api}/
33+
├── components/ui/ # Shared primitive components (Shadcn-style)
34+
├── lib/ # Utilities, Stellar SDK wrappers, schemas
35+
└── styles/ # Global CSS and Tailwind theme tokens
36+
```
37+
38+
## Quality Gates
39+
40+
```bash
41+
npm run lint # ESLint (fails on warnings)
42+
npm run typecheck # tsc --noEmit strict check
43+
npm run build # Production build
44+
```
45+
46+
CI runs all three sequentially on every push/PR to `main`.
47+
48+
## Environment Variables
49+
50+
Copy `frontend/.env.example``frontend/.env.local`.
51+
52+
- `NEXT_PUBLIC_*` variables are safe for the browser.
53+
- All other variables are **server-only** — never import them in Client Components.
54+
Use `import '@/lib/server-guard'` at the top of server-only modules to enforce this at build time.

0 commit comments

Comments
 (0)