Skip to main content

Performance Test Plan

Performance Test PlanPlan: Drop — Fintech Payment App

Project: {{PROJECT_NAME}}Drop — Remittance + QR Payments Version: {{VERSION}}1.0 Date: {{DATE}}2026-02-23 Author: {{AUTHOR}}John (AI Director) Status: Draft | In Review | Approved Reviewers: {{REVIEWERS}}Alem Bašić (CEO)

Document History

Version Date Author Changes
0.1 {{DATE}}2026-02-23 {{AUTHOR}}John Initial draftperformance plan — targets from NFR-P01..P06 + api-benchmarks.test.ts

1. Performance Testing Objectives

  1. Validate that {{PROJECT_NAME}}Drop meets the performance SLAs defined in the NFR document under normal operating conditions (200 concurrent users on SQLite MVP; 5,000+ on PostgreSQL Phase 1)
  2. Determine the maximumSQLite capacityconcurrent theuser system can handlelimit before performancemigrating degradesto PostgreSQL (target: migrate at 200 concurrent)
  3. Identify bottlenecks (database,bcrypt application,hashing, infrastructure)DB queries, rate limiter) before production release
  4. Establish a performance baseline for regression comparison in future releases

Reference NFRs: {{NFR_DOC_LINK}}docs/BUSINESS-REQUIREMENTS/non-functional-requirements.md — Section 2 (Performance)


2. Performance Requirements Reference

(P95)
Endpoint / Feature P50 P90 P95 P99 Error Rate ThroughputNotes
GET /api/health (homepage) < {{P50}}ms20ms < {{P90}}ms50ms < {{P95}}ms100ms < {{P99}}ms200ms < {{ERR}}%0.1% {{RPS}}Health req/scheck — fast always
POST /api/auth/login (bcrypt) < {{P50}}ms700ms < {{P90}}ms900ms < {{P95}}ms1,000ms < {{P99}}ms1,200ms < {{ERR}}%0.1% {{RPS}}bcrypt req/s12 rounds; NFR-P03
POST /api/auth/register (bcrypt)< 700ms< 900ms< 1,000ms< 1,200ms< 0.1%Same bcrypt cost
POST /api/transactions/remittance< 200ms< 350ms< 500ms< 800ms< 0.1%NFR-P02
POST /api/transactions/qr-payment< 200ms< 350ms< 500ms< 800ms< 0.1%NFR-P02
GET /api/{{RESOURCE}}rates < {{P50}}ms20ms < {{P90}}ms50ms < {{P95}}ms100ms < {{P99}}ms200ms < {{ERR}}%0.1% {{RPS}}Cached req/s/ fast
POSTGET /api/{{RESOURCE}}transactions < {{P50}}ms50ms < {{P90}}ms100ms < {{P95}}ms200ms < {{P99}}ms400ms < {{ERR}}%0.1% {{RPS}} req/sNFR-P02
DatabaseDB SELECT query < {{DB_P95}}ms10ms 0% NFR-P04
DB INSERT query < 20ms0%NFR-P04
50 concurrent rate limit checks0%< 2,000ms total (NFR-P06)
Page load (First Contentful Paint) < {{FCP}}ms3,000ms NFR-P01 (4G, cold cache)
Core Web Vitals LCP< 2,500msNFR-P05

3. Test Types

3.1 Load Testing — Normal Load Simulation

Objective: Confirm the systemDrop meets SLAs under expected normal load (Norwegian remittance corridor peak traffic) Normal load definition: {{NORMAL_USERS}}200 concurrent users (SQLite MVP limit) / {{NORMAL_RPS}}~20 requests/second Duration: {{LOAD_DURATION}}10 minutes (after 2-minute ramp-up) Pass criteria: All SLA targets in Section 2 met with ≤ {{LOAD_ERROR_RATE}}%0.1% error rate

3.2 Stress Testing — Beyond Normal Capacity

Objective: Find theSQLite maximumconcurrent capacityuser andlimit; understand failure behavior to plan PostgreSQL migration Starting point: {{STRESS_START_USERS}}50 users, increasing by {{STRESS_INCREMENT}}25 users every {{STRESS_STEP}}min2 minutes Stop condition: Error rate > {{STRESS_STOP_ERROR}}%5% or P99 > 3,000ms or service crashes Pass criteria: System fails gracefully (circuit breakers,with meaningful error messages),messages (429 rate limit, not 500); data integrity maintainedmaintained; no double-spend under stress

3.3 Spike Testing — Sudden Traffic Surges

Objective: VerifySimulate systemscenarios handleslike marketing campaigns or media coverage causing sudden trafficuser spikes without crashinginflux Baseline: {{SPIKE_BASELINE}}20 users Spike to: {{SPIKE_PEAK}}100 users ({{SPIKE_MULTIPLIER}}× baseline) Spike duration: {{SPIKE_DURATION}}2 minutes Pass criteria: System recovers to baseline performance within {{SPIKE_RECOVERY}}5 minutes after spike endsends; no data corruption

3.4 Endurance / Soak Testing — Sustained Load

Objective: Identify resourceSQLite file lock issues, connection pool exhaustion, memory leaks and degradation under sustained load Load level: {{SOAK_USERS}}50 users ({{SOAK_PERCENT}}%25% of normal200 load)concurrent limit) Duration: {{SOAK_DURATION}}2 hours Metrics to watch: MemorySQLite write queue depth, memory usage trend, response time trend, disk space, database connection pooltrend Pass criteria: No upward trend in memory/response time over the soak periodperiod; no SQLite database locked errors

3.5 Scalability Testing — IncreasingPhase Load1 PostgreSQL Migration

Objective: Verify linearPostgreSQL (ormigration better)enables proportional scaling asfor infrastructurePhase grows1 target (5,000+ users) Test: Step load from {{SCALE_START}}200 to {{SCALE_MAX}}1,000 concurrent users whileon scalingPostgreSQL from {{MIN_INSTANCES}} to {{MAX_INSTANCES}} instancesstaging Pass criteria: ThroughputP95 increasesstays proportionallyunder (≥500ms {{SCALE_EFFICIENCY}}%as efficiency)concurrent withusers addedscale; instancesno P99 explosion Note: PostgreSQL not yet deployed — Phase 1 task. This plan establishes the baseline for comparison.


4. Load Profiles

Scenario Virtual Users Ramp-Up Hold Ramp-Down Think Time IterationsNotes
Smoke (quick sanity) {{SMOKE_VU}}5 {{SMOKE_RAMP}}s10s {{SMOKE_HOLD}}min1min 30s10s 1s 1Per-deploy quick check
Load (normal)normal SQLite) {{LOAD_VU}}200 {{LOAD_RAMP}}min2min {{LOAD_HOLD}}min10min 5min1min {{THINK}}s2s NFR-S01 MVP target
Stress (find limit) {{STRESS_VU}}Up (increasing)to 500 {{STRESS_RAMP}}min2min steps Until failurefail {{THINK}}s2s SQLite vs PostgreSQL
Spike (traffic burst) {{SPIKE_VU}}100 (instant) 0s {{SPIKE_HOLD}}min2min 0s {{THINK}}s1s Marketing/media event
Soak (stability) {{SOAK_VU}}50 {{SOAK_RAMP}}min1min {{SOAK_HOLD}}h2h 10min2min {{THINK}}s3s Memory leak detection

Think time simulation: Random between {{THINK_MIN}}s and {{THINK_MAX}}s (realisticRealistic user behavior)think time of 2–5s (Norwegian users reviewing remittance details before confirming)


5. Test Environment

CRITICAL:NOTE: Performance tests run onagainst a dedicatedrepresentative environmentstaging withenvironment. theSQLite sameMVP infrastructurelimits sizingare astested production.on Fly.io staging (1× shared CPU, 256MB RAM). Phase 1 PostgreSQL tests require production-equivalent environment.

Component TestMVP EnvironmentStaging (Fly.io) ProductionPhase 1 Target
App instances {{TEST_APP_INSTANCES}} ×shared-cpu-1x {{TEST_INSTANCE_TYPE}}(256MB) {{PROD_APP_INSTANCES}} × {{PROD_INSTANCE_TYPE}}dedicated-cpu-2x
Database {{TEST_DB_SPEC}}SQLite on persistent volume {{PROD_DB_SPEC}}PostgreSQL (managed Fly.io)
CacheRegion {{TEST_CACHE_SPEC}}Stockholm (arn) {{PROD_CACHE_SPEC}}Stockholm (arn)
CDN DisabledNone (directAPI hit)only) EnabledNone (API) / Vercel (landing)

Load generator infrastructure:generator:

  • Tool: {{PERF_TOOL}}Vitest benchmarks (api-benchmarks.test.ts) for micro-benchmarks
  • Load generator for integration: k6 scripts in infrastructure/performance/
  • Load generator location: {{LG_LOCATION}}Local or CI runner (same region as app,Fly.io separate VPC)
  • Load generator sizing: {{LG_SPEC}}Stockholm)

6. Test Data Requirements

productiondata
Data Type Volume Generation Method
Users {{USER_COUNT}}500 Scriptnpm +run factorydb:seed:perf
{{DATA_TYPE_1}}Recipients (remittance targets) {{VOLUME}}200 Bulk importSeed script
{{DATA_TYPE_2}}Merchants {{VOLUME}}50 Bulk importSeed script
SearchTransactions index(historical) Production-sized10,000 SeededBulk frominsert anonymizedseed
Exchange rates6 corridors (fixed)Always seeded

Database size at test time: {{DB_SIZE}}GB~50MB SQLite file Data preparation: bashnpm scripts/perf-seed.shrun db:seed:perf (estimated time: {{SEED_TIME}}min)~2 minutes)


7. Tools & Infrastructure

Tool Version Purpose Config
{{PERF_TOOL}}Vitest (bench) {{VERSION}}2.x LoadMicro-benchmarks: generationbcrypt, DB queries, rate limiter perf-tests/src/drop-app/__tests__/api-benchmarks.test.ts
{{MONITOR_TOOL}}k6 {{VERSION}}Latest Real-timeHTTP metricsload duringtesting test(concurrent users) Dashboard linkinfrastructure/performance/k6-scripts/
{{APM_TOOL}}Fly.io Metrics {{VERSION}} ApplicationReal-time performanceCPU/memory/request profilingmetrics DashboardFly.io linkdashboard
{{DB_MONITOR}}SQLite EXPLAIN QUERY PLAN {{VERSION}} DatabaseDB query analysis DashboardVia linkflyctl ssh console

Script location: {{PERF_SCRIPT_PATH}}src/drop-app/__tests__/api-benchmarks.test.ts (Vitest benchmarks)


8. Key Metrics to Capture

Response Time

Metric Description Tool
P50 (median) Half of requests faster than this {{TOOL}}Vitest bench / k6
P90 90% of requests faster than this {{TOOL}}k6
P95 95% of requests faster than this {{TOOL}}k6 (NFR gate)
P99 99% of requests faster than this {{TOOL}}k6
Max Worst single request {{TOOL}}k6

Throughput

Metric Description
Requests/second Total API throughput at peak load
Transactions/second Successful businessremittance/QR transactions/transactions per second
Data transferredTotal MB/s in + out

Error Metrics

Metric Target
HTTP error rate (5xx) < {{HTTP_ERR}}%0.1%
TimeoutSQLite ratedatabase locked errors <0% {{TIMEOUT_ERR}}%(rate limit blocks excess concurrency)
Connection refusedtimeout rate 0%< 0.1%

Resource Utilization (Fly.io Metrics)

200ms
Resource Warning Critical
App CPU > {{CPU_WARN}}%70% > {{CPU_CRIT}}%90%
App Memory > {{MEM_WARN}}%80% (200MB / 256MB) > {{MEM_CRIT}}%95%
DBSQLite CPUwrite queue > {{DB_CPU_WARN}}%50ms wait > {{DB_CPU_CRIT}}%
DB Connections> {{DB_CONN_WARN}}% of pool> {{DB_CONN_CRIT}}%
Cache hit ratio< {{CACHE_HIT}}%< {{CACHE_CRIT}}%wait

Database Query Performance (NFR-P04)

undernormal
Metric Target
AverageSELECT query timeP95 < {{AVG_QUERY}}ms10ms
INSERT query P95< 20ms
Slow queries (> {{SLOW_THRESHOLD}}ms)100ms) < {{SLOW_COUNT}}0 per minute
Deadlocks0load

9. SLA Targets Per Endpoint (from api-benchmarks.test.ts)

Endpoint Method P95 SLA Error Rate SLA Notes
/api/auth/login GETPOST {{P95}}ms1,000ms < {{ERR}}%0.1% Staticbcrypt or12 cachedrounds
/api/auth/loginregister POST {{P95}}ms1,000ms < {{ERR}}%0.1% Authbcrypt critical12 pathrounds
/api/{{RESOURCE}}transactions/remittance GETPOST {{P95}}ms500ms < {{ERR}}%0.1% {{NOTE}}NFR-P02
/api/{{RESOURCE}}transactions/qr-payment POST {{P95}}ms500ms < {{ERR}}%0.1% {{NOTE}}NFR-P02
/api/ratesGET100ms< 0.1%Cached
/api/healthGET100ms< 0.1%Always fast
DB SELECT10ms0%NFR-P04
DB INSERT20ms0%NFR-P04
50 concurrent rate limit2,000ms total0%NFR-P06

10. Baseline Establishment (api-benchmarks.test.ts Results)

Baseline criteria:established: SystemPhase in0 stableMVP state,on seededlocal withdev production-realistic(SQLite data, running load test scenario for {{BASELINE_DURATION}} minutes

Baseline metrics to record:in-memory)

Metric Baseline Value Date Recorded Test
P95bcrypt latencyhash (key endpoints)register) TBD~800ms {{DATE}}2026-02-23api-benchmarks.test.ts
Throughputbcrypt atverify normal load(login) TBD~800ms {{DATE}}2026-02-23api-benchmarks.test.ts
ErrorRate ratelimit atcheck normal(50 loadconcurrent) TBD~1,800ms {{DATE}}2026-02-23api-benchmarks.test.ts
CPUDB utilization at normal loadSELECT TBD~5ms {{DATE}}2026-02-23api-benchmarks.test.ts
MemoryDB utilization at normal loadINSERT TBD~10ms {{DATE}}2026-02-23api-benchmarks.test.ts
SHA-256 hash (reject baseline)~1ms2026-02-23auth.test.ts

Regression threshold: Alert if any metric degrades > {{REGRESSION_THRESHOLD}}%15% vs baseline


11. Test Execution Schedule

Run Type Trigger Environment Frequency
SmokeBenchmark smoke Every deploymentCI run StagingLocal / CI runner Per deploycommit
Loadapi-benchmarks.test.ts (baseline)fullEvery PRCIPer PR
k6 load test Release candidate Production-sizedFly.io staging Per release
Stressk6 stress test MajorBefore featurePhase releases1 PostgreSQL migration Production-sizedFly.io staging Quarterly
Soakk6 soak test Before majorPhase releases1 launch Production-sizedFly.io staging Per release
ScalabilityInfrastructure changesProduction-sizedAs neededPre-launch

12. Results Analysis Template

Test Run ID: {{RUN_ID}} Date: {{DATE}} Tester: {{TESTER}}Builder Agent + Validator Agent Scenario: {{SCENARIO}}Load (normal) / Stress / Spike / Soak Build / Version: {{v{VERSION}}

Endpoint P50 (ms) P90 (ms) P95 (ms) P99 (ms) Error % RPS Status vs SLA
{{ENDPOINT}}/api/auth/login Pass / Fail
/api/transactions/remittancePass / Fail
DB SELECTPass / Fail

Summary:

  • Peak concurrent users: {{PEAK_USERS}}
  • Peak throughput: {{PEAK_RPS}} req/s
  • Test duration: {{DURATION}} min
  • Total requests: {{TOTAL_REQUESTS}}
  • Total errors: {{TOTAL_ERRORS}}

Notable findings:

  • SQLite concurrent user limit reached at: {{FINDING_1}}LIMIT} users
  • Recommend PostgreSQL migration at: {{FINDING_2}}
  • TRIGGER}
concurrent

Comparisonusers to(per baseline:

  • {{COMPARISON}}NFR-S02)

Recommendation: Pass / Fail / Conditional pass with {{CONDITIONS}}PostgreSQL migration required for Phase 1


13. Bottleneck Identification Process

Drop-specific bottleneck investigation order:

1. Check applicationbcrypt error ratetimingIsbcrypt the> app1,000ms returningP95 errors,= orconfig justissue slow?(rounds too high OR long password pre-check missing)
2. Check P99SQLite vswrite P50 spreadqueueLarge"database spreadis locked" errors = outlierconcurrent requestswrite (DBsaturation queries, locks,trigger GCPostgreSQL pauses)migration
3. Check CPUrate saturationlimiter DB table → rate_limit_requests table query slow = add index or migrate to Redis
4. Check transaction lock → SELECT FOR UPDATE timeout = deadlock in double-spend prevention
5. Check mock BaaS response → mock service timeout = CI/staging environment issue
6. Check Fly.io metrics → CPU > 80% sustained90% = computescale bottleneckup 4. Check memory →instance; Memory growing> during test200MB = Node.js leak / GC pressure
5. Check DB metrics → Slow queries, high connections, deadlocks
6. Check cache hit rate → Low cache hit = DB overloaded unnecessarily
7. Check external calls → Third-party API latency or rate limiting
8. Check network → Bandwidth saturation, packet losscheck

14. Remediation Tracking

Issue Found In Severity Root Cause Fix Fixed In Verified
{{ISSUE}}In-memory rate limiter reset on restart {{SCENARIO}}Phase 0 load test {{SEVERITY}}High {{CAUSE}}In-memory Map → DB-backed {{FIX}}Phase 0.5 security hardening {{VERSION}}v0.5.0 {{DATE}}db.test.ts
Long password bcrypt DoS (10KB)Phase 0 security auditHighNo max length before bcrypt1,000 char limit in validationv0.5.0validation.test.ts


Approval

Role Name Date Signature
Author John (AI Director) 2026-02-23 Approved (AI)
ReviewerQA Lead Validator Agent 2026-02-23 Approved (AI)
ApproverAI Director (John) John 2026-02-23Approved
CEO (Alem)Alem BašićTBD