DEV Community

JihadBadran
JihadBadran

Posted on

Cursor + LLMs: My Dev Journey from "Wow!" to "WTF?" to "Wait, I Got This!"

The Honeymoon: Pure Magic

First week with Cursor? Mind-blown.

"Hey Cursor, make me a dropdown menu with Tailwind."
BAM - perfect code appears.

Productivity through the roof. Documentation lookups? Gone. Stack Overflow visits? Plummeted.

It was like having a 10x developer bestie who never needed coffee breaks or complained about my variable naming.

Reality Check: When Complexity Kicks In

Then our healthcare app got complicated. Simple stuff? Still magic. Complex features? Complete dumpster fire.

Take our ActionButtons.tsx component:

const handleStartClick = () => {
  setLocalLoading(true);
  handleStart();
};
Enter fullscreen mode Exit fullscreen mode

Cursor nailed it. But ask it about offline recording sync with IndexedDB and ServiceWorkers? Chaos.

Real conversation:

Me: "How do I store encrypted audio blobs in IndexedDB?"

Cursor: "Easy! Just use browser.storage.encryptedLocal.set()!"

Me: "That's... not a real API."

Cursor: "I meant window.crypto.encryptedStorage!"

Me: "Still made up."

Cursor: "...I'll see myself out."

It hallucinated APIs faster than I could Google them. Like asking a drunk friend for directions - confidently wrong at every turn.

The Breakthrough: Documentation-First Dev

Then it hit me. I was using it wrong!

Instead of "write this complex feature," I tried:

  1. Use Cursor to draft requirements
  2. Generate a PRD
  3. Create architecture docs
  4. Then implement code

Our offline recording feature became the test case.

Started with: "We need offline recording capability"

Ended with a detailed PRD:

## 2.1 Business goals
- Increase user retention by providing uninterrupted service
- Reduce data loss during patient encounters
- Improve reliability in varied network environments
Enter fullscreen mode Exit fullscreen mode

Then an architecture doc with actual useful stuff:

## 5.1 IndexedDB Schema (version 1)
db: offline_recordings_v1

ObjectStore: recordings (keyPath: "id")
• id: string (uuid)
• userId: string (Cognito `sub`)
• encounterId: string
...
Enter fullscreen mode Exit fullscreen mode

The result? Implementation was surprisingly smooth. What would've been weeks of planning compressed into days.

Test-Driven AI: Because "It Works On My Machine" Doesn't Cut It

But then came the dreaded question from our QA lead: "How do we test this offline monster?"

My first instinct was to throw my laptop out the window and change careers. But instead, I tried Cursor again.

Conversation went something like:

Me: "How do I test a Service Worker that handles IndexedDB transactions?"

Cursor: "With prayers and sacrifices to the testing gods!"

Me: "Seriously."

Cursor: "Fine. Let's use Workbox testing utilities and mock IndexedDB."

So we evolved our workflow:

  1. Requirements → PRD → Architecture → Test Plan → Code → Actual Tests

The test plan became another crucial doc:

## Unit Tests
1. NetworkStatusService
   - Should detect when browser goes offline
   - Should emit events when status changes

2. EncryptedDB
   - Should encrypt recordings before storage
   - Should properly handle storage quota errors
Enter fullscreen mode Exit fullscreen mode

Here's where it got weird - we used Cursor to generate test cases BEFORE writing implementation code. Like asking someone to grade a test you haven't taken yet.

Example:

test("should properly encrypt recordings before storage", async () => {
  const mockBlob = new Blob(["test audio"], { type: "audio/webm" });
  const service = new EncryptedDBService();

  const id = await service.storeRecording({
    encounterId: "123",
    blob: mockBlob,
    durationSec: 30
  });

  // Get the raw IndexedDB entry
  const rawEntry = await getRawIndexedDBEntry("recordings", id);

  // Should NOT contain the original audio content
  const text = await blobToText(rawEntry.blob);
  expect(text).not.toContain("test audio");
});
Enter fullscreen mode Exit fullscreen mode

Cursor actually helped debug this test before the implementation existed! It was like having a fortune teller for bugs.

The E2E Chronicles: Testing Like Real Users (But With Robots)

Unit tests were fine, but offline features need E2E tests that simulate actual network failures.

This led to the greatest Cursor conversation ever:

Me: "How do I simulate network outage in Playwright?"

Cursor: "You can use page.route() to intercept all requests and make them fail."

Me: "But what about navigator.onLine?"

Cursor: "Right... you need to mock that too with page.evaluate()"

Me: "But ServiceWorker..."

Cursor: "I see your point. Let's get crazy."

The result? A test that:

  1. Started recording
  2. Cut network connection
  3. Continued recording
  4. Restored connection
  5. Verified sync happened
test('should sync recording after reconnection', async ({ page }) => {
  // Start normal
  await page.goto('/encounter/123');
  await page.getByRole('button', { name: 'Start' }).click();

  // Record a bit
  await page.waitForTimeout(3000);

  // OH NO NETWORK DOWN 😱
  await page.context().setOffline(true);

  // Keep recording in the darkness
  await page.waitForTimeout(5000);

  // Speak into the void
  await page.evaluate(() => {
    console.log("Testing offline recording...");
  });

  // End recording while offline
  await page.getByRole('button', { name: 'End' }).click();

  // Expect offline indicator to show
  await expect(page.getByTestId('offline-indicator')).toBeVisible();

  // THE INTERNET IS BACK! 🎉
  await page.context().setOffline(false);

  // Did it sync?
  await expect(page.getByText('Synchronization complete')).toBeVisible({ timeout: 10000 });
});
Enter fullscreen mode Exit fullscreen mode

My QA lead read this test and actually smiled. First time ever. Might frame that moment.

AI-Generated Mocks: When Fake Data Gets Too Real

We hit another problem - realistic test data. Our test recordings were all "testing 1 2 3" which doesn't simulate real medical conversations.

So I asked Cursor to generate medical conversation mocks:

Me: "Generate a mock patient-doctor conversation about diabetes management"

Cursor went full method actor:

Dr: "Your A1C levels have improved since our last visit, Mrs. Johnson."
Patient: "I've been following that diet you suggested, but I still have questions about the medication schedule."
Dr: "I understand. Let's review the insulin timing again..."
Enter fullscreen mode Exit fullscreen mode

Our test recordings suddenly got eerily realistic. QA reported a bug where "the doctor in the test is more empathetic than our actual doctors." Not sure if that's a code issue or existential crisis material.

From Architecture to Tasks: When Your AI Becomes a Project Manager

The next evolution in our workflow? Breaking down that beautiful architecture doc into actual sprint-ready tasks.

Our PM was skeptical: "So you want to use AI to turn your architecture doc into JIRA tickets?"

Yes. Yes, I did.

I fed the architecture doc to Cursor:

Me: "Break this architecture into sprint-ready tasks with estimates, complexity, and dependencies."

Cursor morphed into the PM we all wish we had:

# Sprint Tasks: Offline Recording Sync

## Epic 1: Core Infrastructure
- **Task 1.1**: Set up IndexedDB schema with encryption support
  - Priority: High
  - Complexity: Medium
  - Estimate: 1 day
  - Dependencies: None
  - Assignee: TBD

- **Task 1.2**: Implement NetworkStatusService
  - Priority: High
  - Complexity: Low
  - Estimate: 0.5 days
  - Dependencies: None
  - Assignee: TBD

## Epic 2: Service Worker Implementation
- **Task 2.1**: Register Service Worker with proper scope
  - Priority: High
  - Complexity: Low
  - Estimate: 0.5 days
  - Dependencies: None
  - Assignee: TBD

- **Task 2.2**: Implement BroadcastChannel communication
  - Priority: High
  - Complexity: Medium
  - Estimate: 1 day
  - Dependencies: Task 2.1
  - Assignee: TBD
Enter fullscreen mode Exit fullscreen mode

Our PM stared at this, then at me, then back at the task list. "These... are actually good estimates."

I know, right? AI task estimates are mysteriously more accurate than human ones. No more "that's a 2-point story" that actually takes 2 weeks.

We generated 32 tasks from the architecture doc, complete with acceptance criteria:

### Task 1.1: Set up IndexedDB schema
- **Acceptance Criteria**:
  - ✓ Create database with proper version management
  - ✓ Implement recordings store with required fields
  - ✓ Add indexes for userId and status
  - ✓ Include encryption/decryption methods
  - ✓ Handle storage quota errors gracefully
Enter fullscreen mode Exit fullscreen mode

My favorite part? We asked Cursor to analyze dependencies and generate a critical path:

Critical Path: 1.1 → 2.2 → 3.3 → 4.2 → 5.1
Minimum Implementation Time: 5 days
Risks: Task 3.3 (Encryption Logic) has highest complexity
Enter fullscreen mode Exit fullscreen mode

Our architect looked at this and whispered, "It's basically doing my job."

I just nodded. No one needed to know that Cursor also drafted my performance review self-assessment.

Final Form: A Workflow That Actually Works

Now my fully evolved workflow:

  1. Requirements → PRD → Architecture → Test Plan → Task Breakdown → Implementation → Actual Tests
  2. Tell Cursor specifically what I'm building at each stage
  3. Get Cursor to generate edge cases I'd never think of
  4. Always verify against docs (trust issues are healthy!)

Best part? I could import those tasks directly into JIRA with MCP. The team thought I'd spent a weekend meticulously planning. Nope, just me and my AI buddy talking about IndexedDB for 20 minutes.

During standup, I'd casually check off tasks: "Finished the BroadcastChannel implementation, moving on to offline storage."

No one suspected my secret weapon was generating daily status updates too:

Me: "Write my standup update for implementing the ServiceWorker sync functionality"

Cursor: "Yesterday: Completed ServiceWorker registration and basic message passing.
Today: Working on background sync functionality and retry logic.
Blockers: Need clarification on max retry attempts from product team."

It was technically true. I was doing those things. Cursor just made me sound more professional than my usual "I fought with IndexedDB all day and now I hate everything."

The Moral of the Story

Cursor isn't a replacement coder - it's dev thought process steroids. Don't ask it to solve your complex problem. Ask it to help you THINK ABOUT your complex problem, TEST your complex problem, ORGANIZE your complex problem, then fix the inevitable bugs in your complex problem.

And honestly? The best part is using it to generate commit messages. "Fix IndexedDB transaction error on Safari" becomes "Tamed Safari's rebellious IndexedDB implementation before it could corrupt more user data and probably steal your lunch too."

AI-generated humor > my humor. And I'm totally fine with that.

Top comments (0)