SharedLedger Journey Part 1: From Zero to Phoenix

posted by donghyun

last updated

13 min read

νƒœκ·Έ

🌍 The Context: Berlin, New Life, New Needs

September 2025, I moved to Berlin. New city, new life, and new finances to manage with my partner. Using both EUR (Euro) and KRW (Korean Won) simultaneously, existing expense tracking apps couldn’t meet our needs:

  • Multi-currency support (EUR ↔ KRW real-time conversion)
  • Shared ledger concept (for couples)
  • Transaction categorization
  • Monthly/annual summaries and analysis

At the same time, I wanted to explore the AI coding tools space deeply.

β€œSo, why not build it myself? With AI tools.”

πŸ€– Why AI-Assisted Development?

This project started with AI coding tool experimentation in mind from the beginning:

  • Test Claude Code’s real-world project capabilities
  • Identify strengths and limitations of AI tools
  • Learn effective AI utilization patterns
  • Validate AI tool viability in the Elixir/Phoenix ecosystem

πŸ’‘ Honest Expectations Setup

What you should know before starting:

This is NOT a story where β€œAI perfectly built everything.” The reality:

  • βœ… My Role: Architecture design, planning, decision making, extensive refactoring, fixing broken implementations
  • πŸ€– Claude Code’s Role: Code generation, boilerplate creation, initial feature implementation
  • ⏰ Time Reality: ~30% planning, ~40% AI-assisted coding, ~30% refactoring/fixing what AI messed up

AI tools are powerful, but especially with specialized frameworks like Ash Framework, they required significant corrections and improvements. This series covers that realistic journey.

πŸ”§ Technology Choices

Why Elixir?

Elixir is my favorite language, but recently I’ve been using other languages at work, which made me crave an Elixir project even more. Since I consider myself an Elixir expert, I was curious how well I could validate the Elixir code Claude Code generates.

Why Phoenix LiveView?

I’m still not sure if Phoenix LiveView can build complex SPA-level services. There are many inconveniences, and it’s actively evolving, so I’m constantly catching up. I’m genuinely curious if LiveView will one day perfectly replace frontend development.

Why Ash Framework?

Ash Framework has been really hot lately, but the learning curve is steep. As always, using a powerful framework means giving up some freedom. For this project, I was particularly curious how well Claude Code could handle Ash.

Key Decision: PostgreSQL (not ETS/SQLite)

  • Initial plan: SQLite for MVP
  • Reality: Switched to PostgreSQL early
  • Reason: Production-ready from day one

πŸš€ Project Initialization

Day 1: Setting Up

  1. Documentation phase with Claude (17+ files, ~5,500 lines):

    Architecture Documents (in docs/architecture/):

    • DOMAIN_MODEL.md (1,066 lines) - Defined 4 domains (Identity, Accounts, Ledger, Currency)
    • UI_COMPONENTS.md (1,026 lines) - Complete UI spec based on Atomic Design
    • API_SPECIFICATION.md (645 lines) - LiveView event contracts
    • DATABASE_DESIGN.md (489 lines) - Complete schema structure
    • ASH_FRAMEWORK_ANALYSIS.md (355 lines) - Ash framework evaluation and usage strategy
    • SYSTEM_ARCHITECTURE.md (292 lines) - Layered architecture and patterns

    Project Documents (in docs/):

    • REQUIREMENTS_SPECIFICATION.md (815 lines) - Functional/non-functional requirements
    • PROJECT_PLAN.md (572 lines) - MVP β†’ Phase 2 β†’ Phase 3 roadmap
    • TECHNICAL_SPECIFICATION.md - Implementation details
    • CLAUDE.md (229 lines) - AI assistant guide
    • Plus: PROJECT_STATUS, DEPLOYMENT_OPERATIONS_GUIDE, DATA_FLOW_INTEGRATION
  2. Project initialization:

    • mix phx.new shared_ledger
    • mix igniter.install for Ash Framework and dependencies

πŸ“ First Lesson with Claude Code

Day 1: Perfect Planning

Before actually running mix new to generate code, I focused on creating proper documentation. Using the expertise I gained from company projects, I started creating essential documents with Claude’s help. The more thorough you are here, the less unnecessary effort later.

Good documentation means:

  • βœ… AI understands my architectural intent
  • βœ… Generates code with consistent patterns
  • βœ… Doesn’t repeat the same mistakes

But there was a trap…

Day 2: Collision with Reality

# Code perfectly planned on Day 1
changeset = Ash.Changeset.for_action(User, :create, %{})
form = to_form(changeset)  # πŸ”₯ Protocol error!

Error message: Protocol Phoenix.HTML.FormData not implemented for Ash.Changeset

Even with perfect documentation, special Ash Framework integration issues couldn’t be prevented. New documents were created that day:

  • DEVELOPMENT_CONVENTIONS.md - Ash+Phoenix patterns
  • ADR-005: Ash-Phoenix Form Integration - Why we did it this way

Two types of documentation:

  1. Proactive (Day 1) - Documentation that prevents problems
  2. Reactive (Day 2) - Documentation that solves and records problems

AI Agents constantly and unintentionally embed information that differs from what I want, so I needed to carefully review documentation and continuously update it.

Lesson: Documentation is not one-and-done. It must be living documentation.

πŸ—οΈ Architecture Planning

Domain Contexts

Initial planning led to 4 main contexts:

  1. Identity - Users, authentication, sessions
  2. Accounts - Shared accounts, memberships, roles
  3. Ledger - Transactions, categories, summaries
  4. Currency - Exchange rates, conversions
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   Phoenix UI                     β”‚
β”‚              (LiveView Components)               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                Domain Layer                      β”‚
β”‚  Identity  β”‚  Accounts  β”‚  Ledger  β”‚  Currency  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Ash Resources Layer                 β”‚
β”‚    (Declarative definitions + Actions)          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  PostgreSQL                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ€” Architecture Decision Challenges

Initial state: I was confident in Elixir, but domain modeling and relationship design were areas with many concerns, so I decided to follow Claude’s concrete and comprehensive design this time.

Core mistake: Uncritically accepting β€œit sounds logical so it must be right.”

Major cases:

  • 4-domain structure β†’ Week 5 domain boundary refactoring
  • Many-to-many + RBAC β†’ Implemented without understanding manage_relationship β†’ 2 weeks debugging
  • SQLite β†’ Forced PostgreSQL migration (Day 7)
  • 403 Forbidden β†’ 404 NotFound (security issue)

Pattern: Claude suggests β†’ β€œSounds good” β†’ Implement β†’ Discover problems β†’ Refactoring

Time Cost: 10 hours architecture review vs. 3-4 weeks fixing later (1:20~30 ratio)

Lesson: AI knows patterns. But it doesn’t know my problem, trade-offs, security implications. β€œAI presents options. I decide.”

β†’ Part 2 covers domain design details

πŸ“‹ Initial Feature Planning

MVP Scope (Week 1 Planning)

Must Have:

  • βœ… User authentication (email/password)
  • βœ… Create/join shared accounts
  • βœ… Add transactions (amount, category, date, note)
  • βœ… Multi-currency support (EUR, KRW)
  • βœ… Basic transaction list view
  • βœ… Monthly summary

Nice to Have (Later):

  • ❌ Budget tracking
  • ❌ Recurring transactions
  • ❌ Advanced analytics
  • ❌ Mobile app (PWA instead)

πŸ’‘ Lesson: Pattern Pollution

The most dangerous pattern when working with AI: Bad code snowballing

Scenario: Big feature request (500 lines) β†’ Mostly working β†’ Skip detailed review due to laziness β†’ 10 lines of bad code hidden β†’ Claude learns it β†’ Repeats in next feature.

Real Example:

  • Week 1: Direct Ash.Query usage in Transaction LiveView (no review)
  • Week 2-3: Category, Summary LiveView β†’ Same pattern copied
  • Week 5: git grep "Ash.Query" β†’ Found 12 files β†’ 2 weeks refactoring

Another example: Using Decimal instead of Money β†’ Spreads to all calculations β†’ Loss of currency information.

Key points:

  • β€œWorking β‰  Right”
  • One mistake = 12 bugs
  • Review 30 min vs. Refactoring 2 weeks (1:40 ratio)

Solution:

  1. Detailed review mandatory even for big features
  2. Fix wrong patterns immediately (not later)
  3. Record anti-patterns in CLAUDE.md
  4. Periodic audits (git grep forbidden patterns)

β†’ Part 4 covers refactoring in detail

🎯 Documentation-Driven Development

One of the best decisions: Creating comprehensive documentation for Claude Code.

Files created:

  • CLAUDE.md - Project-specific guidelines
  • AGENTS.md - Phoenix/LiveView/Elixir rules (later)
  • ASH_DEVELOPMENT_GUIDE.md - Ash framework patterns
  • ASH_LIVEVIEW_STRICT_RULES.md - Quick checklist

πŸ“ Why This Mattered

ROI: 12-16 hours documentation vs. 30-40 hours saved (~2-3x)

Effects:

  • Claude follows consistent patterns
  • Reduces repeated mistakes
  • Enables multitasking (documentation replaces me)

Trade-offs:

  • Takes significant time to write documentation
  • Requires continuous updates
  • Claude sometimes ignores documentation

Conclusion: Complex frameworks (Ash, LiveView) require documentation. Simple projects don’t need it.

πŸ”„ Development Workflow Setup

Tools & Environment

# Docker for PostgreSQL
docker-compose up -d postgres

# Development commands (Makefile)
make dev-setup  # First time
make dev        # Daily use
make test       # Run tests
make format     # Code formatting

πŸ€” Workflow with Claude Code

Established pattern:

  1. Feature start: Create branch β†’ Provide context to Claude (DOMAIN_MODEL.md, etc.)
  2. During work: Immediate review, stop on pattern violations, check compile at each step
  3. Iteration: Average 3-4 times (Direct Ash β†’ Domain functions β†’ Authorization β†’ Error handling)
  4. Commit: Reject Claude’s commit message suggestions, write my own

Role division:

  • Claude: Boilerplate, repetitive CRUD, test drafts
  • Me: Architecture decisions, complex business logic

Key point: Use as pair programmer, but I make final decisions.

πŸ“Š First Week Results

By the end of first week (Sep 11-18):

βœ… Project initialized
βœ… Ash framework integrated
βœ… Basic domain structure defined
βœ… SQLite setup (later migrated to PostgreSQL)
βœ… Initial documentation written
βœ… Core features implemented (but needed fixes)
⚠️  Many compilation errors to resolve

Git commits tell the story:

dd3de03 - docs: Add comprehensive Ash framework implementation
4377a84 - docs: Add complete Ash framework architecture
b010fc3 - feat: Implement core MVP features with Ash
394878a - feat: Implement Phoenix LiveView UI

πŸ’‘ Key Insight

Planning saved time:

  • Documentation first: 48 hours total investment
  • Without documentation (estimated): 60+ hours (architecture refactoring, repeated mistakes)
  • Saved: ~20%

More importantly: Correct structure, consistent patterns, less technical debt.

However: Documentation couldn’t prevent everything. Week 5-6 needed 26 refactoring commits. AI-generated code still requires review and refactoring.

🎬 What’s Next?

In Part 2, we’ll dive into:

  • Implementing the four domain contexts with Ash
  • Resource definitions and relationships
  • Authorization setup (RBAC)
  • Testing in IEx before touching LiveView
  • Lessons learned about guiding Claude with Ash patterns