<?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: Chairul Akmal</title>
    <description>The latest articles on DEV Community by Chairul Akmal (@chairulakmal).</description>
    <link>https://dev.to/chairulakmal</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3987486%2Fa9a95454-d8e3-4486-bbb5-6c289b4c6c39.jpeg</url>
      <title>DEV Community: Chairul Akmal</title>
      <link>https://dev.to/chairulakmal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chairulakmal"/>
    <language>en</language>
    <item>
      <title>I built a Rails 8 + Next.js 16 SaaS boilerplate so you don't have to</title>
      <dc:creator>Chairul Akmal</dc:creator>
      <pubDate>Tue, 16 Jun 2026 13:24:11 +0000</pubDate>
      <link>https://dev.to/chairulakmal/i-built-a-rails-8-nextjs-16-saas-boilerplate-so-you-dont-have-to-4bem</link>
      <guid>https://dev.to/chairulakmal/i-built-a-rails-8-nextjs-16-saas-boilerplate-so-you-dont-have-to-4bem</guid>
      <description>&lt;p&gt;Every SaaS project I've started begins the same way: wire up Devise, figure out JWT, build Stripe service objects, set up i18n, configure Docker, write CI, sort out deployment. That's two or three days of work that produces zero product value.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://github.com/chairulakmal/tarik" rel="noopener noreferrer"&gt;tarik&lt;/a&gt; — a GitHub Template that ships all of it wired together and ready to extend.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the box
&lt;/h2&gt;

&lt;p&gt;Rails 8 in API mode, Next.js 16 App Router, Devise + devise-jwt with &lt;code&gt;Authorization: Bearer&lt;/code&gt; tokens (no cookies — any HTTP client works), Stripe integrated through service objects, English and Japanese i18n from the first commit, Docker Compose for local Postgres and Redis, GitHub Actions CI, and Railway deployment config.&lt;/p&gt;

&lt;p&gt;There's also a demo mode. Set &lt;code&gt;DEMO_MODE=true&lt;/code&gt;, seed the database, and you can explore the full subscription flow without touching Stripe at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why service objects for payments
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;stripe&lt;/code&gt; gem directly — not the &lt;code&gt;pay&lt;/code&gt; abstraction. All Stripe logic lives under &lt;code&gt;app/services/payments/&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;app/services/&lt;br&gt;
├── payment_service.rb          # facade&lt;br&gt;
└── payments/&lt;br&gt;
    ├── charge_service.rb&lt;br&gt;
    ├── subscription_service.rb&lt;br&gt;
    └── webhook_service.rb&lt;/p&gt;

&lt;p&gt;Nothing in controllers or models. This makes the code easy to test, easy to reason about, and — when the time comes — easy to swap out. Which brings me to the next thing.&lt;/p&gt;
&lt;h2&gt;
  
  
  The PAY.JP angle
&lt;/h2&gt;

&lt;p&gt;tarik ships a &lt;a href="https://github.com/chairulakmal/tarik/blob/main/docs/payjp-migration.md" rel="noopener noreferrer"&gt;full migration guide&lt;/a&gt; for moving from Stripe to PAY.JP. PAY.JP is widely used in Japan's Ruby bootcamp and startup ecosystem, and the service object pattern means the swap&lt;br&gt;
is contained: no controller or model changes needed for the core migration. The guide covers all nine steps with ready-to-apply code.&lt;/p&gt;
&lt;h2&gt;
  
  
  The AI agent angle
&lt;/h2&gt;

&lt;p&gt;This is the part I'm most interested in. tarik ships an &lt;code&gt;AGENTS.md&lt;/code&gt; that documents the architecture, conventions, and hard rules in a format designed for AI coding agents. When you hand a codebase to Claude, GPT, or any other agent, it re-derives the same decisions every time — Devise vs Rodauth, where business logic lives, how auth flows. Every token spent on that is a token not spent on your product.&lt;/p&gt;

&lt;p&gt;With tarik, the decisions are already made and documented. Your agent — and you — start at product, not at scaffolding.&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Click &lt;strong&gt;Use this template&lt;/strong&gt; on the &lt;a href="https://github.com/chairulakmal/tarik" rel="noopener noreferrer"&gt;tarik repo&lt;/a&gt;, then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/your-username/your-project
&lt;span class="nb"&gt;cd &lt;/span&gt;your-project
bin/setup
bin/dev

bin/setup handles dependencies, .env creation, Docker services, and database setup.
It&lt;span class="s1"&gt;'s idempotent — safe to run more than once.

Frontend at localhost:3000, API at localhost:3001.

---
Would love feedback from anyone who'&lt;/span&gt;s built something similar or has opinions on the architecture choices —
especially the JWT-in-localStorage vs HttpOnly-cookie tradeoff, which I&lt;span class="s1"&gt;'ve documented in docs/auth.md along with instructions for switching if you need SSR-protected pages.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>ruby</category>
      <category>rails</category>
      <category>nextjs</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
