<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Amanuel Demissie</title>
    <description>The latest articles on DEV Community by Amanuel Demissie (@amanuel_demissie).</description>
    <link>https://dev.to/amanuel_demissie</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3937245%2Fa0f687dc-1945-49a9-8937-a1f18b717b56.png</url>
      <title>DEV Community: Amanuel Demissie</title>
      <link>https://dev.to/amanuel_demissie</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amanuel_demissie"/>
    <language>en</language>
    <item>
      <title>Week 7: How GusLift Handles Payment Without a Payment Processor</title>
      <dc:creator>Amanuel Demissie</dc:creator>
      <pubDate>Sat, 23 May 2026 10:29:57 +0000</pubDate>
      <link>https://dev.to/guslift/week-7-how-guslift-handles-payment-without-a-payment-processor-4n66</link>
      <guid>https://dev.to/guslift/week-7-how-guslift-handles-payment-without-a-payment-processor-4n66</guid>
      <description>&lt;p&gt;&lt;code&gt;#mobiledevelopment&lt;/code&gt; &lt;code&gt;#backenddevelopment&lt;/code&gt; &lt;code&gt;#database&lt;/code&gt; &lt;code&gt;#infrastructure&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Campus rideshare is informal. Nobody wants to enter a card number. But "figure it out after the ride" doesn't work either — it creates friction and confusion at drop-off. We needed a payment flow that's lightweight, works with Venmo and CashApp, and doesn't require GusLift to touch money.&lt;/p&gt;

&lt;p&gt;Here's what we built.&lt;/p&gt;

&lt;p&gt;Fare Calculation&lt;/p&gt;

&lt;p&gt;Fares are computed from the straight-line distance between two campus buildings using the Haversine formula. The base fare is $1.00. Distance adds $0.75 per mile on top. All 20 Augustana buildings have precomputed lat/lng coordinates, so the fare for any route is deterministic and computable on the client with no API call.&lt;/p&gt;

&lt;p&gt;The rider sees an estimated fare on the home screen before they even request a ride, calculated from their saved commute. That number is confirmed again on the ride detail screen once a match is made.&lt;/p&gt;

&lt;p&gt;Driver Payout Settings&lt;/p&gt;

&lt;p&gt;Drivers configure their preferred payment method once — Venmo handle, CashApp tag, Zelle phone number, or "cash." This is stored in a &lt;code&gt;driver_payment_settings&lt;/code&gt; table in Postgres. When a rider views a confirmed ride, they see which method the driver accepts and the amount to send.&lt;/p&gt;

&lt;p&gt;We also scaffolded Stripe Connect routes for future use, but that path isn't active. For now, all transactions happen off-platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz7uo96ov11gitk5mxbom.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz7uo96ov11gitk5mxbom.png" alt=" " width="753" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Verbal Code&lt;/p&gt;

&lt;p&gt;The rider generates a 4-digit code through the app after paying. The code is written to the Rides table and marked &lt;code&gt;code_issued&lt;/code&gt;. At drop-off, the rider reads the code to the driver, who enters it in the driver ride detail screen. The backend verifies the code matches, marks the ride &lt;code&gt;payment_verified&lt;/code&gt;, and that's it.&lt;/p&gt;

&lt;p&gt;There's no escrow, no hold, no dispute mechanism. The code is purely a lightweight confirmation signal: the rider clicked "I paid" and got a code; the driver confirmed they heard it. For a campus app where both sides know each other by face, that's sufficient.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F80e0w4nwonyl80ux53ny.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F80e0w4nwonyl80ux53ny.png" alt=" " width="753" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Schema Changes&lt;/p&gt;

&lt;p&gt;Four new columns on Rides: &lt;code&gt;fare_cents&lt;/code&gt;, &lt;code&gt;payment_code&lt;/code&gt;, &lt;code&gt;payment_status&lt;/code&gt;, &lt;code&gt;payment_method&lt;/code&gt;. One new table: &lt;code&gt;driver_payment_settings&lt;/code&gt;. The ride history screens for both roles now surface payment status on completed rides.&lt;/p&gt;

&lt;p&gt;What's Left&lt;/p&gt;

&lt;p&gt;The flow assumes the rider pays before the ride ends and that the driver actually checks the code. There's no enforcement if either side skips. For pilot scale — a few dozen rides a week — that's acceptable. Rate limiting on code generation and expiry on unverified codes are the obvious next additions.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>backend</category>
      <category>mobile</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>Week 7: How GusLift Shows Your Route in Real Time</title>
      <dc:creator>Amanuel Demissie</dc:creator>
      <pubDate>Sat, 23 May 2026 10:25:24 +0000</pubDate>
      <link>https://dev.to/guslift/week-7-how-guslift-shows-your-route-in-real-time-jnh</link>
      <guid>https://dev.to/guslift/week-7-how-guslift-shows-your-route-in-real-time-jnh</guid>
      <description>&lt;p&gt;&lt;code&gt;#reactnative&lt;/code&gt; &lt;code&gt;#maps&lt;/code&gt; &lt;code&gt;#crossplatform&lt;/code&gt; &lt;code&gt;#mobiledevelopment&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Every ride request involves two locations. The matching screen was showing those as text. Adding a map that actually shows both pins — pickup in green, dropoff in red, other participants in blue — is a small change in concept but a surprisingly tricky one in practice.&lt;/p&gt;

&lt;p&gt;Here's how we got there.&lt;/p&gt;

&lt;p&gt;The Native Maps Dead End&lt;/p&gt;

&lt;p&gt;The first attempt used react-native-maps backed by Google Maps. It worked on iOS and Android simulators. It didn't work on web at all, and the native build requires an API key wired into the native layer, which adds friction every time someone clones the repo. After getting it running, we ripped it out entirely.&lt;/p&gt;

&lt;p&gt;What We Replaced It With&lt;/p&gt;

&lt;p&gt;The map is now a WebView embed running Leaflet over OpenStreetMap tiles. On web it renders as a plain &lt;code&gt;&amp;lt;iframe srcDoc&amp;gt;&lt;/code&gt;. On iOS and Android it uses react-native-webview. Same HTML, same behavior, no API key required, no native build step.&lt;/p&gt;

&lt;p&gt;The map HTML is generated at runtime. We compute a bounding box from all the pins, set the center and zoom dynamically, and inject the markers as JavaScript into the Leaflet page before it loads. Each pin is a custom SVG — a teardrop shape with a white circle — colored by role.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8sdc462763nq2r0ahbvc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8sdc462763nq2r0ahbvc.png" alt=" " width="726" height="1590"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Coordinate Layer&lt;/p&gt;

&lt;p&gt;Campus buildings don't have addresses that geocoding handles well. We precomputed lat/lng for all 20 Augustana buildings from OpenStreetMap and stored them in a static lookup table — &lt;code&gt;campusCoords.js&lt;/code&gt;. Every pin resolves through that table. No geocoding at runtime, no API call, no latency.&lt;/p&gt;

&lt;p&gt;Where Maps Appear&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RouteMap&lt;/code&gt; is a single reusable component that takes &lt;code&gt;pickup&lt;/code&gt;, &lt;code&gt;dropoff&lt;/code&gt;, and an optional &lt;code&gt;extraMarkers&lt;/code&gt; array. It appears on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The rider and driver waiting rooms (your own route while you wait)&lt;/li&gt;
&lt;li&gt;The ride detail screens (confirmed route after match)&lt;/li&gt;
&lt;li&gt;The available riders/drivers screens (driver sees all rider pickup pins; rider sees the driver's pickup pin in purple once matched)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The matching worker was extended to broadcast &lt;code&gt;pickup_loc&lt;/code&gt; alongside &lt;code&gt;to_location&lt;/code&gt; over WebSocket so that map pins for other participants are available on match screens without an extra DB fetch.&lt;/p&gt;




&lt;p&gt;What Didn't Change&lt;/p&gt;

&lt;p&gt;State, matching logic, and the Durable Object model are untouched. The map is purely display — it reads locations already present in the app state and renders them.&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>mobile</category>
      <category>reactnative</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
