DEV Community

Cover image for How Egyptian FRA Regulations Built Better FinTech Architecture
Khalid Elokiely
Khalid Elokiely

Posted on

How Egyptian FRA Regulations Built Better FinTech Architecture

When our team started building the backend for a licensed NBFI under Egyptian financial regulations, compliance felt like a list of things we couldn't do. We couldn't use a shared global deployment. We couldn't integrate a foreign KYC provider. We couldn't use a standard database table for financial records. What we discovered, six months into the build, is that every single constraint the FRA (Financial Regulatory Authority) imposed was pointing us toward an architecture we should have built anyway. This is that architecture.

Four Hard Constraints, One Architecture

The Egyptian Financial Regulatory Authority (FRA) frames a secure and sustainable fintech gateway as an integrated system with four constraints mentioned through two key regulatory decisions: 139/2023, 140/2023

  1. Your Data Doesn't Leave Egypt
  2. You Can't Buy Identity Off the Shelf (KYC)
  3. The Regulator Will Ask For Five Years of Proof
  4. An UPDATE Statement Is a Compliance Violation

Your Data Doesn't Leave Egypt

The FRA is explicit: hardware, database servers, application servers, and web servers must physically reside within Egypt's geographic borders. A shared global cloud deployment with no regional isolation strategy fails this requirement on day one.
The two realistic paths are a local data center provisioned through an Egyptian vendor, or a solution like AWS Outposts; which runs AWS-managed infrastructure on your premises, letting your team work with familiar tooling while satisfying the physical residency requirement. For Kubernetes specifically, the defensible pattern under audit is a dedicated cluster per regulatory zone, not just namespace isolation. Namespaces share underlying nodes; under a strict physical audit, that shared compute is a risk you don't want to defend.

You Can't Buy Identity Off the Shelf

FRA Decision 140/2023 explicitly states: identity verification must use the Egyptian National ID system — a document that is legally recognized across all financial and telecom records in Egypt — and the phone number must be registered under that same national ID.That last requirement might sound like administrative redundancy. It isn't.

The MFA framework defines three authentication categories.

  • Something you know: the PIN or password the user sets at registration.
  • Something you have: access to their registered phone number, email, or national ID document.
  • Something you are: the live biometric scan — the facial recognition and liveness check that confirms the person holding the ID is the person creating the account.

The FRA's requirement that the phone number link back to the national ID isn't a fourth step — it collapses the second and third categories into one verifiable chain. The phone number is registered to a national identity. The biometric confirms the identity is present and alive. There is no gap between "someone has this number" and "this person is who they claim to be."

From a development standpoint, the KYC interface must be swappable. KYC vendors design flows that create lock-in — proprietary SDKs, non-portable session tokens, verification states that live in their systems rather than yours. When terms change or quality drops, migration becomes a re-enrollment exercise for your entire user base.

The architectural answer is to treat KYC as a side effect, not a dependency. Your domain retains the artifacts of verification — the national ID hash, the verified phone number, the liveness result, the assigned trust tier, and the timestamp — in a normalized format that belongs to your system. A new provider receives these artifacts and resumes from the correct trust level. The user never re-verifies from scratch. This is not just good architecture; it is what Decision 140/2023 implicitly demands when it defines three distinct trust tiers that must persist across sessions and remain auditable for five years.

type KYCProvider interface {
    InitiateVerification(ctx context.Context, req VerificationRequest) (*Session, error)
    CheckStatus(ctx context.Context, sessionID string) (*VerificationResult, error)
    FetchArtifacts(ctx context.Context, sessionID string) (*KYCArtifacts, error)
}

type KYCArtifacts struct {
    NationalIDHash    string
    VerifiedPhone     string
    LivenessConfirmed bool
    TrustTier         TrustTier
    VerifiedAt        time.Time
}
Enter fullscreen mode Exit fullscreen mode

The implementation behind this interface is a detail. The artifacts it produces belong to your domain permanently

The Regulator Will Ask For Five Years of Proof

Decision 139/2023 mandates a security baseline that reads like a SOC2 checklist before your first engineer writes a line of application code: next-generation firewall, web application firewall, asset monitoring across all systems, security isolation between services by sensitivity level, annual penetration testing with submitted reports to the FRA, and unique session IDs with timestamps on every connection.

The hardest requirement to retrofit is also the most specific: all system logs, security logs, and application logs must be retained for no less than five years from the date of the event. Full transaction logs — every login, every logout, every financial operation — for the same period.

Five years is not a backup policy. It is a forensic requirement. The FRA is stating that five years from now, a regulator must be able to reconstruct exactly what happened in your system on any given day. That reconstruction is only possible if logging was part of your domain model from day one — not a middleware you added in sprint twelve.

The architectural consequence is straightforward: every domain event is a first-class record. Not a log line written to stdout. Not an entry in a monitoring dashboard that rotates after 90 days. A structured, timestamped, indexed record that lives in the same persistence tier as your business data, subject to the same retention guarantees. If your observability stack and your business data have different retention policies, you have already failed this requirement. The FRA does not distinguish between "application logs" and "transaction records" in its five-year mandate. Neither should your architecture.

An UPDATE Statement Is a Compliance Violation

Immutability in financial systems doesn't mean the data store throws an error when you try to edit a record. It means the system is designed so that editing a record is never the right operation — only appending a new one is.

// ImmutableLedger enforces append-only financial state.
// No entry is ever modified or deleted - only superseded.
type ImmutableLedger[T any, ID comparable] interface {
    // CreateEntry appends a new record to the ledger.
    // The rolling balance is computed from all prior entries
    // for this account — never stored as mutable state.
    CreateEntry(ctx context.Context, accountID ID, record T) error

    // ReverseEntry does not delete. It creates an equal and
    // opposite entry that cancels the effect of the original.
    // Both entries remain permanently visible in the audit trail.
    ReverseEntry(ctx context.Context, originalID ID, reason string) error

    // History returns the full, ordered, unmodified chain
    // of entries for an account. The current balance is the
    // sum of this chain — always derivable, never cached mutably.
    History(ctx context.Context, accountID ID) ([]T, error)
}

// Transaction is the canonical ledger entry.
// Once written, no field changes. Ever.
type Transaction struct {
    ID            string
    AccountNumber string
    FromAccount   string
    ToAccount     string
    Debit         decimal.Decimal
    Credit        decimal.Decimal
    RollingBalance decimal.Decimal // computed at write time, never updated
    Description   string
    CreatedAt     time.Time
    ReversalOf    *string // non-nil if this entry reverses a prior one
}
Enter fullscreen mode Exit fullscreen mode

Notice what's absent: there is no UpdateEntry. There is no DeleteEntry. These operations don't exist because they have no valid meaning in a financial ledger. A wrongly recorded transaction isn't corrected by overwriting it — it's corrected by recording the reversal. Both entries remain. The audit trail is complete. A regulator asking "what happened to this account on this date" gets a chain of immutable facts, not a current state that may have been edited twelve times since the event occurred.

The rolling balance is never stored as a mutable field that gets updated on each transaction. It is computed from the full chain of entries at write time and recorded as part of that entry. If you need the current balance, you read the most recent entry. If you need to audit, you read all of them. The source of truth is the chain — not any single record within it.

This is the pattern the FRA mandates when it states that digital records must carry "the evidentiary weight of official instruments" from the moment of their creation. An UPDATE statement issued after the fact destroys that evidentiary weight. An append-only ledger preserves it by design.

Formance is an open source financial core which implements this pattern at production scale — with multi-currency support, account hierarchies, and a query layer built specifically for financial audit — without requiring you to enforce these constraints manually across your codebase. The interface above describes the contract; Formance is one of the most elegant implementations of it available as open infrastructure today.

For a ledger like Formance, an append only immutable ledger API spans the following operations

# 1. Append a completely new, unchangeable transaction to the log
POST /api/ledger/main_ledger/transactions  {"script": {"plain": "send [EGP/2 100] (source = @users:001 destination = @merchant:checkout)"}}

# 2. Retrieve the full, permanent transaction history for an account
GET /api/ledger/main_ledger/accounts/users:001/transactions
Enter fullscreen mode Exit fullscreen mode

Regulation as Architecture: A Pattern That Travels

These patterns didn't originate with the FRA. They are the global consensus on what regulated financial infrastructure looks like. The pattern suggested by FRA regulations are actually more widespread and mandated internationally by all regulatory bodies across the EU and APAC.

FRA Constraint Architectural Pattern EU Equivalent APAC Equivalent
Data residency in Egypt Regional isolation GDPR Article 44 MAS TRM (Singapore)
Egyptian KYC providers only Pluggable provider interface PSD2 SCA RBI KYC (India)
5-year immutable logs Event sourcing / ledger SOX Section 802 HKMA record retention
Accounting always visible Double-entry ledger PSD2 audit trail MAS audit requirements

The FRA didn't hand our team a list of architectural best practices. It handed us a list of regulatory requirements. But when we mapped each requirement to its implementation, what emerged wasn't a compliance checklist — it was a backend that was genuinely harder to break, easier to audit, and more honest about what it was doing with user data.

Regional isolation because the law required it. Pluggable KYC because the law required it. Five-year event logs because the law required it. Append-only ledger because the law required it.

Every one of those decisions would have been the right call without the regulation. The regulation just made the conversation shorter.

If you're building financial infrastructure — in Egypt, in the EU, in Southeast Asia, anywhere a regulator has an opinion about where your data lives and how long you keep it — the constraints are not the obstacle. They are the specification. Build to them first, and the architecture takes care of itself.

Top comments (2)

Collapse
 
khalidelokiely profile image
Khalid Elokiely

Have you ever had to swap out an identity or KYC vendor mid-product? Did you treat it as a pluggable interface/side-effect like the Go snippet in the article, or did vendor lock-in force you into a painful user re-enrollment? Let me know your architectural horror stories or wins!

Collapse
 
khalidelokiely profile image
Khalid Elokiely

The other huge constraint is retention. How is your team handling high-volume, 5-year log compliance guarantees? Treating system and application logs as first-class, permanent records can get incredibly expensive as a startup scales. What data warehousing or long-term cold storage strategies have you used to keep these financial audits performant without breaking the bank?