<?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: Harun Al Rasyid</title>
    <description>The latest articles on DEV Community by Harun Al Rasyid (@hrnlrsyd).</description>
    <link>https://dev.to/hrnlrsyd</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%2F3307271%2F434aa911-849e-452a-b683-57b0f6cd7237.jpg</url>
      <title>DEV Community: Harun Al Rasyid</title>
      <link>https://dev.to/hrnlrsyd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hrnlrsyd"/>
    <language>en</language>
    <item>
      <title>Building Cursor Powered App: A Devlog Series, Powered by Cursor (Part 4) – Authentication Logic</title>
      <dc:creator>Harun Al Rasyid</dc:creator>
      <pubDate>Sat, 09 Aug 2025 05:47:14 +0000</pubDate>
      <link>https://dev.to/hrnlrsyd/building-cursor-powered-app-a-devlog-series-powered-by-cursor-part-4-authentication-logic-39ag</link>
      <guid>https://dev.to/hrnlrsyd/building-cursor-powered-app-a-devlog-series-powered-by-cursor-part-4-authentication-logic-39ag</guid>
      <description>&lt;p&gt;In the last few episodes of this devlog saga, we laid down the basics. From crafting our &lt;code&gt;pkg&lt;/code&gt; utilities to sketching out the core architecture.&lt;br&gt;&lt;br&gt;
Now it's time to work on one of the most important parts of any app: &lt;strong&gt;Authentication&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;Yes, that magical system that decides whether you're a &lt;em&gt;trusted user&lt;/em&gt; or just some stranger.&lt;br&gt;&lt;br&gt;
And, get ready for another &lt;em&gt;temporary&lt;/em&gt; hardcoded user. Promise, it's just for testing. (I know, we said the same thing about any other config in previous part :D).&lt;/p&gt;

&lt;p&gt;In this post, we'll walk through the &lt;strong&gt;authentication domain&lt;/strong&gt;, &lt;strong&gt;use cases&lt;/strong&gt;, and how we wire them together using &lt;strong&gt;dependency injection&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
While the implementation uses a hardcoded user for now (since the database setup comes later), all the token mechanics are already production-style.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Authentication Domain
&lt;/h2&gt;

&lt;p&gt;At its core, the authentication domain has just two main players: &lt;strong&gt;Credential&lt;/strong&gt; and &lt;strong&gt;Session&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
You give us your credentials, we give you a session. Simple as that. At least in theory. &lt;/p&gt;

&lt;p&gt;The authentication domain is basically the brain of our login system.&lt;br&gt;
It's where we keep all the logic for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validating login credentials (right now for our VIP hardcoded user membership).&lt;/li&gt;
&lt;li&gt;Generating JWT tokens.&lt;/li&gt;
&lt;li&gt;Handling refresh logic.&lt;/li&gt;
&lt;li&gt;Revoking tokens so they can't be reused.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The cool part? It doesn't care about HTTP, JSON, or any of that transport stuff. It's just pure business logic.&lt;/p&gt;

&lt;p&gt;And, before your forgot that this is a &lt;em&gt;Cursor-powered&lt;/em&gt; application, let's kick things off the right way, by stating the &lt;strong&gt;Cursor Rule&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;### Credential
Represents the input required for user authentication (login).

- **Fields:**
  - Email: type `user.Email` (referenced from user package), validated as `required,email`
  - Password: type `user.Password` (referenced from user package), validated as `required,password`
- **Best Practices:**
  - Do not store credentials; use only for authentication input
  - Always validate both fields before processing
- **Method:**
  - `Verify(ctx context.Context, matchedUser *user.User) error`: Checks if the provided password matches the user's stored ciphertext. Returns nil if matched, otherwise returns InvalidCredential. Uses the Password's validation and matching logic.

## Session Object
Represents the output of a successful authentication (login), containing issued tokens.

- **Fields:**
  - AccessToken: type `token.Token` (referenced from token package)
  - RefreshToken: type `token.Token` (referenced from token package)
- **Best Practices:**
  - AccessToken is used for short-lived API access
  - RefreshToken is used to obtain new access tokens
  - Consider implementing refresh token rotation for enhanced security
  - Do not expose sensitive token details in logs or user-facing messages

## Token Subject Constants
- **AccessTokenSubject**: Constant string value representing the subject for access tokens (e.g., "access_token").
- **RefreshTokenSubject**: Constant string value representing the subject for refresh tokens (e.g., "refresh_token").
- **Usage**: These constants should be used as the `Subject` field in token claims to distinguish between access and refresh tokens throughout the authentication flow.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We generate two tokens: an access_token and a refresh_token, and store their metadata in Redis.&lt;br&gt;
This metadata is the Session Object, and it's what lets us fully control a token's lifecycle.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;access_token&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A short-lived token (valid for 2 hours) used for most API requests.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;refresh_token&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A longer-lived token (valid for 48 hours), inactive for the first 2 hours.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These tokens are not just random strings. They are stored in Redis along with metadata records in redis.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;exp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expiration timestamp.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nbf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"Not before” timestamp, ensuring the refresh token can't be used too early.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jti&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unique token ID, similar to a JWT claim.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;user_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The ID of the authenticated user.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;link_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A link between an access token and its refresh token (used for revocation).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Storage keys in Redis:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;access:&amp;lt;jti&amp;gt;&lt;/code&gt; → metadata&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;refresh:&amp;lt;jti&amp;gt;&lt;/code&gt; → metadata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt;&lt;br&gt;
The Session Object is the source of truth for authentication. It allows us to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enforce expiration and "not before" rules.&lt;/li&gt;
&lt;li&gt;Implement revocation instantly (kill a token in Redis, and it's dead on the next request).&lt;/li&gt;
&lt;li&gt;Revoke both tokens at once via link_id.&lt;/li&gt;
&lt;li&gt;Avoid trusting client-side tokens blindly. Every token is validated against Redis.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Use Cases
&lt;/h2&gt;

&lt;p&gt;We (&lt;strong&gt;I and cursor&lt;/strong&gt;) have implemented three core authentication flows.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Login Endpoint
&lt;/h3&gt;

&lt;p&gt;The login flow takes in email and password (right now, it's checked against a hardcoded user. Don't judge, it's just a demo).&lt;/p&gt;

&lt;p&gt;If you pass the vibe check, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An access token (valid for 2 hours)&lt;/li&gt;
&lt;li&gt;A refresh token (valid for 48 hours, but time-locked for the first 2 hours via nbf).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why the lock? Because we don't want people refreshing too soon, &lt;strong&gt;like your PM who asks "are we done yet?" five minutes after the task was delivered&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Refresh Token Endpoint
&lt;/h3&gt;

&lt;p&gt;The refresh endpoint accepts a &lt;code&gt;refresh_token&lt;/code&gt; and:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Validates that &lt;code&gt;nbf&lt;/code&gt; ≤ current time.&lt;/li&gt;
&lt;li&gt;Issues a &lt;strong&gt;new pair of tokens&lt;/strong&gt; (access + refresh).&lt;/li&gt;
&lt;li&gt;Revokes the old refresh token (single-use only, like that one time lunch coupon you forgot to redeem).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By revoking the old refresh token, we ensure attackers can't reuse a stolen refresh token.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Logout Endpoint
&lt;/h3&gt;

&lt;p&gt;The logout flow accepts the &lt;code&gt;Authorization: Bearer &amp;lt;access_token&amp;gt;&lt;/code&gt; header and:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Revokes the access token.&lt;/li&gt;
&lt;li&gt;Uses &lt;code&gt;link_id&lt;/code&gt; to find and revoke the associated refresh token.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This prevents both access and refresh tokens from being used again.&lt;/p&gt;


&lt;h2&gt;
  
  
  Dependency Injection
&lt;/h2&gt;

&lt;p&gt;We use Google Wire (&lt;a href="https://github.com/google/wire" rel="noopener noreferrer"&gt;https://github.com/google/wire&lt;/a&gt;) to handle dependency injection in the authentication module.&lt;br&gt;
The snippet below defines a UseCaseSet&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;UseCaseSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wire&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConfigSet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c"&gt;// Configuration&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProvideRedisClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProvideRedisAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c"&gt;// Repositories&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProvideUserRepository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProvideTokenGenerator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c"&gt;// Use Cases&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProvideAuthUseCase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c"&gt;// Container&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProvideContainer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;InitializeContainer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wire&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UseCaseSet&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Removes manual dependency wiring.&lt;/li&gt;
&lt;li&gt;Makes components easier to test (swap in mocks).&lt;/li&gt;
&lt;li&gt;Avoids accidental "hidden"”" dependencies.&lt;/li&gt;
&lt;li&gt;Keeps our codebase modular.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, UseCaseSet is the blueprint, Wire is the builder, and Container is the final assembled product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links, if you're curious
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/harungurubudi/mtsg/issues/5" rel="noopener noreferrer"&gt;Issue #5 – Implement Session Based Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/harungurubudi/mtsg" rel="noopener noreferrer"&gt;&lt;code&gt;mtsg&lt;/code&gt; Repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Now that authentication is in place, it's time to bring it to life in the presentation layer.&lt;br&gt;
Here, our APIs will finally be able to greet the outside world. And yes, we'll even make it shake hands politely with Swagger docs.&lt;/p&gt;

</description>
      <category>vibecoding</category>
      <category>go</category>
    </item>
    <item>
      <title>Building Cursor Powered App: A Devlog Series, Powered by Cursor (Part 3) - Laying the Foundation with Packages</title>
      <dc:creator>Harun Al Rasyid</dc:creator>
      <pubDate>Fri, 01 Aug 2025 10:58:40 +0000</pubDate>
      <link>https://dev.to/hrnlrsyd/building-cursor-powered-app-a-devlog-series-powered-by-cursor-part-3-laying-the-foundation-nc6</link>
      <guid>https://dev.to/hrnlrsyd/building-cursor-powered-app-a-devlog-series-powered-by-cursor-part-3-laying-the-foundation-nc6</guid>
      <description>&lt;p&gt;Hey! Before we dive into login screens and token refresh logic, I want to take a step back and shine a light on something that rarely gets the attention it deserves: the supporting packages.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They don't flash UI.&lt;/li&gt;
&lt;li&gt;They don't talk HTTP.
But they are everything that makes the rest of the app possible.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;But first, a confession.&lt;br&gt;
I did something bold. Brave. Maybe even a little impulsive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I subscribed to Cursor Pro&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, I paid actual money. And I have zero regrets.&lt;/p&gt;

&lt;p&gt;Why? Because coding with Cursor feels less like using a tool and more like pairing with a genius friend who never gets tired, judges my bad naming only silently, and finishes my half-baked ideas without drama X)).&lt;/p&gt;

&lt;p&gt;It's not just about giving it prompts. It's about building vibes. You teach Cursor your coding rituals, your quirks, your "I know it's ugly but it works" logic. And wow! it adapts. It's like a teammate that reads your mind, writes tests, and never asks for coffee breaks.&lt;/p&gt;


&lt;h1&gt;
  
  
  The Foundation: Packages
&lt;/h1&gt;

&lt;p&gt;Before we get fancy with login forms and token flows, let's appreciate the "boring yet essential" stuff: the packages. The heroes of app that quietly hold everything together without complaining.&lt;/p&gt;
&lt;h2&gt;
  
  
  Redis Adapter
&lt;/h2&gt;

&lt;p&gt;This package wraps Redis operations. I didn't reinvent the wheel, just made it easier to test, swap, and inject (like a good dependency should). The idea is simple: don't scatter &lt;code&gt;redisClient.Set(...)&lt;/code&gt; all over your app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Redis Adapter Rule

The `redis` package provides an adapter that wraps the `github.com/go-redis/redis/v8` library, offering a simplified and type-safe API for common Redis operations.

## Purpose
- Abstract away direct usage of the go-redis client
- Provide a reusable, testable, and idiomatic interface for Redis operations
- Enable easy mocking and extension for testing and future enhancements

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Token Provider
&lt;/h2&gt;

&lt;p&gt;This one powers the generation, validation, and parsing. Both access and refresh tokens. I use a TokenSubject enum to keep things clean (AccessTokenSubject, RefreshTokenSubject, etc).&lt;/p&gt;

&lt;p&gt;I also introduced something fun: &lt;strong&gt;LinkedToken&lt;/strong&gt;. It embeds the refresh token ID inside the access token's claim. This way, revoking both tokens becomes possible even when all you have is the access token, neat, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Error
&lt;/h2&gt;

&lt;p&gt;In this app, I separate internal errors (think: Redis down, token parsing failed) from business errors (like "wrong credentials").&lt;/p&gt;

&lt;p&gt;How?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Internal errors are wrapped with my beloved stackerror package. They bubble up with stack traces and observability in mind.&lt;/li&gt;
&lt;li&gt;Business errors are returned as value objects and interpreted at the presentation layer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This separation lets me write usecases that don't care about HTTP status codes, they just speak in errors, and the HTTP handler translates.&lt;br&gt;
It's like a translator for angry backend logic.&lt;/p&gt;


&lt;h2&gt;
  
  
  Bonus: Cursor Rule Files Are a Superpower
&lt;/h2&gt;

&lt;p&gt;With Cursor, I rely heavily on .mdc files to establish patterns and expectations.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Convention
All packages under /pkg must expose clear interfaces and avoid coupling with HTTP or Echo

# Rule
Business errors are never returned as HTTP errors from usecases
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's not just prompting, it's like training your AI teammate on your architectural beliefs.&lt;/p&gt;




&lt;p&gt;That's it for today!&lt;br&gt;
Authentication is coming next, but I hope showing the invisible infrastructure was helpful. If you've ever wondered how to structure pkg in a scalable Go backend, or want to make AI pair programming less chaotic, this is where I started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links, if you're curious
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/harungurubudi/mtsg" rel="noopener noreferrer"&gt;&lt;code&gt;mtsg&lt;/code&gt; Repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Next Up
&lt;/h2&gt;

&lt;p&gt;We're diving into the juicy stuff: the authentication business module.&lt;br&gt;
Think clean usecases, no HTTP nonsense, and logic that could survive a framework apocalypse.&lt;/p&gt;

&lt;p&gt;We'll answer questions like:&lt;/p&gt;

&lt;p&gt;What actually happens during a login?&lt;/p&gt;

&lt;p&gt;How do refresh tokens work with Redis?&lt;/p&gt;

&lt;p&gt;Can you TOTP your way into greatness?&lt;/p&gt;

&lt;p&gt;Stay tuned, the domain is strong with this one&lt;/p&gt;

</description>
      <category>vibecoding</category>
      <category>go</category>
    </item>
    <item>
      <title>Building Cursor Powered App: A Devlog Series, Powered by Cursor (Part 2) - Defining the Domain</title>
      <dc:creator>Harun Al Rasyid</dc:creator>
      <pubDate>Mon, 14 Jul 2025 13:27:07 +0000</pubDate>
      <link>https://dev.to/hrnlrsyd/building-cursor-powered-app-a-devlog-series-powered-by-cursor-part-2-defining-the-domain-1o9h</link>
      <guid>https://dev.to/hrnlrsyd/building-cursor-powered-app-a-devlog-series-powered-by-cursor-part-2-defining-the-domain-1o9h</guid>
      <description>&lt;p&gt;After struggling with docs in Part 1, I finally touched some code.&lt;br&gt;&lt;br&gt;
This was the start of the actual &lt;strong&gt;domain modeling&lt;/strong&gt; process: defining the core business entities of the app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Tenant&lt;/code&gt;: represents a customer account (company/org)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;User&lt;/code&gt;: belongs to a tenant and interacts with the system&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Project&lt;/code&gt;: something users can create and manage under their tenant&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each model is defined in its own file inside &lt;code&gt;internal/domain/&lt;/code&gt;, keeping things modular and easy to scale.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Start with Domain?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Because the &lt;strong&gt;domain layer is the heart&lt;/strong&gt; of the app.&lt;/li&gt;
&lt;li&gt;And, let's be honest. It makes me look like I know what I'm doing&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Directory Layout
&lt;/h2&gt;

&lt;p&gt;I’m keeping the structure… well, not exactly simple.&lt;br&gt;&lt;br&gt;
But trust me, I'm &lt;em&gt;pretending&lt;/em&gt; I know what I'm doing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;internal/
└── domain/
    ├── tenant/
    ├── user/
    └── project/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each entity gets its own package. It might look like overkill now, but it will pay off as things grow.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Domain Rules
&lt;/h3&gt;

&lt;p&gt;To keep my domain layer consistent (and to future-proof my sanity), I started writing some generic domain rules in &lt;code&gt;.mdc&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;Here’s what I’ve got so far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;entity.mdc&lt;/code&gt;, defines how entities should be structured (fields, IDs, invariants)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;generic-types.mdc&lt;/code&gt;, documents reusable components like &lt;code&gt;Identity&lt;/code&gt;, &lt;code&gt;Enumerated String&lt;/code&gt; types.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;unit-test.mdc&lt;/code&gt;, outlines rules for generating unit tests for domain entities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These arent just notes. They act as &lt;strong&gt;Cursor-aware prompts&lt;/strong&gt; or &lt;strong&gt;codegen contracts&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Its a bit like meta-programming: I describe the rules, and Cursor helps generate code that follows them.&lt;/p&gt;

&lt;p&gt;So yes, I am basically writing documentation for an AI to read X))&lt;/p&gt;
&lt;h3&gt;
  
  
  Entity
&lt;/h3&gt;

&lt;p&gt;Once I had my &lt;code&gt;entity.mdc&lt;/code&gt; rule in place, I started defining specific entity contracts. Beginning with &lt;code&gt;tenant.mdc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here’s how it works: instead of jumping straight into code, I describe the entity and its behavior in Markdown, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Tenant

This rule describes the **tenant** entity and its behavior.

## Entity

### Tenant

- ID: Identity of Tenant – New Identity
- Name: string – constructor input
- Status: Enumerated string of "active", "inactive", default("active")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't just documentation — Cursor uses it to generate consistent, valid Go code that follows my conventions.&lt;br&gt;&lt;br&gt;
It reads the structure, applies the meta-rules from &lt;code&gt;entity.mdc&lt;/code&gt;, and gives me a complete Go struct, constructor, and even basic validation.&lt;/p&gt;

&lt;p&gt;So in a way, I am designing the system in plain text first, and letting AI turn it into working code.&lt;br&gt;&lt;br&gt;
And honestly? I amm starting to feel like it writes Go better than I do X)).&lt;/p&gt;

&lt;h2&gt;
  
  
  Links, if you're curious
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/harungurubudi/mtsg/issues/2" rel="noopener noreferrer"&gt;Issue #2 – Define core domain models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/harungurubudi/mtsg/pull/4" rel="noopener noreferrer"&gt;PR #4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/harungurubudi/mtsg" rel="noopener noreferrer"&gt;&lt;code&gt;mtsg&lt;/code&gt; Repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Next Up
&lt;/h2&gt;

&lt;p&gt;Now that the domain layer is in place, I'm going to focus on session management and authentication.&lt;/p&gt;

&lt;p&gt;I'll be storing sessions in Redis (instead of using JWTs) so I can invalidate them easily — a pattern I've used and loved in past projects.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building Cursor Powered App: A Devlog Series, Powered by Cursor (Part 1)</title>
      <dc:creator>Harun Al Rasyid</dc:creator>
      <pubDate>Sat, 12 Jul 2025 07:29:42 +0000</pubDate>
      <link>https://dev.to/hrnlrsyd/building-cursor-powered-app-a-devlog-series-powered-by-cursor-part-1-1lh0</link>
      <guid>https://dev.to/hrnlrsyd/building-cursor-powered-app-a-devlog-series-powered-by-cursor-part-1-1lh0</guid>
      <description>&lt;p&gt;A few days ago, I found myself curious about this whole &lt;strong&gt;"vibe coding"&lt;/strong&gt; movement. You know, using AI-powered tools like &lt;a href="https://cursor.sh" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt; or Copilot to speed up the flow of coding, especially in solo or creative projects.&lt;/p&gt;

&lt;p&gt;I wasn’t chasing productivity or building a startup — I just wanted to see how it &lt;em&gt;feels&lt;/em&gt; to build something serious but personal, with AI as a pair.&lt;/p&gt;

&lt;p&gt;So I asked ChatGPT (yes, I even ask AI for the idea) for ideas that would:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simulated the real world project&lt;/li&gt;
&lt;li&gt;Stay safely outside of my current job’s non-compete zone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s when it suggested:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How about building a cleanly architected, multi-tenant SaaS backend in Go?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Boom!! A project name idea was invented:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Multi-Tenant SaaS Backend&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I even had no idea what that meant. X))&lt;/p&gt;

&lt;p&gt;Still, I thought hard about the project and figured I’d better start by abbreviating the name: &lt;strong&gt;MTSB&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
How smart am I.&lt;/p&gt;

&lt;p&gt;And instead of hiding it away, I decided to document every step — one post per task, like a devlog journal.&lt;/p&gt;

&lt;p&gt;This is the first post in what might become a very long devlog series — one post per issue or PR. Basically a public journal of code, architecture, struggle, and vibes.&lt;/p&gt;

&lt;p&gt;So be ready. It could be millions of posts. Or like, five.&lt;/p&gt;

&lt;h2&gt;
  
  
  Day 1 — Setting the Foundation with Docs
&lt;/h2&gt;

&lt;p&gt;Before writing a single line of code, I decided to start with something most devs (myself included) usually skip or leave half-baked:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Why? Because it’s a great way to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clarify what I’m actually building&lt;/li&gt;
&lt;li&gt;Lay out the structure before getting lost in implementation details&lt;/li&gt;
&lt;li&gt;Make the repo portfolio-ready from Day 1&lt;/li&gt;
&lt;li&gt;Make me looks like professional dev :D&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I Wrote (or not written by me)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/harungurubudi/mtsg/blob/develop/README.md" rel="noopener noreferrer"&gt;&lt;code&gt;README.md&lt;/code&gt;&lt;/a&gt; – basic overview, goals, tech stack, and structure&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/harungurubudi/mtsg/blob/develop/docs/architecture.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/architecture.md&lt;/code&gt;&lt;/a&gt; – Clean Architecture overview with Mermaid diagrams&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/harungurubudi/mtsg/blob/develop/docs/data-model.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/data-model.md&lt;/code&gt;&lt;/a&gt; – sketches of key entities and relationships&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/harungurubudi/mtsg/blob/develop/docs/tenant.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/tenant.md&lt;/code&gt;&lt;/a&gt; – a deeper look at the "tenant" concept and how it fits into the app&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/harungurubudi/mtsg/blob/develop/docs/user-journey.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/user-journey.md&lt;/code&gt;&lt;/a&gt; – a rough user flow from signup to project creation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Looks smart isn't it? Unfortunately not. I didn’t write the docs alone. I used &lt;strong&gt;Cursor&lt;/strong&gt; to keep the flow tight and fast. Combined with ChatGPT, it felt less like "writing docs" and more like sketching out a blueprint with a buddy who types faster and doesn’t complain.&lt;/p&gt;

&lt;p&gt;Cursor helped:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Suggest Markdown layout&lt;/li&gt;
&lt;li&gt;Autocomplete repetitive sections&lt;/li&gt;
&lt;li&gt;Keep my thoughts structured and clean&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It was honestly the most painless documentation session I’ve ever had.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Starting with documentation forces you to think before you build. Sounds obvious… but it’s so easy to skip.&lt;/li&gt;
&lt;li&gt;Defining architecture early sets the tone. Even if it changes later, you’ve at least set a direction.&lt;/li&gt;
&lt;li&gt;You don’t need to over-engineer docs. A few &lt;code&gt;.md&lt;/code&gt; (or more precisely &lt;code&gt;.mdc&lt;/code&gt;) files can go a long way when done with intention.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You even don't need to write article like this from scratch. Credit to chatGPT.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Links, If You're Curious
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/harungurubudi/mtsg/issues/1" rel="noopener noreferrer"&gt;Issue #1 – Define the project docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/harungurubudi/mtsg/pull/3" rel="noopener noreferrer"&gt;Pull Request #3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/harungurubudi/mtsg/tree/develop/docs" rel="noopener noreferrer"&gt;docs/ folder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/harungurubudi/mtsg" rel="noopener noreferrer"&gt;&lt;code&gt;mtsg&lt;/code&gt; GitHub Repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Up Next: Domain Modeling
&lt;/h2&gt;

&lt;p&gt;In next session, I’ll start building the core domain layer.&lt;br&gt;&lt;br&gt;
That means defining types like &lt;code&gt;Tenant&lt;/code&gt;, &lt;code&gt;User&lt;/code&gt;, &lt;code&gt;Project&lt;/code&gt;, and laying the foundation for the actual business logic — all while keeping it clean, testable, and cursor-powered.&lt;/p&gt;




&lt;p&gt;Thanks for reading! Stay tuned for more journal entries — and if you’re building something similar, let’s connect! &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Revisiting My Old Neural Network Project in Go</title>
      <dc:creator>Harun Al Rasyid</dc:creator>
      <pubDate>Tue, 01 Jul 2025 08:17:15 +0000</pubDate>
      <link>https://dev.to/hrnlrsyd/revisiting-my-old-neural-network-project-in-go-37ep</link>
      <guid>https://dev.to/hrnlrsyd/revisiting-my-old-neural-network-project-in-go-37ep</guid>
      <description>&lt;p&gt;A few years ago, I built a minimal neural network toolkit in Go: &lt;a href="https://github.com/harungurubudi/rolade" rel="noopener noreferrer"&gt;Rolade – a minimal neural network library written in Go&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It was messy, naïve, and mostly forgotten in my GitHub. The goal was to better understand the internals of forward and backpropagation by implementing everything manually, without relying on external ML libraries. The code worked, but it was very basic and lacked in performance.&lt;/p&gt;

&lt;p&gt;Now, I’m revisiting this project to refactor the code and improve the overall design. Here’s a summary of what I’ve improved:&lt;/p&gt;

&lt;h2&gt;
  
  
  What Was Already Working
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Modular organization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The codebase already had a good separation of concerns: activation functions, loss, optimizers, and network logic were neatly organized into their own modules. This made it relatively easy to extend the library with new features.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Improvement : Parallel Training
&lt;/h2&gt;

&lt;p&gt;To improve training efficiency, I implemented &lt;strong&gt;parallel batch training&lt;/strong&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Training data is split into multiple batches, each processed in a separate goroutine using &lt;code&gt;sync.WaitGroup&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I used &lt;code&gt;sync.Mutex&lt;/code&gt; to safely collect training errors and weight deltas from all batches.&lt;/li&gt;
&lt;li&gt;After all batches are processed, the deltas are merged using a custom &lt;code&gt;mergeDeltas()&lt;/code&gt; function and applied once at the end of the epoch.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Race Condition&lt;/strong&gt;. Initial versions caused data races when multiple goroutines accessed or modified shared weight structures.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Fix&lt;/strong&gt;: Delay all updates until after parallel computation finishes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Locking Can Kill Parallelism&lt;/strong&gt;. Putting locks around weight updates inside each batch makes the process sequential. It removes the benefit of parallelism.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Fix&lt;/strong&gt;: Do all mutation &lt;em&gt;after&lt;/em&gt; goroutines have joined.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unstable Training Without Averaging&lt;/strong&gt;. Summing raw deltas led to unstable error gradient.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Fix&lt;/strong&gt;: Add delta average in &lt;code&gt;mergeDeltas()&lt;/code&gt; to stabilize learning.&lt;/p&gt;




&lt;h3&gt;
  
  
  🚀 Final Result
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Training speed increased (especially for datasets like Iris).&lt;/li&gt;
&lt;li&gt;Accuracy was retained.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧩 Source: &lt;a href="https://github.com/harungurubudi/rolade" rel="noopener noreferrer"&gt;github.com/harungurubudi/rolade&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>machinelearning</category>
      <category>neuralnetwork</category>
    </item>
  </channel>
</rss>
