DEV Community

Khalil Habib Shariff
Khalil Habib Shariff

Posted on

Rococo Supercharged Immutability, Time-Travel Debugging & Event-Driven Workflows

How Rococo Supercharged My Banking API: Immutability, Time-Travel Debugging & Event-Driven Workflows

When I started building a small banking API for learning purposes, I expected the hardest parts to be the API endpoints or the money transfer logic.

I was wrong.

The real challenge was data correctness over time.

If a customer deposits money, withdraws money, initiates a dispute, or reports that something went wrong earlier in the month, traditional CRUD becomes the enemy:

  • Updates erase history
  • Deletes destroy audit trails
  • Logs can’t rebuild financial state

In financial systems, data is not just data — it’s truth.

This is where Rococo, a Python versioning + event-sourcing framework, completely changed the game for me.


🧠 Why CRUD is a trap in banking

Imagine a basic workflow:


Start balance: $0
Deposit $100 → balance = $100
Withdraw $20 → balance = $80

Enter fullscreen mode Exit fullscreen mode

In traditional systems, the balance column gets overwritten twice.

So when a customer asks:

“What was my balance before I withdrew $20 on January 12?”

You can’t answer — because the previous state is gone.

With Rococo, every state transition becomes a new immutable version, creating a perfect historical timeline instead of destructive updates.


🔥 Rococo’s magic: Immutable Version Models

Here’s what my Account model looks like with Rococo:

@dataclass
class Account(VersionedModel):
    def deposit(self, amount: float, actor_id: str) -> 'Account':
        return replace(
            self,
            balance=self.balance + amount,
            changed_by_id=actor_id,
            changed_on=datetime.utcnow(),
            previous_version=self.version,
            version=str(uuid.uuid4())
        )
Enter fullscreen mode Exit fullscreen mode

Every deposit (or withdrawal) produces a brand-new version of the entity — nothing is overwritten.

This enables a superpower:

Time-travel debugging & dispute resolution

Calling:

GET /accounts/{account_id}/versions
Enter fullscreen mode Exit fullscreen mode

returns the entire lifetime of an account:

Version Balance Actor Timestamp
v1 $0 system 2024-01-01
v2 $100 user-123 2024-01-02
v3 $80 user-123 2024-01-03

Now when a user claims:

“My balance is wrong”

I don’t guess.
I show the exact historical truth.


🔒 Built-in audit trail — without writing custom audit code

Rococo automatically records:

  • previous version
  • new version
  • who made the change
  • when it happened

Here’s the kind of audit schema it creates:

id | entity_id | version | previous_version | balance | currency |
created_by_id | created_on | active
Enter fullscreen mode Exit fullscreen mode

I didn’t write any audit logic at all — Rococo handled everything.


⚡ Event-driven architecture with zero friction

The next killer feature: auto-publishing events when an entity changes.

self.repo = BaseRepository(
    adapter=self.adapter,
    model=Account,
    message_adapter=self.message_adapter,
    queue_name="account_events"
)
Enter fullscreen mode Exit fullscreen mode

Now every account update generates a message on the event bus (RabbitMQ, SQS, etc.)

This allowed my system to:

  • trigger fraud detection workflows
  • sync account balances to analytics
  • push updates to the frontend in real-time
  • track money movement in parallel systems without polling

Event-driven UX with almost no extra code.


🧩 System Architecture of the Project

FastAPI  ⟶  Service Layer  ⟶  Rococo Repository  ⟶ PostgreSQL
                                             ⟶ Audit Table
                                             ⟶ Event Bus
Enter fullscreen mode Exit fullscreen mode

Frontend stack: Vue 3
Backend stack: FastAPI + Rococo
Database: PostgreSQL

🔗 GitHub Repository: https://github.com/Khaleelhabeeb/banking_ledger
🔗 Live Demo: https://bankingledger.vercel.app


🏁 Final Thoughts

Rococo didn’t just make my banking API work
it made it correct, traceable, and auditable.

Without extra effort, I gained:

  • Zero-loss history of data
  • Permanent audit trail
  • Time-travel debugging
  • Event sourcing with minimal complexity

If you’re working in a domain where truth and history matter more than speed, Rococo deserves a spot in your toolbox.


💬 Want to chat?

I’m actively experimenting with Rococo and plan to build more adapters (DynamoDB next 👀).

If you’re working with Rococo, event-driven architectures, or just enjoy these concepts — I’d love to connect.

Thanks for reading! 🙌

Top comments (0)