Data Flow Document
Data Flow Document
Project: Drop{{PROJECT_NAME}}
Version: 1.0{{VERSION}}
Date: 2026-02-23{{DATE}}
Author: Petter Graff, Senior Enterprise Architect{{AUTHOR}}
Status: Draft | In Review | Approved
Reviewers: Alem Bašić (CEO), John (AI Director){{REVIEWERS}}
Classification: Public | Internal | Confidential | Restricted
Document History
| Version |
Date |
Author |
Changes |
| 0.1 |
2026-02-23{{DATE}} |
Petter Graff{{AUTHOR}} |
Initial draft from real architecture and schema docs |
1. Data Flow Overview
System: Drop Payment Platform (ALAI Holding AS){{SYSTEM_NAME}}
Data Owner: Alem Bašić, CEO — [email protected]{{DATA_OWNER_ROLE}}
DPO Contact: [email protected] (DPO designation TBD — required before production launch per GDPR Art. 37){{DPO_EMAIL}}
Overview: Drop processes personal, financial, and compliance data for Norwegian residents (18+) using a PSD2 pass-through model. Data enters from three surfaces: user registration (BankID OIDC), transaction initiation (web + mobile clients), and compliance webhooks (Sumsub KYC). Data is stored in 19 PostgreSQL tables, with sensitive fields (national ID, IBAN) hashed or encrypted. Data exits through the REST API (user-facing), PISP calls (payment rails), and regulatory reporting (Finanstilsynet, Okokrim).
Critical Architectural Principle: Drop never holds customer funds. bank_accounts.balance is a cached AISP read from the user's actual bank — not a Drop balance. No wallet, no top-up.{{DESCRIBE_WHAT_DATA_FLOWS_THROUGH_SYSTEM}}
High-Level Data Flow
flowchart LR
subgraph Inputs["Data Sources / Ingestion"]
BID["BankIDU[Users OIDC\n(Identity— +Web/App]
age)"]API_IN[External WEB["WebAPI]
App\n(Next.js)"]IMPORT[Bulk MOB["MobileImport]
App\n(Expo)"]
SUM["Sumsub Webhooks\n(KYC results)"]
OB["Open Banking AISP\n(Balance reads)"]WEBHOOK[Webhooks]
end
subgraph Processing["DropProcessing API Processing"]
AUTH["Auth Middleware\n(JWT verify, session check)"Layer"]
VAL["InputValidation Validation\n(validateName,& sanitizeText,\nvalidateAmount,Sanitization]
validatePhone)"]
BIZ["TRANS[Business Logic\n(FeeLogic calc,/ FX,Transformation]
disclosure,\nKYCENRICH[Data enforcement)"]
AUDIT["Audit + Compliance\n(audit_log, AML rules, STR)"]Enrichment]
end
subgraph Storage["DropStorage Database (PostgreSQL 16)"Layer"]
CORE["CoreDB[(Primary Domain\nusers, sessions,\ntransactions, bank_accounts,\nrecipients, merchants,\nnotifications, settings"DB\nPostgreSQL)]
COMPLIANCE["Compliance Domain\naudit_log, aml_alerts,\nstr_reports, screening_results,\nconsents, data_access_requests,\ncomplaints"CACHE[(Cache\nRedis)]
SYSTEM["System\nexchange_rates,BLOB[Object rate_limits,\ncardsStorage\nS3/Blob]
(future),SEARCH[Search spending_limitsIndex\nElasticsearch]
(future)"DW[Data Warehouse\n{{DW_TECH}}]
end
subgraph Outputs["EgressData Consumers / Data Consumers"Egress"]
API_OUT["REST API\n(WebAPI]
+REPORTS[Reports Mobile/ clients)"]Analytics]
PISP_OUT["OpenEXPORT[Data BankingExport]
PISP\n(PaymentTHIRD[Third-party initiationIntegrations]
toEMAIL[Email user's/ bank)"]
SEPA["SEPA/SWIFT\n(Remittance settlement)"]
REG["Regulatory Reporting\nFinanstilsynet + Okokrim (STR)"]
SENTRY["Sentry\n(Errors — PII masked)"]Notifications]
end
BIDU -->& AUTHAPI_IN & IMPORT & WEBHOOK --> VAL
--> BIZ
WEB & MOBVAL --> AUTHTRANS
SUMTRANS --> VALENRICH
OBENRICH --> COREDB BIZ& BLOB
DB --> CORECACHE & COMPLIANCESEARCH
& SYSTEM
BIZDB --> AUDITDW
AUDIT --> COMPLIANCE
COREDB --> API_OUT CORE& REPORTS & EXPORT
DW --> PISP_OUTREPORTS
ENRICH --> SEPATHIRD
COMPLIANCEDB --> REG
BIZ --> SENTRYEMAIL
2. Data Sources & Ingestion
| Source |
Type |
Protocol |
Volume (est. MVP)) |
Format |
PII? |
Validation |
BankID OIDC ID token |
Real-time (per login) |
HTTPS OIDC callback |
100-1000 logins/day |
JWT (signed) |
YES — pid, name |
JWKS signature + issuer + nonce + age >= 18 |
Web appapplication user actionsusers |
Real-time |
HTTPS POST |
500-5000 req/day |
JSON |
YES — IBAN, amount |
Schema validation + validateName/validateAmount |
Mobile app user actions |
Real-time |
HTTPS POST (Bearer) |
200-2000{{REQ_PER_DAY}} req/day |
JSON |
YES |
SameSchema as+ webbusiness rules |
SumsubMobile webhooksapp users |
Event-drivenReal-time |
HTTPS POST (inbound) |
10-100{{REQ_PER_DAY}} webhooks/req/day |
JSON |
YES — KYC result |
HMAC-SHA256Schema signature+ verificationbusiness rules |
Open{{EXTERNAL_SYSTEM}} Banking AISPAPI |
On-demand + scheduledReal-time |
HTTPS GETWebhooks |
4{{EVENTS_PER_DAY}} reads/account/events/day max |
JSON (Berlin Group) |
YES{{YES/NO}} |
—HMAC IBAN,signature balance+ schema |
| CSV bulk import |
Batch |
File upload |
{{IMPORTS_PER_DAY}} files/day |
CSV |
{{YES/NO}} |
Column mapping + row validation |
{{THIRD_PARTY_API}} |
Polling |
REST/HTTPS |
{{CALLS_PER_HOUR}}/hour |
JSON |
{{YES/NO}} |
Response schema validation + consent check |
Ingestion Error Handling
| Error Type |
Action |
Notification |
BankID signature invalid |
Reject — return jwks_verification_failed 502 |
Sentry HIGH alert |
Schema validation failure |
Reject — return 400 validation_error with fielderror details |
NoReturn alert400 (expected)to caller |
SumsubDuplicate HMAC mismatchrecord |
RejectUpsert —(prefer existing) or reject |
Log, return 401 |
Sentry HIGH alert — possible SUMSUB_SECRET_KEY rotation issue |
Open Banking consent expired |
Reject AISP call — prompt user to re-link |
In-app notification409 |
PII fieldfields withcontain unexpected formatdata |
Quarantine + alert |
Slack #{{CHANNEL}} |
| Import file corrupted |
Reject +entire log (masked)file |
SentryEmail MEDIUMuploader alert+ error report |
3.1 Ingestion Transformations (before storage)
3.2 ETL Pipeline (to Data Warehouse)
Drop
flowchart doesLR
notsubgraph haveExtract["Extract"]
a separate data warehouse or ETL pipeline at MVP scale. All analytics queries run directly against the PGLOG[PostgreSQL replicaWAL / CDC]
SCHED[Scheduled SQL Export]
end
subgraph Transform["Transform (when{{TRANSFORM_TOOL}})"]
available).CLEAN[Data ACleaning]
dataJOIN[Joins warehouse& isAggregations]
plannedDEDUP[Deduplication]
forANON[PII PhaseAnonymization]
3end
subgraph Load["Load"]
DW[({{DATA_WAREHOUSE}})]
end
PGLOG --> CLEAN
SCHED --> CLEAN
CLEAN --> JOIN
JOIN --> DEDUP
DEDUP --> ANON
ANON --> DW
Pipeline schedule: {{PIPELINE_SCHEDULE}} (10K+e.g., users).hourly incremental, daily full)
Latency: Source to DW within {{MAX_LATENCY}}
Tool: {{ETL_TOOL}} (e.g., dbt, Airbyte, custom)
4. Data Storage
| Storage System |
Technology |
Purpose |
Data Classification |
Encryption at Rest |
| Primary Database |
PostgreSQL{{DB_TECH}} 16 (AWS RDS){{VERSION}} |
All transactional and complianceTransactional data — 19 tables |
Restricted / Confidential |
AES-256 (RDS storage encryption, AWS-managed key){{KEY_MGMT}}) |
Development DatabaseCache |
SQLiteRedis 3 (/app/data/drop.db){{VERSION}} |
LocalHot devdata, only — no real PIIsessions |
Internal |
OS-level (developer machine)AES-256 |
SecretsObject Storage |
AWS Secrets Manager{{S3_COMPATIBLE}} |
JWT_SECRET,Files, BankIDdocuments, credentials, DB credentials, Sentry DSNmedia |
Critical{{CLASSIFICATION}} |
AES-256SSE-S3 (AWS/ KMS)SSE-KMS |
BackupsSearch Index |
RDSElasticsearch |
automatedFull-text backupssearch |
Internal |
TLS + snapshotsat-rest encryption |
| Data Warehouse |
{{DW}} |
Analytics, reporting |
Anonymized |
{{DW_ENCRYPTION}} |
| Backup Storage |
{{BACKUP_TECH}} |
Disaster recovery |
Restricted |
AES-256 (RDS) |
ErrorAudit Logs |
Sentry{{LOG_STORAGE}} |
ErrorCompliance events/ (PIIaudit masked)trail |
InternalRestricted |
Sentry'sImmutable, encryption |
App Logs |
AWS CloudWatch |
Request/response logs (PII excluded) |
Internal |
CloudWatch encryption |
Container images |
AWS ECR |
Docker images — no data, no secrets |
Internal |
ECR encryption at restencrypted |
5. Data Access Patterns
5.1 Read Patterns
| Consumer |
Data Accessed |
Frequency |
Access Method |
Caching |
Web app (GET /api/auth/me)application |
User profile, bank accounts, total balancesettings |
Per page loadrequest |
REST API |
Balance:Redis bank_accounts.balance_synced_at5min (6h staleness)TTL |
Web app (GET /v1/transactions)application |
Transaction{{ENTITY}} list (paginated) |
Per page load |
REST API (paginated, limit 20)paginated) |
NoCDN cache+ — real-time from DBRedis |
MobileReporting app (GET /v1/transactions)service |
TransactionAggregated listmetrics |
PerEvery page load1h |
RESTDW APIquery |
NoMaterialized cache |
Mobile app (GET /v1/recipients) |
Saved recipients |
Per send-money flow |
REST API |
No cache |
Web app (GET /v1/rates/:currency) |
Exchange rate |
Per amount-entry |
REST API |
Rate limited to 120/min — DB row readviews |
Admin (GET /api/admin/users)dashboard |
UserRaw list with KYC statusrecords |
On demand |
REST API (admin-only)admin) |
No cache |
| External partner |
{{SUBSET_OF_DATA}} |
{{FREQUENCY}} |
REST API (scoped JWT) |
{{CACHING}} |
5.2 Write Patterns
| Writer |
Data Written |
Frequency |
Write Method |
Consistency |
AuthUser moduleactions (BankID callback)web) |
users,CRUD sessions, audit_logoperations |
Per loginuser action |
AtomicREST DB transactionAPI |
Strong (synchronous) |
TransactionsBackground routeworker |
transactions,Aggregates, bank_accountscomputed (balance deduct), audit_log, notifications |
Per payment |
Atomic DB transaction |
Strong |
Sumsub webhook |
users.kyc_status, screening_results, audit_log, notifications |
Per KYC event |
Atomic DB transaction |
Strong (within Drop) |
Rate limit middleware |
rate_limits (count + reset_at)fields |
Every rate-limited request{{INTERVAL}} |
Direct DB write |
Eventual (cleanup every 100 calls) |
AISPImport balance syncprocess |
bank_accounts.balance,Bulk bank_accounts.balance_synced_atrecords |
Up{{FREQUENCY}} |
toBatch 4x/dayinsert |
Strong (per accountbatch) |
| Event consumer |
Denormalized cache |
On event |
Direct DB write |
Eventual (cached value) |
6. Data Retention & Archival
| Data Category |
Retention Period |
Legal Basis |
Action at Expiry |
Automated? |
| User account data |
Duration of relationship + 5{{N}} years |
Contract (Finansavtaleloven) |
Soft delete → anonymize (nullify PII fields) |
PlannedAutomated — (nightly jobjob) |
| Transaction records |
5{{N}} years |
Legal obligation (Hvitvaskingsloven § 22){{REGULATION}}) |
Archive to cold storage (planned) |
Planned |
AML alerts + STR reports |
5 years |
Legal obligation (Hvitvaskingsloven § 22) |
Retain — not deletable per AML law |
No (legal retention)Automated |
Audit logs (audit_log) |
5{{N}} years |
Legitimate interest (security + compliance)security) |
PurgeDelete |
PlannedAutomated |
Session tokens (sessions) |
7{{N}} hours/days max |
Technical necessity |
ExpiredAuto-expire expires_atvia rows pruned on loginTTL |
Yes (sessionRedis cleanup on login)TTL) |
GDPRMarketing consentsconsent |
Until consent withdrawn |
Consent (GDPR Art. 6(1)(a)) |
Delete within 30{{N}} days of withdrawal |
Manual + planned jobautomated |
KYCAnalytics screening resultsdata |
5{{N}} years |
Legal obligation |
Archive |
Planned |
Notifications |
90 days |
Legitimate interest (UX) |
Delete |
Planned |
Rate limit counters |
60 seconds (TTL = reset_at) |
Technical necessity |
Auto-cleaned every 100 calls |
Yes (middleware cleanup) |
Error logs (Sentry) |
90 daysanonymized) |
Legitimate interest |
Auto-purged by SentryDelete |
Yes (Sentry retention policy)Automated |
RDSBackup backupsfiles |
30{{N}} days (prod), 7 days (staging) |
Business continuity |
Overwrite (rolling) |
YesAutomated |
(RDS
automated)
| Error logs |
{{N}} days |
Legitimate interest |
Delete |
Automated |
AMLRetention Override:schedule job: GDPR Art. 17 (right to erasure) is overridden by Hvitvaskingsloven § 22retention-policy.job.ts — transactionruns anddaily KYCat data{{TIME}} mustUTC
beArchival retainedtarget: 5 years regardless of user erasure request. Drop implements soft delete + anonymization (nullify email, first_name, last_name, phone) while retaining financial and compliance records.{{COLD_STORAGE_LOCATION}}
7. Data Quality Rules
7.1 Validation Rules
| Field |
Rule |
Error Action |
Severity |
users.national_id_hashemail |
SHA-256Valid hexRFC string5322 (64 chars)format |
Reject login |
CRITICAL |
users.date_of_birthphone |
ISOE.164 date, age >= 18 yearsformat |
Reject |
loginHIGH |
{{DATE_FIELD}} |
Not in future |
Reject |
HIGH |
{{AMOUNT_FIELD}} |
>= 0 |
Reject |
CRITICAL |
transactions.amount{{FK_FIELD}} |
100References ≤existing amount ≤ 50000 (NOK)record |
Reject payment |
CRITICAL |
transactions.idempotency_key{{TEXT_FIELD}} |
UniqueMax (UNIQUE{{N}} index)characters |
Reject duplicate, return existing |
CRITICAL |
recipients.country |
One of: RS, BA, PL, PK, TR, EU |
Reject recipient creation |
HIGH |
bank_accounts.iban |
Valid IBAN format (application-layer check) |
Reject bank linking |
HIGH |
users.email |
Placeholder format [email protected] |
N/A (generated) |
LOW |
Input text fields (name, description) |
Sanitized (no HTML, max lengths per field) |
Reject with 422 |
MEDIUM |
7.2 Data Quality Metrics
| Metric |
Target |
Current |
Alert Threshold |
Null rate on users.national_id_hashrequired fields |
0% |
Any{{CURRENT}} |
occurrence> 0.1% |
TransactionDuplicate idempotency violations preventedrate |
100%< 0.01% |
Any{{CURRENT}} |
duplicate> slip-through0.1% |
KYC webhook HMACSchema validation pass rate |
100%> 99.9% |
{{CURRENT}} |
< 100% → alert ops99% |
AISPETL balancepipeline stalenesssuccess > 24h |
0%rate |
> 99.5% |
of{{CURRENT}} |
accounts< → alert98% |
8. PII Data Flow Mapping
8.1 PII Inventory
| PII Category |
Fields |
Storage Location |
Encrypted? |
Access Controls |
Lawful Basis |
NorwegianContact national IDinfo |
users.national_id_hashemail, phone, address |
PostgreSQLPrimary usersDB, tableEmail system |
SHA-256 one-way hashYes |
AuthRole-based middleware(user self + admin only |
Contract + Legal obligation |
Full name |
users.first_name, users.last_name |
PostgreSQL users table |
At-rest (RDS encryption) |
Auth middleware (own data) + adminadmin) |
Contract |
Date of birthIdentity |
users.full_name, date_of_birth |
PostgreSQLPrimary users tableDB |
At-restYes (field-level) |
Auth middleware (own data) + admin |
Contract + Legal obligation (age verification) |
Phone number |
users.phone |
PostgreSQL users table |
At-rest |
Own data + adminRole-based |
Contract |
IBAN / bank accountFinancial |
bank_accounts.iban, bank_accounts.account_number, recipients.bank_account{{PAYMENT_FIELD}} |
PostgreSQL{{PAYMENT_PROVIDER}} (tokenized) |
At-restTokenized |
OwnPCI datascope only (user_id FK enforced) |
Contract |
Cached bank balanceBehavioral |
bank_accounts.balancelogin_history, click_events |
PostgreSQLAnalytics DB |
At-rest |
Own data only |
ContractNo (AISP) |
IP address |
audit_log.ip_address, consents.ip_address, rate_limits.key |
PostgreSQL |
At-restanonymized) |
Admin only |
Legitimate interest (security) |
KYC documentsLocation |
Notip_address stored(→ by Dropgeo) |
SumsubLogs servers(masked) |
Sumsub handlesN/A |
Sumsub dashboardAdmin only |
LegalLegitimate obligationinterest |
| Device |
user_agent, device_id |
Analytics DB |
No |
Admin only |
Legitimate interest |
8.2 PII Flow Diagram
flowchart TD
USER([Norwegian Resident\nDataData Subject]) -->|"BankID OIDC\n(pid, name, birthdate)"|Provides| INGESTION[DropIngestion Auth Module]Layer]
INGESTION -->|"SHA-256(pid)Validates =& national_id_hash\nname → first/last_name\nbirthdate from pid"|encrypts| DB[(PostgreSQL\nusersPrimary table\DB\nPII encrypted at rest)]
DB -->|"OwnPseudonymized| profileDW[(Data only\n(JWT-gated)"|Warehouse\nNo API_OUT["RESTdirect API\n/api/auth/me"PII)]
DB -->|"national_id_hashMasked only\n(neverin rawlogs| pid)"|LOGS[Log AUDIT[audit_log]Aggregator]
USERDB -->|"DocumentTokenized| upload"|PAYMENT[Payment SUMSUB_SDK[SumsubProvider\nPCI SDKscope]
Widget]
SUMSUB_SDKDB -->|"ApplicantExplicit data\n+consent| documentEMAIL[Email images"|Provider\nEmail SUMSUB[(Sumsub+ Servers\nKYCname documentsonly]
stored)]
SUMSUBDB -->|"kyc_statusRight result\n(noto rawerasure| docDELETION[Anonymization data)"|Service]
DROP_WEBHOOK[Drop Webhook Handler]
DROP_WEBHOOKDELETION -->|"kyc_status update\nscreening_result"|Anonymized| DB
DB -->|"GDPRAudit Art.trail| 17AUDIT[Audit erasure\n(softLog\nRestricted delete + anonymize)"| ANONYMIZE[Anonymization\nNullify: email, first_name,\nlast_name, phone\nRetain: transactions, AML (5yr)]
ANONYMIZE --> DB
DB -->|"PISP: amount + IBAN\n(user's own bank)"| PISP_OUT["Open Banking PISP\n(Neonomics → ASPSP)"]
PISP_OUT -->|"Execute transfer"| BANK[(User's Bank\nmoney always here)]
DB -.->|"STR reports\n(hvitvaskingsloven)"| REG["Okokrim / EFE\n(Regulatory)"]access]
style DB fill:#ffcccc
style SUMSUBDW fill:#ccffcc
style LOGS fill:#ffffcc
style BANK fill:#ccffcc
style REGAUDIT fill:#ffcccc
9. Cross-Border Data Transfer
| Transfer |
From |
To |
Data Category |
Mechanism |
DPA Signed?DPA/SCCs? |
KYC applicant data{{TRANSFER_1}} |
NorwayEU (Drop){{COUNTRY}}) |
InternationalUS (Sumsub){{PROVIDER}}) |
Name, DOB, document images{{DATA_CATEGORY}} |
Standard Contractual Clauses (SCCs) |
TBDYes — requiredsigned before production{{DATE}} |
Error events{{TRANSFER_2}} |
Norway (Drop)EU |
USA (Sentry){{COUNTRY}} |
Error stack traces (PII masked){{DATA_CATEGORY}} |
StandardAdequacy Contractual Clauses (SCCs) |
Sentry DPA via ToS |
BankID auth |
Norway (user browser) |
Norway (BankID Norge) |
OIDC tokens, pid |
Norwegian entity — no cross-border transferdecision |
N/A |
Neonomics AISP/PISP{{TRANSFER_3}} |
Norway (Drop API)EU |
Norway/EEA (Neonomics){{COUNTRY}} |
IBAN, balance, payment data{{DATA_CATEGORY}} |
EEABinding entityCorporate — adequacyRules |
DPA required in contract{{YES/NO}} |
Third-party processors with data access:
| Processor |
Service |
Data Accessed |
DPA Signed |
Location |
Sumsub{{PROCESSOR_1}} |
KYC/AML verification{{SERVICE}} |
applicantId, external user ID, KYC result (documents stored by Sumsub, not Drop){{DATA}} |
RequiredYes |
International{{LOCATION}} |
Sentry{{PROCESSOR_2}} |
Error tracking{{SERVICE}} |
Error messages (PII must be masked before capture){{DATA}} |
Via Sentry ToS DPAYes |
USA (SCCs) |
AWS |
Cloud hosting |
All Drop data (encrypted at rest) |
AWS DPA |
eu-north-1 (Stockholm) — EEA |
Neonomics |
Open Banking aggregator |
IBAN, balance, payment details |
Required in commercial contract |
Norway / EEA{{LOCATION}} |
10. Data Lineage Tracking
Lineage tool: audit_log{{LINEAGE_TOOL}} table(e.g., —Apache customAtlas, implementationDataHub, custom)
Coverage: AllPrimary user-triggeredDB data+ mutations capturedDW
Lineage Events Captured
{
"id"eventType": "audit_<hex16>"DATA_WRITE",
"user_id"timestamp": "usr_abc123"ISO8601",
"actor": "system/user-id",
"action": "transaction.createCREATE | kyc.approvedUPDATE | session.createDELETE | ...EXPORT | IMPORT",
"resource": {
"type": "{{ENTITY}}",
"resource_type"id": "transactionUUID"
|},
user"fields_modified": | session | ...["{{field1}}", "resource_id"{{field2}}"],
"sourceSystem": "tx_abc123"{{SOURCE}}",
"ip_address"traceId": "192.168.1.1",
"created_at": "2026-02-23T10:00:00.000Z"UUID"
}
Actions tracked in audit_log:
session.create, session.revoke, session.revoke_all
transaction.create, transaction.status_update
kyc.initiated, kyc.approved, kyc.rejected
qr_payment.create
user.delete_account, user.data_export, user.data_export_request
complaint.create
bankid.login, bankid.callback_error
11. Backup & Recovery for Data
| Storage |
Backup Method |
Frequency |
Retention |
RTO |
RPO |
Test Frequency |
PostgreSQLPrimary (RDS prod)DB |
Continuous automatedWAL backups (PITR)archiving + daily snapshots |
Continuous / Daily |
30 days |
1 hour1h |
5 minutes5min |
Monthly |
PostgreSQLObject (RDS staging)Storage |
AutomatedCross-region backupsreplication |
DailyContinuous |
730 days |
2 hours4h |
24 hours1h |
Quarterly |
SQLiteData (dev)Warehouse |
Git-ignored; no backup (dev-only)Snapshot |
N/ADaily |
N/A14 days |
Rebuild from seed8h |
N/A24h |
N/AQuarterly |
SecretsRedis (Secrets Manager)Cache |
AWS-managedRDB replicationsnapshots |
ContinuousEvery 15min |
Indefinite (versioned)24h |
< 5 min (create new)15min |
N/A15min |
N/AMonthly |
PostgreSQL Point-in-Time Recovery:
aws rds restore-db-instance-to-point-in-time \
--source-db-instance-identifier drop-prod \
--target-db-instance-identifier drop-prod-restored \
--restore-time "2026-02-23T10:00:00Z"
Last backup test: TBD{{DATE}} — RequiredResult: before production launch{{PASS/FAIL}}
Recovery runbook: docs/dr-runbook.md{{LINK_TO_RUNBOOK}}
Approval
| Role |
Name |
Date |
Signature |
| Author |
Petter Graff |
2026-02-23 |
|
| Data Owner |
Alem Bašić (CEO) |
|
|
| DPO / Privacy |
TBD — required before production |
|
|
| Security |
|
|
|
| Tech Lead |
John (AI Director) |
|
|