<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Fastapi on Daffa Abhipraya</title><link>https://blog.abhipraya.dev/tags/fastapi/</link><description>Recent content in Fastapi on Daffa Abhipraya</description><generator>Hugo</generator><language>en-us</language><copyright>© Daffa Abhipraya</copyright><lastBuildDate>Thu, 09 Apr 2026 00:00:00 +0700</lastBuildDate><atom:link href="https://blog.abhipraya.dev/tags/fastapi/index.xml" rel="self" type="application/rss+xml"/><item><title>PPL: SOLID Principles in a FastAPI Invoice System</title><link>https://blog.abhipraya.dev/ppl/part-a/solid/</link><pubDate>Thu, 09 Apr 2026 00:00:00 +0700</pubDate><guid>https://blog.abhipraya.dev/ppl/part-a/solid/</guid><description>&lt;p>SIRA (Smart Invoice Reminder AI) is a system that automates invoice collection reminders. It monitors payment status, scores client risk using a weighted formula, and sends personalized reminders by email or messaging. The backend is built with FastAPI, Supabase (Postgres via REST), Celery for background jobs, and Redis as the message broker.&lt;/p>
&lt;p>This blog walks through how SOLID principles shaped the architecture at three levels: the overall layer structure, service-level design patterns, and individual function design. The goal is not to explain what SOLID stands for (there are plenty of articles for that), but to show what it looks like in production code and why certain design choices were made over simpler alternatives.&lt;/p></description></item><item><title>PPL: SOLID and Layered Architecture [Sprint 1, Week 3]</title><link>https://blog.abhipraya.dev/ppl/part-b/s1w3-programming/</link><pubDate>Fri, 13 Mar 2026 00:00:00 +0700</pubDate><guid>https://blog.abhipraya.dev/ppl/part-b/s1w3-programming/</guid><description>&lt;h2 id="what-i-worked-on">
 &lt;a class="anchor" href="#what-i-worked-on" data-anchor="what-i-worked-on" aria-hidden="true">#&lt;/a>
 What I Worked On
&lt;/h2>
&lt;p>This week&amp;rsquo;s invoice management feature (MR !12) required a full CRUD stack with filtering, sorting, auth enforcement, and business validation (status transitions, admin-only delete). Building this properly meant enforcing strict layer boundaries and handling the tension between HTTP concerns and domain logic.&lt;/p>
&lt;h2 id="the-three-layer-pattern-in-practice">
 &lt;a class="anchor" href="#the-three-layer-pattern-in-practice" data-anchor="the-three-layer-pattern-in-practice" aria-hidden="true">#&lt;/a>
 The Three-Layer Pattern in Practice
&lt;/h2>
&lt;p>SIRA&amp;rsquo;s backend follows Router → Service → DB, where each layer has a single responsibility:&lt;/p></description></item><item><title>PPL: Test-Driven Development [Sprint 1, Week 3]</title><link>https://blog.abhipraya.dev/ppl/part-b/s1w3-tdd/</link><pubDate>Fri, 13 Mar 2026 00:00:00 +0700</pubDate><guid>https://blog.abhipraya.dev/ppl/part-b/s1w3-tdd/</guid><description>&lt;h2 id="what-i-worked-on">
 &lt;a class="anchor" href="#what-i-worked-on" data-anchor="what-i-worked-on" aria-hidden="true">#&lt;/a>
 What I Worked On
&lt;/h2>
&lt;p>This week shipped three full-stack features using strict TDD discipline: invoice management (CRUD + filtering), layout/dashboard (sidebar, header, dashboard with role-based navigation), and a payments sidebar navigation link. Each feature followed red-green-refactor with tagged commits.&lt;/p>
&lt;p>The project now has &lt;strong>392 backend tests&lt;/strong> and &lt;strong>195 frontend tests&lt;/strong> (587 total), up from 51 last week.&lt;/p>
&lt;h2 id="red-green-refactor-commit-discipline">
 &lt;a class="anchor" href="#red-green-refactor-commit-discipline" data-anchor="red-green-refactor-commit-discipline" aria-hidden="true">#&lt;/a>
 Red-Green-Refactor Commit Discipline
&lt;/h2>
&lt;p>Every feature branch this week followed tagged commits so the TDD flow is auditable from the git history alone.&lt;/p></description></item><item><title>PPL: Code Review Across Architecture and Runtime Bugs [Sprint 1, Week 2]</title><link>https://blog.abhipraya.dev/ppl/part-b/s1w2-code-review/</link><pubDate>Wed, 04 Mar 2026 00:00:00 +0700</pubDate><guid>https://blog.abhipraya.dev/ppl/part-b/s1w2-code-review/</guid><description>&lt;h2 id="overview">
 &lt;a class="anchor" href="#overview" data-anchor="overview" aria-hidden="true">#&lt;/a>
 Overview
&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>MR&lt;/th>
 &lt;th>Feature&lt;/th>
 &lt;th>Issues&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;a href="https://gitlab.lab.local/joint-research/ui/smart-invoice-reminder/SIRA/-/merge_requests/10">!10&lt;/a> - SIRA-31&lt;/td>
 &lt;td>Payment recording (dafandikri)&lt;/td>
 &lt;td>2&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://gitlab.lab.local/joint-research/ui/smart-invoice-reminder/SIRA/-/merge_requests/12">!12&lt;/a> - SIRA-30&lt;/td>
 &lt;td>Invoice management (froklax)&lt;/td>
 &lt;td>7&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://gitlab.lab.local/joint-research/ui/smart-invoice-reminder/SIRA/-/merge_requests/17">!17&lt;/a> - SIRA-29&lt;/td>
 &lt;td>Client management (fadhli)&lt;/td>
 &lt;td>1&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://gitlab.lab.local/joint-research/ui/smart-invoice-reminder/SIRA/-/merge_requests/20">!20&lt;/a> - SIRA-27&lt;/td>
 &lt;td>Layout and dashboard (haliza)&lt;/td>
 &lt;td>1&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>11 issues total. Each review included specific file and line references.&lt;/p>
&lt;hr>
&lt;h2 id="mr-10---payment-recording-2-issues">
 &lt;a class="anchor" href="#mr-10---payment-recording-2-issues" data-anchor="mr-10---payment-recording-2-issues" aria-hidden="true">#&lt;/a>
 MR !10 - Payment Recording (2 issues)
&lt;/h2>
&lt;p>&lt;strong>Issue 1: &lt;code>.single()&lt;/code> causes an unhandled 500 on missing records.&lt;/strong>&lt;/p>
&lt;p>&lt;code>get_payment_by_id&lt;/code> used &lt;code>.single()&lt;/code> which throws &lt;code>PostgRESTError (PGRST116)&lt;/code> when no row is found, making the &lt;code>if payment is None&lt;/code> guard below it dead code. The fix is &lt;code>.maybe_single()&lt;/code>, which returns &lt;code>None&lt;/code> cleanly. The same fix was already applied in MR !23 for &lt;code>app_users.py&lt;/code>.&lt;/p></description></item><item><title>PPL: Test-Driven Development in a FastAPI Project [Sprint 1, Week 2]</title><link>https://blog.abhipraya.dev/ppl/part-b/s1w2-tdd/</link><pubDate>Wed, 04 Mar 2026 00:00:00 +0700</pubDate><guid>https://blog.abhipraya.dev/ppl/part-b/s1w2-tdd/</guid><description>&lt;p>TDD forces you to think about the interface before the implementation. This post covers how it was applied in the Smart Invoice Reminder AI (SIRA) backend for Sprint 1.&lt;/p>
&lt;h2 id="test-distribution">
 &lt;a class="anchor" href="#test-distribution" data-anchor="test-distribution" aria-hidden="true">#&lt;/a>
 Test Distribution
&lt;/h2>
&lt;p>The API currently has 51 test functions across 4 files:&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>File&lt;/th>
 &lt;th>Tests&lt;/th>
 &lt;th>Scope&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;code>tests/test_auth.py&lt;/code>&lt;/td>
 &lt;td>14&lt;/td>
 &lt;td>JWT validation, RBAC, DB queries&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>tests/test_payments.py&lt;/code>&lt;/td>
 &lt;td>24&lt;/td>
 &lt;td>Payment CRUD, business logic, edge cases&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>tests/test_db_schema_and_seed.py&lt;/code>&lt;/td>
 &lt;td>6&lt;/td>
 &lt;td>Migration integrity, seed validation&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>tests/test_logging_middleware.py&lt;/code>&lt;/td>
 &lt;td>7&lt;/td>
 &lt;td>HTTP access logging, request/response capture&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="red-green-refactor">
 &lt;a class="anchor" href="#red-green-refactor" data-anchor="red-green-refactor" aria-hidden="true">#&lt;/a>
 Red-Green-Refactor
&lt;/h2>
&lt;p>The authentication feature (&lt;a href="https://linear.app/ppl-sira/issue/SIRA-26">SIRA-26&lt;/a>) followed strict TDD commit discipline. Each backend function got its own RED commit (failing test) followed by a GREEN commit (passing implementation) before any cleanup.&lt;/p></description></item></channel></rss>