Skip to content

Commit 78a541a

Browse files
JoeX17BigBen-7
andauthored
feat: email bounce handling, job monitoring dashboard, API key analytics, benchmarking (#988)
* feat: email bounce handling, queue monitoring, API key analytics, benchmark suite Closes #943, #944, #945, #946 - Email bounce/complaint webhook handling with spam complaint support and sender reputation dashboard (GET /email/reputation) - List-Unsubscribe header added to marketing emails - Hard bounce auto-suppress sets user emailStatus to BOUNCED - Background job monitoring dashboard for BullMQ queues under admin/queues with retry/cancel endpoints (admin-only) - API key usage analytics with daily aggregation, configurable monthly quota, 429 on exceeded, usage alerts at 75/90/100% - GET /auth/api-keys/:id/usage returns detailed usage breakdown - Performance benchmark suite (scripts/benchmark.ts) for 10 critical endpoints with p50/p95/p99 latencies and performance budgets - GitHub Actions workflow for weekly and PR-triggered benchmarks - Prisma schema: ApiKeyUsageDaily model, monthlyQuota on ApiKey, SpamAction enum and spamAction field on EmailBounce * fix: add Optional to ApiKeyAnalyticsService dependency, fix test mocks * fix: update email bounce test expectation BOUNCED not INVALID --------- Co-authored-by: bigben-7 <benardsimon7@gmail.com>
1 parent 268112c commit 78a541a

21 files changed

Lines changed: 1129 additions & 169 deletions

‎.github/workflows/benchmark.yml‎

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
name: API Performance Benchmark
2+
3+
on:
4+
pull_request:
5+
branches: [main, develop]
6+
schedule:
7+
- cron: '0 6 * * 1' # Weekly on Monday at 6am UTC
8+
workflow_dispatch:
9+
inputs:
10+
iterations:
11+
description: 'Number of iterations per endpoint'
12+
required: false
13+
default: '50'
14+
15+
jobs:
16+
benchmark:
17+
runs-on: ubuntu-latest
18+
19+
services:
20+
postgres:
21+
image: postgres:15
22+
env:
23+
POSTGRES_USER: postgres
24+
POSTGRES_PASSWORD: postgres
25+
POSTGRES_DB: test
26+
ports:
27+
- 5432:5432
28+
options: >-
29+
--health-cmd pg_isready
30+
--health-interval 10s
31+
--health-timeout 5s
32+
--health-retries 5
33+
redis:
34+
image: redis:7
35+
ports:
36+
- 6379:6379
37+
38+
steps:
39+
- uses: actions/checkout@v3
40+
41+
- name: Setup Node.js
42+
uses: actions/setup-node@v3
43+
with:
44+
node-version: '20'
45+
cache: 'npm'
46+
47+
- name: Install dependencies
48+
run: npm ci
49+
50+
- name: Generate Prisma Client
51+
run: npx prisma generate
52+
env:
53+
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
54+
55+
- name: Sync database schema
56+
run: npx prisma db push --skip-generate --accept-data-loss
57+
env:
58+
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
59+
60+
- name: Build application
61+
run: npm run build
62+
63+
- name: Start application
64+
run: |
65+
npm run start:dist &
66+
for i in $(seq 1 30); do
67+
if curl -s http://localhost:3000/api > /dev/null 2>&1; then
68+
echo "Server is up"
69+
break
70+
fi
71+
echo "Waiting for server... ($i)"
72+
sleep 2
73+
done
74+
env:
75+
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
76+
REDIS_URL: redis://localhost:6379
77+
JWT_SECRET: bench-secret
78+
JWT_REFRESH_SECRET: bench-refresh-secret
79+
NODE_ENV: production
80+
81+
- name: Run benchmarks
82+
run: npx ts-node scripts/benchmark.ts
83+
env:
84+
BENCHMARK_BASE_URL: http://localhost:3000/api
85+
BENCHMARK_ITERATIONS: ${{ github.event.inputs.iterations || '100' }}
86+
87+
- name: Upload benchmark results
88+
uses: actions/upload-artifact@v4
89+
if: always()
90+
with:
91+
name: benchmark-results
92+
path: benchmark-results.json
93+
94+
- name: Comment on PR with results
95+
if: github.event_name == 'pull_request' && always()
96+
uses: actions/github-script@v7
97+
with:
98+
script: |
99+
const fs = require('fs');
100+
try {
101+
const report = JSON.parse(fs.readFileSync('benchmark-results.json', 'utf8'));
102+
const lines = ['## API Benchmark Results\n'];
103+
lines.push(`| Endpoint | p50 (ms) | p95 (ms) | p99 (ms) | Budget (ms) | Status |`);
104+
lines.push(`|----------|----------|----------|----------|-------------|--------|`);
105+
for (const r of report.results) {
106+
const status = r.passed ? 'PASS' : 'FAIL';
107+
lines.push(`| ${r.endpoint} | ${r.latencyMs.p50} | ${r.latencyMs.p95} | ${r.latencyMs.p99} | ${r.budgetMs} | ${status} |`);
108+
}
109+
lines.push(`\n**Summary:** ${report.summary.passed}/${report.summary.total} passed`);
110+
await github.rest.issues.createComment({
111+
owner: context.repo.owner,
112+
repo: context.repo.repo,
113+
issue_number: context.issue.number,
114+
body: lines.join('\n'),
115+
});
116+
} catch (e) {
117+
console.log('Could not post benchmark results:', e.message);
118+
}

‎docs/MFA_ROADMAP.md‎

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,3 @@
1-
<<<<<<< ours
2-
# Multi-Factor Authentication (MFA) Roadmap
3-
4-
## Purpose
5-
This document outlines the planned MFA implementation for PropChain. MFA is opt-in and will be introduced without breaking current authentication flows.
6-
7-
## Goals
8-
- Add second-factor verification for sensitive actions and login.
9-
- Support TOTP-based authenticators and backup codes.
10-
- Keep MFA optional for users.
11-
- Provide a developer-friendly path for future enrollment, verification, and recovery.
12-
13-
## Current placeholder endpoints
14-
The backend exposes the following auth-related endpoints today:
15-
16-
- `POST /auth/2fa/setup` — initialize enrollment, generate a TOTP secret, QR code URL, and backup codes.
17-
- `POST /auth/2fa/verify` — verify the TOTP code and enable two-factor authentication for the user.
18-
- `POST /auth/2fa/disable` — disable two-factor authentication after password confirmation.
19-
20-
These endpoints are currently implemented in the `AuthService` as enrollment and verification flow placeholders.
21-
22-
## Implementation plan
23-
24-
### Phase 1: Secure enrollment and verification
25-
1. Generate a TOTP secret and hashed backup codes.
26-
2. Store the secret and backup codes in the user record.
27-
3. Present the user with a QR code URL and a code list.
28-
4. Verify the first TOTP code before enabling MFA.
29-
30-
### Phase 2: Login flow support
31-
1. Require a second factor during login only for users with MFA enabled.
32-
2. Accept either a valid TOTP code or an unused backup code.
33-
3. Consume backup codes on use and maintain a fresh in-memory/hard storage list.
34-
35-
### Phase 3: Recovery and revocation
36-
1. Add endpoints to regenerate backup codes.
37-
2. Add endpoint to disable MFA after re-authentication.
38-
3. Audit MFA changes in user activity logs.
39-
40-
## Notes
41-
- The API contract is simple and opt-in.
42-
- Existing auth workflows continue to work for users who do not enable MFA.
43-
- Future expansion can include push notifications, SMS OTP, or hardware keys.
44-
=======
451
# MFA / 2FA Roadmap
462

473
## Current State
@@ -89,4 +45,3 @@ Two-factor authentication is fully implemented using TOTP (Time-based One-Time P
8945
- [ ] Hardware key (WebAuthn/FIDO2) support
9046
- [ ] Admin-enforced 2FA for agent/admin roles
9147
- [ ] Trusted device management
92-
>>>>>>> theirs

0 commit comments

Comments
 (0)