How "Separation of Concerns" turned Cursor into a Senior Architect (and gave me 100% One-Shot features)
By ShadowVibe354 · ISSUE · About Cursor
This turned into a Cursor appreciation post, but it deserves it as I feel like what I have been able to build in a couple of months with my amateur coding background (decades old, rusty to say the least) is nothing short of amazing.
I’ve been building a somewhat complex sports-tech app (React Native/Expo/Supabase) and I just hit a milestone: a full week of 100% one-shot implementations for complex features. What started as a simple idea to keep track of a teams playing time became a multi-platform, multi-access layered insights, analytics, and recommendations platform where coaches and fans can see teams insights in parallel, with robust monetization options across account types and platforms (https://www.wiespeelter.nl).
I realized the problem wasn't the LLM—it was my architecture. If your logic leaks everywhere, the AI has to guess. If your architecture has "clear streets," the AI just follows the map. It resulted in a painful week of refactoring, but in the end it was worth it.
Here is the **Layered Strategy** I'm using to keep Cursor in "Senior Architect" mode:
### 1. The Infrastructure Layer (`/lib`)
I stopped letting Cursor import third-party libs directly into components. Everything goes through a centralized "Gateway".
* **The Logic:** Take `lib/haptics.ts`. It wraps `expo-haptics` with platform guards (web vs. native) and checks a global user preference from the database.
* **The Win:** When I asked for a "Global Haptic Toggle" in Settings, Cursor didn't have to hunt. It updated the service, and the entire app—which was already consuming that service—was instantly synced.
### 2. The Service & Access Layer (`/services` & `/hooks`)
This is where the "heavy lifting" lives, completely decoupled from the UI.
* **Services:** Pure async functions (e.g., `deleteMatchWithLogs(id)`). They handle the Supabase calls and cascading deletes.
* **Access Layer:** This is the brain. Custom hooks like `useHistoryData()` determine **permissions** based on the user's role (e.g., `canEdit: true` for owners, `false` for fans).
* **Why it works:** My UI components are "dumb." They just ask the Access Layer: *"Am I allowed to show a delete button?"* and call the Service if clicked. Cursor can't accidentally break business logic while changing a layout because the logic isn't in the layout.
### 3. The Component Layer (`/components/shared`)
Instead of raw Modals or Alerts, we use "Opinionated Components." We built a shared `ConfirmDialog` with strict variants (`danger`, `warning`, `default`).
* A `danger` variant automatically knows to use red styling and trigger a `heavy` haptic vibration. Cursor just picks the variant; the system handles the rest.
### 4. The "Constitution" (`.cursorrules`)
This is the secret sauce. I’ve baked my architectural "laws" into the `.cursorrules`. It’s not a prompt; it’s a policy manual that Cursor reads before every task:
# UI Interaction & Feedback Policy
- **Destructive action?** -> Must use `ConfirmDialog` with `variant="danger"`.
- **Toggle flipped?** -> Trigger `hapticFeedback.selection()`.
- **Blocked action (Nav-lock)?** -> `hapticFeedback.error()` + Toast.
- **Hierarchy:** No haptics on chevrons or tabs. Keep the "tactile energy" for goals and subs.
- **Constraints:** Never import `expo-haptics` outside of `lib/haptics.ts`.
#The Takeaway
Architecture is the ultimate prompt. By spending time on the Separation of Concerns—Infrastructure, Services, Access, and Presentation—I’ve created a codebase where it’s actually harder for the AI to make a mistake than to do it right.
Ps. Using I and We interchangeably as Cursor at this point really feels like a partner 😀
9 upvotes · 3 comments
Comments (3)
SolarSurfer919: I mean cursor is not the senior architect. You just did that yourself and instructed cursor. I have a similar experience. The vibe-coding gang will not like this.
NeonFlux225: idk why people are overly obsessed with "one shot" implementations. That's not how software works and even if you can pull it off a couple times it always endup collapsing.
The important thing is that you setup the guardrails in a way you can have steering conversations with the model so you can ev
EpicDrift889: Can you share or distill some of the prompts you used to refactor into this structure?
More discussions about Cursor on HonestUse