Non‐Functional Requirements Demo 4 - COS301-SE-2026/Mealchemy GitHub Wiki

3.1.5 Non-Functional Requirements

The Demo 3 quality requirements are grouped under Performance, Scalability, Security, Reliability and Availability, and Maintainability. Each requirement is quantified and mapped to an architectural tactic, an executable test, and a recorded result.

QR1: Performance

QR1.1 Supported-load performance

Quantified requirement Architectural tactic Executable test Target Actual result Verdict
Non-recommendation read endpoints support a 10-user baseline and a 20-user peak for 5 minutes each. Region co-location, connection pooling, stateless backend k6 constant-VU performance test and comparison script Both runs: p95 <= 2 s and error rate < 1%. Peak throughput >= 1.8x baseline. Baseline: p95 368.382 ms, 0% errors, 6.965 requests/s. Peak: p95 522.876 ms, 0% errors, 13.103 requests/s. Throughput ratio: 1.881x. Met

How the test works

The k6 test signs in once, starts a fixed number of virtual users, and rotates their authenticated requests through vaults, pantry, shopping lists, and recipes. Only these read requests are measured. The comparison script reads the sanitized 10-user and 20-user result files and checks both latency and error targets before calculating the throughput ratio.

Why these measures and targets were chosen

The 10-user run represents the normal baseline and the 20-user run represents the expected peak for the supported deployment. Five minutes measures sustained behavior instead of a short traffic burst.

p95 latency is the time within which 95% of measured requests finish. The 2-second target sets the longest acceptable wait for nearly all supported-load requests without allowing a few extreme requests to define the result. The recorded values mean that 95% of baseline requests finished within 368.382 ms and 95% of peak requests finished within 522.876 ms.

An error rate below 1% requires more than 99 of every 100 requests to succeed. Both runs recorded 0% errors. Throughput is the average number of completed requests per second. Doubling users should produce close to double the completed work, so the minimum ratio is 1.8x, allowing 10% scaling overhead. The measured ratio of 1.881x means throughput increased by 88.1%, from 6.965 to 13.103 requests per second.

QR2: Scalability

QR2.1 High-load resilience

Quantified requirement Architectural tactic Executable test Target Actual result Verdict
Non-recommendation read endpoints remain available for 100 concurrent users for 5 minutes without a service crash or manual recovery. Cloud Run autoscaling, stateless backend, managed restart k6 constant-VU resilience test At least 99% successful responses; no service crash; no manual recovery. Latency is observed, not thresholded. 99.934% successful responses; 19,603 passed checks and 13 failed checks. The run completed without a service crash or manual recovery. Observed p95 latency: 903.709 ms. Met

Latency increases at high load because the deployment is capped at three Cloud Run instances for cost control.

How the test works

The resilience profile starts 100 constant virtual users for 5 minutes. Each user performs the same four authenticated read operations with one second of pacing. The test checks the successful-response rate and records latency without applying the 2-second performance threshold.

Why these measures and targets were chosen

One hundred users is five times the supported 20-user peak, so this test measures resilience beyond normal operating load. The 99% success target allows at most one failed response per 100 while still requiring the service to remain usable. The measured 99.934% success rate means only 0.066% of checks failed.

No latency threshold is applied because this test measures continued service, not supported-load speed. The observed p95 of 903.709 ms records the degradation for comparison while keeping it separate from the QR1 performance claim. Completing the full run without a crash or manual recovery shows that the service remained operational under the higher load.

Stress-test observation

The paced 1,000-user recipe storage and retrieval test completed with no failed operations. Observed p95 latency was 16.603 s for storage and 15.239 s for retrieval. This is a stress-test observation and is not used as evidence for the supported-load latency target.

Each virtual user creates one temporary private recipe, repeatedly retrieves that recipe, and removes the test data during cleanup. Startup is spread over 240 seconds to avoid sending all creation requests at once.

QR3: Security

ID Quantified requirement Architectural tactic Executable test Target Actual result Verdict
QR3.1 Protected endpoints reject missing and invalid tokens. JWT filter and deny-by-default authorization rules k6 authorization matrix 100% of authorization checks pass. 154 of 154 checks passed; 0 authorization failures. Met
QR3.2 Authenticated users cannot access data owned by another user. Ownership checks in the service layer Backend service and integration tests 100% of ownership tests pass. 109 ownership tests passed. Met
QR3.3 No secrets are committed to the repository. CI secret scanning Gitleaks 0 verified secrets Latest recorded result: 0 findings. Met
QR3.4 Backend and engine container images contain no known high or critical vulnerabilities. Dependency and container-image scanning Trivy 0 high or critical findings Latest recorded result: 0 findings. Met
QR3.5 The public and authenticated staging API contain no unresolved medium, high, or critical security findings. Input validation, security headers, limited exposure ZAP GET-only public and authenticated API scan 0 unresolved medium, high, or critical findings 0 unresolved medium, high, or critical findings. Met

How the tests work

Test Method
Authorization matrix Sends requests without a token and with an invalid token to every protected route. Each request must return HTTP 401 or 403. A smaller valid-token control set must return HTTP 200.
Ownership tests Use authenticated requests and service calls to attempt access to another user's data. The service must reject each attempt and integration tests must expose the rejection as HTTP 403.
Gitleaks Scans the repository history during CI and fails when a verified credential or secret is detected.
Trivy Scans the built backend and recommendation-engine container images during CI and fails on any high or critical vulnerability.
ZAP Builds GET-only public and authenticated scan definitions from the staging OpenAPI document. The evaluator combines both reports, removes sensitive data, and fails if any unresolved medium-or-higher finding remains.

Why these measures and targets were chosen

Authorization and ownership use a 100% target because one incorrectly exposed protected route can disclose or change another user's data. The 154 of 154 authorization checks show that every tested missing-token, invalid-token, and valid-token case produced its expected result. The 109 ownership tests cover the rule that authenticated users may access only their own data.

Secret, container, and API security targets are zero because a single verified secret, high or critical container vulnerability, or unresolved medium-or-higher API finding creates a release risk. Gitleaks and Trivy recorded zero findings.

QR4: Reliability and Availability

ID Quantified requirement Architectural tactic Executable test Target Actual result Verdict
QR4.1 The production API remains available on demo day and after a reasonable period after demo day (keeping within free-tier cost contraints). Health checks, managed restart, external monitoring UptimeRobot keyword monitor >= 99.9% availability Latest recorded monitored availability: 99.97%. Met
QR4.2 After one successful synchronization, recipes, vaults, pantry items, and shopping lists remain readable when the backend is unreachable or the token has expired. Viewer-scoped SQLite cache, repository fallback, persisted viewer identity Flutter repository and integration tests 4 of 4 supported collections remain readable; 0 failed cached reads Passing cache tests cover all 4 supported collections. Met
QR4.3 Offline operation does not permit writes or expose another user's cached data. Read-only offline state, mutation interceptor, viewer-scoped composite cache keys Flutter widget, repository, mutation-interceptor, and cache-isolation tests 0 enabled offline mutations; 0 cross-user reads Passing tests reject offline mutations before HTTP and keep cache records isolated by viewer. Met

How the tests work

Test Method
Availability monitor UptimeRobot calls the production health endpoint every 5 minutes. A check passes only when the response contains "status":"UP"; availability is calculated over the required 30-day period.
Offline cached reads Repository tests first store successful online responses for recipes, vaults, pantry items, and shopping lists. They then simulate an unavailable backend and verify that each repository returns data from the active viewer's cache.
Offline safety Mutation-interceptor tests verify that writes are rejected before reaching the HTTP adapter. Cache tests store matching record IDs for different viewers and verify that each viewer can read only their own records.

Why these measures and targets were chosen

The 99.9% availability target permits no more than about 43 minutes of downtime in a 30-day period. An exact 30-day window makes repeated results comparable. The recorded 99.57% is 0.33 percentage points below the target, so it is marked Not met.

The engine test uses 20 requests to show that fallback behavior is repeatable rather than a single successful case. The 3-second limit prevents an unavailable dependency from leaving the user waiting, and zero unhandled HTTP 500 responses requires every failure to be controlled.

The offline-read target is 4 of 4 because recipes, vaults, pantry items, and shopping lists are the four collections promised for offline use. Offline writes and cross-user reads both have a target of zero because either result could corrupt data or expose another user's personal information.

QR5: Maintainability

ID Quantified requirement Architectural tactic Executable test Target Actual result Verdict
QR5.1 Backend application logic maintains automated test coverage. Controller-service-repository layering and dependency injection JaCoCo in CI >= 80% coverage 97% backend coverage Met
QR5.2 Frontend application logic maintains automated test coverage. Repository abstractions and provider overrides Flutter test with lcov in CI >= 80% line coverage 88% frontend coverage Met

How the tests work

Test Method
Backend coverage Maven runs the backend tests and JaCoCo measures application instructions, branches, and methods. CI fails if any enforced coverage measure falls below 80%.
Frontend coverage Flutter runs the automated test suite with lcov. Generated files are removed from the report before CI checks that line coverage is at least 80%.
Accessibility guidelines Static-Landing page, Brand-guide, User Manual scaned with Google Lighthouse's accessibility tool.

Why these measures and targets were chosen

The 80% coverage threshold is the enforced project baseline for both backend and frontend application logic. It is high enough to require broad automated testing while allowing exclusions for generated files and classes with no application logic. The recorded 97% backend and 88% frontend values are the portions of measured code covered by the automated tests; they are not test pass rates.

NFR Test Evidence within the Repo under nfr-tests/

Evidence Location
Supported-load test nfr-tests/performance/non-recommendation-load.js
Supported-load comparison nfr-tests/performance/compare-results.js
10-user baseline result nfr-tests/results/performance-baseline-10vu.json
20-user peak result nfr-tests/results/performance-peak-20vu.json
Performance comparison result nfr-tests/results/performance-comparison.json
100-user resilience result nfr-tests/results/resilience-100vu.json
Authorization test nfr-tests/security/authorization-matrix.js
Authorization result nfr-tests/results/authorization-matrix.json
Recipe concurrency test nfr-tests/performance/recipe-concurrency-load.js
1,000-user paced result nfr-tests/results/recipe-concurrency-1000vu-paced.json
ZAP preparation and evaluation tools nfr-tests/security/zap/

Screenshot evidence can be found in Mealchemy/diagrams/NFR-Screenshots.pdf


Last updated: 30 September 2026