👋 Hi, I’m Seunghan, an AI-Native Engineer.
I build mobile apps and web services powered by AI. Passionate about improving user experiences and solving real-world problems.
👋 Hi, I’m Seunghan, an AI-Native Engineer.
I build mobile apps and web services powered by AI. Passionate about improving user experiences and solving real-world problems.
If you’re building a mobile app with Hotwire Native and Rails 8, you’ll eventually hit issues that don’t show up in development but break things in production — especially on real iOS devices running inside WKWebView. This post documents 7 real-world pitfalls I encountered while shipping a tournament management app (Turbo + Stimulus + ERB + Tailwind CSS 4) as a Hotwire Native iOS app. Each issue includes the symptom, root cause analysis, fix, and lessons learned. ...
Three real-world problems encountered while building a real-time tournament dashboard with Rails 8 + Hotwire, and the exact steps taken to resolve each one. These issues are not edge cases — they reflect the natural friction points of the Hotwire programming model that become apparent only at runtime. 1. Turbo Stream + Stimulus DnD: Events Vanish After DOM Replacement The Problem The feature: drag a player chip onto a court card, send a POST to the server, and get back a Turbo Stream response that replaces both the court card and the player list. ...
The bigger your codebase gets, the harder it is to answer “why does this feature work like this?” You end up opening 5 files. The design doc was written 3 months ago and nobody knows if it still matches the code. Comments are stale, Slack threads are gone, and the original designer left the company. What if the design doc itself was executable, and you maintained that instead of the code? ...

When you’re designing three features simultaneously, they start bleeding into each other. This time I added the following to a tournament bracket management app: FAB Feedback Button — floating button bottom-right → Telegram notification Role-Based Bracket Edit Permissions — tournament vs. friendly mode determines whether regular participants can edit the bracket Audit Log — records who changed what and when, with before/after data Each is simple on its own, but doing them together forced a lot of decisions: where to check permissions, where to write logs, and how much to expose in the UI. ...

When you think about implementing a theme system, the first instinct is to add conditional classes to every component. But what if you could swap the entire app’s color palette by changing a single CSS block — without touching any HTML? In Tailwind v4, that’s exactly what you can do. How Tailwind v4 Compiles Utility Classes The architectural shift that makes this entire pattern possible is subtle but profound. Tailwind v4 compiles utility classes as CSS variable references rather than hard-coded values: ...

I was adding two features to the dashboard of a sports tournament management app: DnD card reordering — drag cards to rearrange sections (My Matches / Bracket / Match List) Card collapse/expand — fold away sections you don’t need Each sounds simple, but add Turbo Frame lazy loading and a requirement that layout state survives page reloads, and there’s more to think about than it first appears. 1. Choosing a DnD Library My first attempt used the native HTML5 Drag & Drop API directly — dragstart, dragover, drop. It works fine on desktop, but the problem is touch devices. The HTML5 drag API has incomplete support on iOS Safari; touch-dragging simply doesn’t work there. ...
I added click-to-highlight interactivity to an SVG-based tournament bracket built with Rails 8 and ViewComponent. Here’s what I ran into. The goal: click a player’s row in the bracket → all matches featuring that player get a subtle color highlight. Background: SVG-rendered bracket The bracket isn’t HTML divs — it’s a pure SVG rendered by a BracketTreeComponent (ViewComponent). The component calculates coordinates for each match slot and emits <rect>, <text>, <circle>, and connector <path> elements. ...
Two problems solved while building a Rails 8 + Hotwire Native iOS app. Real-time notification badge — instantly update the app icon badge and bell button the moment a notification is created on the server Side menu navigation failure — correctly navigate to URLs that require dynamic parameters like a resource ID 1. Background Notification Badge Without setting the badge field in APNs push notifications, no number appears on the iOS app icon. And even when notifications are read, the badge doesn’t clear. ...
Running an iOS app built with Rails 8 + Hotwire Native, I hit a series of issues in a single day. What started as a small UI distortion spiraled into a full permission system redesign. Here is the complete record. The central appeal of Hotwire Native is being able to serve both a web browser and a native iOS or Android shell from a single Rails application. But that architecture quietly encourages a dangerous assumption: if it looks right in the browser, it will look right in the app. In practice, the WKWebView rendering context, the presence of a native navigation bar, and role-based UI branching introduce concerns that have no equivalent in a standard web browser. This post walks through seven of those issues and the patterns that resolved them. ...
While documenting UX flows with Rails + Lookbook, I hit a moment of “something feels off.” Each Step only showed wireframe fragments, so looking at the Lookbook list gave zero sense of the overall flow. I fixed two things: Add a Mermaid flowchart Overview step to each flow Redesign all Step template structures The Problem: Lookbook Step Previews Feel Like “Context-Free Fragments” # @label Admin UX Flow # @logical_path ux_flows class UxFlows::AdminFlowPreview < ViewComponent::Preview # @label 1. Login -> Admin Dashboard def step_1_login_dashboard render_with_template end # ... end Each step_* method renders an ERB template via render_with_template. The ERB contains a wireframe with a simple step navigation bar at the top. ...