Skip to main content

Acceptance Criteria

Acceptance Criteria: {{PROJECT_NAME}}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 draftAC based on integration tests and E2E test suite

1. Purpose & Methodology

1.1 What Are Acceptance Criteria?

Acceptance criteria aredefine the conditions thatunder awhich systemDrop mustfeatures satisfyare toconsidered bedone and accepted by athe stakeholder.business. They answer the question:answer: "How will we know when this feature is done?"

Good acceptance criteria are:

  • Testable — Can be verified with a specific test procedure
  • Clear — Unambiguous; no room for interpretation
  • Complete — Cover happy path, error paths, and edge cases
  • Agreed — Signed off by the business BEFORE development begins

1.2 Format: Given / When / Then (Gherkin-Style)

Given [an initial context / precondition that is true]precondition]
When  [an action or event occurs]
Then  [the expected outcome is observed]
And   [additional expectedchained outcomes, chained]

Example — User Login:

Given a registered user with valid credentials
When the user submits the login form
Then the user is redirected to the dashboard
And a session token is created and stored in a secure cookie
And the last login timestamp is updated in the databaseoutcomes]

1.3 Categories of Acceptance Criteria

Category DescriptionExample
Positive (Happy Path) System works as expected with valid inputsSuccessful login
Negative (Sad Path) System handles invalid inputs gracefully Wrong password error
Edge Case Boundary conditions and unusual but valid scenariosLogin at exact session timeout
IntegrationSecurity SystemInjection, worksauth, correctlyabuse with external servicesPayment processed via Stripeprevention
Non-FunctionalCompliance Performance,Regulatory accessibility, security criteriaPage loads in < 2 seconds
DataCorrect data storage, retrieval, and validationFields saved with correct typesrequirements

2. Feature Acceptance Criteria


Module: {{MODULE_1_NAME}}Authentication & Onboarding


Feature: {{FEATURE_1_NAME}}User Registration — 3-step Onboarding (FR-{{XXX}})001)

Feature Description: {{BRIEF_DESCRIPTION}}New residents register via email + DOB validation → OTP → PIN. BankID replaces DOB in Phase 2. Business Requirement: BR-{{XXX}}001, BR-002 Linked User Stories: US-{{XXX}}, US-{{XXX}}001

Positive Scenarios:

# Scenario Given When Then
AC-001 {{SCENARIO_NAME}}Successful registration {{PRECONDITION}}Valid email, password ≥8 chars, Norwegian phone (+47), DOB ≥18 years {{ACTION}}User submits registration form {{EXPECTED_RESULT}}201 created; user proceeds to OTP step; no password hash in response
AC-002 OTP verification passes Account created; OTP sent to phone User enters correct 6-digit OTP User proceeds to PIN setup
AC-003PIN setup completesOTP verifiedUser enters and confirms 4-digit PINAccount activated; JWT cookie set; redirect to dashboard

Negative Scenarios:

# Scenario Given When Then
AC-003004 {{INVALID_INPUT_SCENARIO}}Under-18 rejected {{PRECONDITION_WITH_BAD_DATA}}DOB indicating age < 18 {{ACTION}}User submits registration {{ERROR_MESSAGE_OR_BEHAVIOR}}422 with message "Du må være minst 18 år"
AC-004005 Duplicate email Existing account for email User submits same email 409 "Email already in use"
AC-006Missing required fieldRegistration formUser submits without first_name422 validation error with field details array
AC-007Short passwordPassword < 8 charactersUser submits422 "Password must be at least 8 characters"
AC-008Invalid phone formatNon-+47 phone numberUser submits422 validation error

Edge Cases:

# Scenario Given When Then
AC-005009 {{BOUNDARY_CONDITION}}Boundary age (exactly 18) {{EDGE_CONDITION}}DOB = today minus 18 years exactly {{ACTION}}Registration submitted {{EXPECTED_RESULT}}Account created successfully
AC-010Invalid JSON bodyMalformed JSON in requestPOST /api/auth/register400 "Invalid JSON body"

Non-FunctionalSecurity Acceptance Criteria:

# Category Criterion
AC-006PerformanceFeature completes in < {{X}} seconds under normal load
AC-007AccessibilityFeature is fully operable by keyboard; ARIA labels present
AC-008Security{{SECURITY_CRITERION_IF_APPLICABLE}}

Feature: User Registration (FR-020)

Feature Description: New users can create accounts using email and password. Business Requirement: BR-{{XXX}} Linked User Stories: US-{{XXX}}

Positive Scenarios:

returnedAPIstarts
#ScenarioGivenWhenThen
AC-010Successful registrationA user visits /register with a valid, unregistered emailUser submits form with valid email, strong password, and required fieldsAccount is created; confirmation email sent; user redirected to email verification page
AC-011 Email verification sentAuth AccountPassword washash justnot created Systemin processesany registration Verification email arrives within 2 minutes with unique, expiring linkresponse
AC-012 Verification link worksAuth Userbcrypt receivesused verification(hash email Userwith clicks$2); verificationSHA-256 linkEmail verified; user redirected to login; account marked as verifiedrejected

Negative Scenarios:

min
#ScenarioGivenWhenThen
AC-013 DuplicateRate emaillimiting An10+ accountregistrations alreadyfrom existssame with [email protected]User submits registration with [email protected]Error "An account with this email already exists" shown; no new account created
AC-014Weak passwordUser is on registration formUser submits password "abc123"Inline error shown: "Password must be at least 8 characters and include uppercase, number, and special character"
AC-015Invalid email formatUser is on registration formUser submits "notanemail"IP in email1 field Inline validation error shown before form submission
AC-016Empty required fieldUser is on registration formUser submits with required field emptyInline error shown; form not submitted

Edge Cases:

#ScenarioGivenWhenThen
AC-017Email with plus addressingUser submits [email protected]Registration submittedAccount created; treated as valid email
AC-018Verification link expiryVerification link generated 25+ hours agoUser clicks expired linkError "Verification link has expired"; option to resend verification email shown
AC-019Double registration attemptUser submits form; due to slow network submits twiceTwo identical POST requests sentOnly one account created; second request returns appropriate error429

Feature: User Login (FR-021)002)

Business Requirement: BR-001 Linked User Stories: US-002

Positive Scenarios:

# Scenario Given When Then
AC-020 Successful login A verifiedRegistered user with valid credentials UserPOST submits /api/auth/login form Authenticated;200; redirectedJWT toin dashboard;httpOnly sessioncookie; createduser object returned
AC-021 RememberAuthenticated route accessValid JWT cookieGET /api/auth/me A200; verifiedcurrent user checksobject "Remember Me"User submits login formSession persists for 30 days; user stays logged in after browser closereturned

Negative Scenarios:

# Scenario Given When Then
AC-022 Wrong password A registeredRegistered user exists User submitsSubmits incorrect password Generic error401 "Invalid email or password" (no enumeration); login not granted
AC-023 Non-existent email No account forwith thisthat email UserLogin submits loginsubmitted Same generic error401 "Invalid email or password" (preventsame usererror — no enumeration)
AC-024 AccountRate lockedlimiting User10+ has made 5 failedlogin attempts from same IP in 1 minute UserNext attempts login againattempt Message:429 rate limit response
AC-025Missing credentialsEmpty email or passwordLogin submitted400 "AccountEmail temporarilyand locked.password Try again in 15 minutes."required"

Edge Cases:

# Scenario Given When Then
AC-025Session expiryUser has been idle for 31 minutesUser attempts to navigateRedirected to login; session cleared; unsaved work warning shown
AC-026 LoginInvalid on unverified accountJSON AccountMalformed created but email not verifiedbody UserPOST attempts to log in/api/auth/login Error400 "PleaseInvalid verifyJSON your email before logging in" with option to resendbody"

Module: Remittance (Send Money)


Feature: {{NEXT_FEATURE_NAME}}Remittance Transaction (FR-{{XXX}})020)

Business Requirement: BR-003, BR-005 Linked User Stories: US-010

Positive Scenarios:

# Scenario Given When Then
AC-{{NEXT}}030 Successful remittance Authenticated + KYC-approved user; valid recipient; sufficient balance POST /api/transactions/remittance with amount=1000, currency=RSD 201; transaction created; fee = 5 NOK (0.5%); transaction in history
AC-031Fee calculation correctAmount = 2000 NOKRemittance submittedfee = 10 NOK; recipient_amount = 2000 NOK (gross)
AC-032Transaction in historySuccessful remittanceGET /api/transactionsTransaction appears with status=completed

Negative Scenarios:

# Scenario Given When Then
AC-{{NEXT}}033 Unauthenticated user No JWT cookie POST /api/transactions/remittance 401 Unauthorized
AC-034KYC not approvedkyc_status=pendingRemittance submitted403 "KYC verification required"
AC-035Recipient not foundInvalid recipientIdRemittance submitted404 "Recipient not found"
AC-036Insufficient balanceBalance < (amount + fee)Remittance submitted402 "Insufficient balance"
AC-037Amount below minimumamount = 99 NOKSubmitted400 "Amount must be between 100 and 50000 NOK"
AC-038Amount above maximumamount = 50001 NOKSubmitted400 validation error
AC-039Invalid amount (NaN)amount = "abc"Submitted400 "Invalid amount"

EdgeCompliance Cases:Criteria:

#CategoryCriterion
AC-040AMLTransaction > 50,000 NOK rejected; daily limits enforced
AC-041Pass-throughNo balance column in users table; DB test verifies absence

Feature: Exchange Rates API (FR-021)

Positive Scenarios:

# Scenario Given When Then
AC-{{NEXT}}050 All rates returned GET /api/rates Called 6 NOK exchange rates returned (RSD, BAM, PKR, TRY, PLN, EUR)
AC-051Single rate returnedGET /api/rates/RSDCalledNOK→RSD rate returned
AC-052Case insensitiveGET /api/rates/rsd (lowercase)CalledSame result as /api/rates/RSD

Negative Scenarios:

#ScenarioGivenWhenThen
AC-053Unsupported currencyGET /api/rates/XXXCalled404 Not Found

Module: QR Payments


Feature: QR Payment — Consumer (FR-030)

Business Requirement: BR-004, BR-005 Linked User Stories: US-020

Positive Scenarios:

#ScenarioGivenWhenThen
AC-060Successful QR paymentAuthenticated + KYC-approved user; valid merchantId; sufficient balancePOST /api/transactions/qr-payment with amount=129, merchantId=valid201; merchant_fee = 1.29 NOK (1%); transaction created
AC-061Fee calculationamount = 200 NOKQR payment submittedmerchant_fee = 2 NOK (1%)

Negative Scenarios:

#ScenarioGivenWhenThen
AC-062Invalid merchantNon-existent merchantIdPayment submitted404 "Merchant not found"
AC-063Amount < 1 NOKamount = 0Submitted400 validation error
AC-064Missing merchantIdNo merchantId in bodySubmitted400 "Merchant ID is required"
AC-065UnauthenticatedNo JWTSubmitted401 Unauthorized

Feature: Merchant Registration + QR Generation (FR-031)

Positive Scenarios:

#ScenarioGivenWhenThen
AC-070Merchant registeredAuthenticated userPOST /api/merchants with business_name, bank_accountMerchant created with unique QR code value
AC-071QR code retrievableRegistered merchantGET /api/merchants/meMerchant details + QR code returned

Module: Security (Cross-cutting)


Feature: Input Validation (FR-001 through FR-080, all)

#ScenarioGivenWhenThen
AC-080XSS in name field<script>alert(1)</script> as firstNameRegistration submitted422 validation error; no script executed
AC-081SQL injection in email'; DROP TABLE users;-- as emailRegistration submitted422 validation error; no DB mutation
AC-08210KB password10,000 character passwordRegistration submitted422 "Password too long" or validation error
AC-083Unicode in nameBosnian chars (š, đ, ć, č, ž) in nameRegistration submitted201 created; name stored correctly
AC-084Underage DOBDOB indicating 17 years oldRegistration submitted422 age validation error

Module: Compliance


Feature: PCI-DSS Card Data Protection (FR-080, Cards feature)

#ScenarioGivenWhenThen
AC-090No CVV in DBCards tableDB schema checkcards table has NO card_number or cvv columns
AC-091No balance in usersUsers tableDB schema checkusers table has NO balance column (pass-through model)
AC-092Only last_four returnedAuthenticated userGET /api/cards/[id]Response contains last_four only; no full card number

3. Integration Scenarios

in
# Integration Scenario Expected Behavior Test Environment
INT-001 {{EXTERNAL_SERVICE}}Sumsub KYC {{SCENARIO}}KYC webhook callback (approved) {{EXPECTED}}User kyc_status updated to 'approved' SandboxMock /webhook Mockin integration tests
INT-002 EmailBaaS providerPISP TransactionalPayment email deliveryinitiation EmailTransaction receivedrecorded; withinconfirmation 2 minutesreturned MailtrapMock /PISP stagingin NEXT_PUBLIC_SERVICE_MODE=mock
INT-003 {{PAYMENT_PROVIDER}}BaaS AISP SuccessfulBalance paymentread from bank TransactionUser recorded;account confirmationbalance shown;returned webhookfrom receivedBaaS StripeMock testAISP modeservice
INT-004 {{PAYMENT_PROVIDER}}Exchange rates PaymentRate declineddata missing UserError seeshandled friendlygracefully; error;GET no/api/rates/XXX order created; no double-charge404 StripeIntegration test mode
INT-005 {{THIRD_PARTY_API}}BaaS unavailable BaaS API timeoutdown System shows user-friendly error; requesttransaction logged;not no data corruptioncreated Mocked timeout
INT-006{{THIRD_PARTY_API}}API unavailableSystem degrades gracefully; non-dependent features still workService unavailable mocktests

4. Non-Functional Acceptance Criteria

4.1 Performance

# Criterion Target Test Method
NF-AC-001 Allbcrypt pages load within targethashing time < 3s initial, < 1.5s subsequent1,000ms Lighthouse on stagingapi-benchmarks.test.ts
NF-AC-002 AllRate APIlimit endpointscheck respond within targettime < 500ms at p95 under normal load50ms k6 load testapi-benchmarks.test.ts
NF-AC-003 CoreDB WebSELECT Vitals passquery LCP < 2.5s, CLS < 0.1, FCP < 1.8s10ms Lighthouseapi-benchmarks.test.ts
NF-AC-004DB INSERT query< 20msapi-benchmarks.test.ts
NF-AC-00550 concurrent rate limit calls< 2,000ms totalapi-benchmarks.test.ts

4.2 AccessibilitySecurity

checker
# Criterion Target Test Method
NF-AC-010 NoSHA-256 criticalpasswords accessibility violationsrejected 0verifyPassword criticalreturns violationsfalse for SHA-256 hashes axe-core automated scanauth.test.ts
NF-AC-011 KeyboardJWT navigationtampered completetokens rejected AllInvalid featuressignature operable without mouseexception Manual testauth.test.ts
NF-AC-012 ColorRate contrastlimiting compliantblocks after limit 11th 4.5:1request text/backgroundfrom same IP → 429 Contrastmiddleware.test.ts
NF-AC-013Input validation completeness10+ validation test cases passvalidation.test.ts
NF-AC-014Foreign key constraints enabledSessions cannot be created for non-existent usersdb.test.ts

4.3 SecurityCompliance

# Criterion Target Test Method
NF-AC-020 No OWASPbalance Topcolumn 10in vulnerabilitiesusers table 0users critical/hightable findingsschema has no 'balance' OWASP ZAP scandb.test.ts
NF-AC-021 AllNo usercard_number/cvv inputsin sanitizedcards table Nocards XSS/injectiontable vulnerabilitieshas no 'card_number' or 'cvv' SAST + manual testingdb.test.ts
NF-AC-022 NoTransaction sensitivetypes data in client-side codelimited NoOnly API'remittance' keys,and tokens'qr_payment' in browseraccepted Code review + browser DevToolsdb.test.ts

5. UAT Scenario Mapping

AC ID AC Description UAT Scenario ID UAT TesterStatusPriority
AC-010001 Successful registration UAT-001 {{TESTER}}Not StartedCritical
AC-011004 EmailUnder-18 verification sentrejected UAT-002 Critical
AC-020 Successful login UAT-003 Critical
INT-003AC-030 PaymentSuccessful successremittance UAT-010 Critical
NF-AC-060Successful QR paymentUAT-020Critical
AC-090No CVV in DBUAT-SEC-001 Page load performanceUAT-P01Critical

6. Traceability to Requirements

AC ID Acceptance Criterion FR Reference BR Reference US Reference
AC-001 {{CRITERION}}Successful registration FR-{{XXX}}001 BR-{{XXX}}001 US-{{XXX}}001
AC-010004Under-18 rejectedFR-001BR-002US-001
AC-020 Successful registrationloginFR-002BR-001US-002
AC-030Successful remittance FR-020 BR-{{XXX}}003, BR-005 US-{{XXX}}010
AC-060Successful QR paymentFR-030BR-004, BR-005US-020
AC-090No CVV in DBFR-080BR-005, RUL-010
NF-AC-020No balance columnFR-001BR-005, RUL-003US-001

Full traceability:traceability matrix: [requirements-traceability-matrix.md](requirements-traceability-matrix.md)


Approval

Approved
Role Name Date Signature
Author John (AI Director) 2026-02-23 Approved (AI)
ReviewerQA Engineer Validator agent 2026-02-23
Business Analyst(AI)
Product Owner John 2026-02-23
QA EngineerApproved
AI Director (John) John 2026-02-23 Approved
ClientCEO Representative(Alem) Alem Bašić TBD