DEV Community

Harun Al Rasyid
Harun Al Rasyid

Posted on

Building Cursor Powered App: A Devlog Series, Powered by Cursor (Part 3) - Laying the Foundation with Packages

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.

  • They don't flash UI.
  • They don't talk HTTP. But they are everything that makes the rest of the app possible.

But first, a confession.
I did something bold. Brave. Maybe even a little impulsive.

I subscribed to Cursor Pro

Yes, I paid actual money. And I have zero regrets.

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)).

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.


The Foundation: Packages

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.

Redis Adapter

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 redisClient.Set(...) all over your app.

# 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 
Enter fullscreen mode Exit fullscreen mode

Token Provider

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).

I also introduced something fun: LinkedToken. 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?

Error

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

How?

  • Internal errors are wrapped with my beloved stackerror package. They bubble up with stack traces and observability in mind.
  • Business errors are returned as value objects and interpreted at the presentation layer.

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


Bonus: Cursor Rule Files Are a Superpower

With Cursor, I rely heavily on .mdc files to establish patterns and expectations.

For example:

# 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 
Enter fullscreen mode Exit fullscreen mode

It's not just prompting, it's like training your AI teammate on your architectural beliefs.


That's it for today!
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.

Links, if you're curious


Next Up

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

We'll answer questions like:

What actually happens during a login?

How do refresh tokens work with Redis?

Can you TOTP your way into greatness?

Stay tuned, the domain is strong with this one

Top comments (0)