Revelry

AI-Driven Custom Software Development

Cursor ide with icons.

How Developers Use Cursor AI: 6 Easy Tasks Beyond Code Generation

In the ever-evolving, fast-paced world of AI coding agents, the tools that are on offer are getting better and better seemingly every day. As I remind friends who aren’t as up to speed on the latest news and trends, AI is as dumb as it will ever be right now… and now … and now again.


And while they’ve gotten quite good at agentic coding — using natural language to tell the agent what you want to build and it will build it — I find that I’m using it instead for an ever-growing list of mundane (yet extraordinarily useful) tasks.
Here are some of the ways I use Cursor – my IDE of choice – not to simply write code but to make my job writing code easier.

Where is the file that renders this template?

As a design engineer who focuses heavily on the front-end of our applications at Revelry, I’m familiar enough with the router file in our projects to find exactly what I’m looking for, however, it still takes me out of my flow when I need to fix something simple on a page; I have to wade through a router file just to find the html template that renders it.

With Cursor, I paste a url from the browser into the chat, ask what renders it, and voila, I have a clickable link to the file.
Now, with the recent addition of the browser tab tool in Cursor, we can take this one step further — click a button with the inspector and ask, what is the line that renders this button? It’s a small but time-saving prompt that I find myself using regularly.

Example Prompt

What file handles the template for http://localhost:4000/dashboard/projects/123/analytics?

Cursor’s Response

That route is handled by:
- LiveView: lib/my_app_web/live/dashboard/project_analytics_live.ex
- Template: lib/my_app_web/live/dashboard/project_analytics_live.html.heex

The route is defined in lib/my_app_web/router.ex at line 45:
scope "/dashboard", MyAppWeb.Dashboard do
  pipe_through [:browser, :require_auth]

  live "/projects/:project_id/analytics", ProjectAnalyticsLive, :show
end

Would you like me to open the LiveView file?

Smart Seeds

As the use cases for our products grow, so too do the variety of data points we’re pulling into the UI. And while “Test Short Name” and “Test Really Long Name to Test for the table to make sure it truncates” can be great ways to push your UI’s limits, they aren’t the most helpful names, and it’s time consuming to get them into the system.
But what if you could call over your intern and tell them to don their data entry cap and add 100 names of varying lengths to the database for you? And what if they could do it in less than a minute?


With an AI assistant, that’s exactly what you get; tell Cursor to seed your local database with X number of widgets, and within moments — and after some inevitable back-and-forth to nail specific, intricate queries — you have a full library of widgets to test out sorting and filtering of your tables.

Example Prompt

Create a seeds file for our products table that includes 50 diverse products with:
- Product names of varying lengths (some short like "Mug", some long like "Professional Stainless Steel Kitchen Mixer")
- Prices ranging from $5 to $500
- Categories: electronics, home, clothing, books, toys
- Stock levels: some out of stock (0), some low (1-5), some high (100+)
- Some with images, some without - get these from the Unsplash API
- Created dates spread over the past 2 years

Cursor’s Response

# priv/repo/seeds/products.exs
alias MyApp.Repo
alias MyApp.Catalog.Product

products = [
  %{
    name: "Mug",
    price: 1299,
    category: "home",
    stock: 0,
    image_url: "https://example.com/mug.jpg",
    inserted_at: DateTime.add(DateTime.utc_now(), -730, :day)
  },
  %{
    name: "Professional Stainless Steel Kitchen Mixer with 12 Speed Settings and Bowl",
    price: 29999,
    category: "home",
    stock: 3,
    image_url: nil,
    inserted_at: DateTime.add(DateTime.utc_now(), -240, :day)
  }
  # ... [48 more varied products]
]

Enum.each(products, fn product_attrs ->
  %Product{}
  |> Product.changeset(product_attrs)
  |> Repo.insert!()
end)

How should I QA this ticket?

At Revelry, engineers and design engineers are tasked with shepherding our tickets across the board and helping each other do the same (“Be Excellent to Each Other” is one of our core values after all). But I can find myself pretty lost in the QA column of the board, especially when there are a lot of unfamiliar back-end changes introduced in the branch that needs QA.
And that’s where I’ll jump into chat and ask Cursor to craft a QA checklist by comparing the branch in question to the app’s main branch. Not only does it thoroughly cover the feature’s intended goals, but it provides tons of edge cases I may never have thought to cover otherwise.

Example Prompt

Compare the feature/user-permissions branch to develop and create a comprehensive QA checklist for me to test before this ships.

Cursor’s Response

QA Checklist for feature/user-permissions

Core Functionality:
- [ ] Admin can create new roles
- [ ] Admin can assign permissions to roles
- [ ] Users with new roles see appropriate menu items
- [ ] Users without permissions get redirected with flash message on restricted pages

Edge Cases to Test:
- [ ] What happens if user's role is deleted while they're logged in?
- [ ] Can a user be assigned multiple roles? Test permission conflicts
- [ ] Test with user who has NO roles assigned
- [ ] Try accessing /admin/roles directly via URL as non-admin
- [ ] Test role creation with special characters in name
- [ ] Create role with same name as existing role (should fail uniqueness constraint)

Database/Backend:
- [ ] Check migration runs cleanly on fresh DB
- [ ] Verify indexes exist on roles and user_roles tables
- [ ] Test rollback scenario
- [ ] Check that foreign key constraints work (can't delete role with assigned users)

LiveView/UI:
- [ ] Role names truncate properly in dropdown (test with 100+ char name)
- [ ] Loading states show when assigning roles (test with push_event)
- [ ] Success/error messages appear via put_flash
- [ ] Test on mobile viewport
- [ ] Verify live patches update URL correctly
- [ ] Test that PubSub broadcasts update other connected clients

The changes modified 12 files including the User schema, so also test:
- [ ] User profile page still loads
- [ ] User search still works in LiveView
- [ ] User deletion still works
- [ ] Preloading associations doesn't cause N+1 queries

Reverse-engineering obscure API responses

I focus on how a set of data looks when displayed to the user, but sometimes I’ll end up in back-end code, working with a third-party API that has sparse or outdated documentation. These responses can be nebulous, confusing and less than helpful to unfamiliar users. But when I find myself in this situation, I can now simply paste that response into the chat and ask Cursor to explain the data structure, identify which fields are relevant for your use case, and spot any gotchas or deprecated fields I should avoid. And the response can be enlightening.

Example prompt

I'm integrating with a payment processor API and got this response back. Can you explain the structure and tell me which fields I should store in our database for order reconciliation?

{
  "txn_id": "TXN_8675309_ABC",
  "merchant_ref": "ORD-2024-1234",
  "amt": 4599,
  "amt_curr": "USD",
  "status": "captured",
  "status_code": 100,
  "card_last4": "4242",
  "card_brand": "visa",
  "avs_result": "Y",
  "cvv_result": "M",
  "settled": false,
  "settled_at": null,
  "fee_amt": 164,
  "net_amt": 4435,
  "metadata": {
    "ip": "192.168.1.1",
    "user_agent": "Mozilla...",
    "risk_score": 12
  },
  "created_at": "2024-11-15T14:32:01Z",
  "_legacy_id": "12345",
  "_api_version": "2023-08"
}

Cursor’s Response

Here's what each field means and my recommendations:

Critical fields to store:
- txn_id: Unique transaction ID from payment processor (store this!)
- merchant_ref: Your order ID that you sent them
- amt: Amount in cents (4599 = $45.99)
- status: Current transaction status
- created_at: When transaction was created

Useful for reconciliation:
- settled: Whether funds have actually transferred (false means pending)
- settled_at: When funds transferred to your account
- fee_amt: Their fee in cents ($1.64)
- net_amt: What you actually receive ($44.35)

For customer service:
- card_last4 & card_brand: For identifying the payment method

Ignore these:
- _legacy_id: Has underscore prefix, likely deprecated
- _api_version: Not needed unless you're debugging
- avs_result/cvv_result: Already validated if status is "captured"
- metadata.user_agent/ip: Privacy concern, only store if legally required

Gotchas I spotted:
⚠️ Amount is in cents, not dollars
⚠️ settled:false means money hasn't hit your account yet
⚠️ Fields with underscore prefixes are likely deprecated
⚠️ They're on API version 2023-08, check if there's a newer version

Naming things (the hardest task in software development)

Struggling to name a component, variable, or function? Describe what it does to Cursor and get 10 suggestions that follow your project’s naming conventions.

Example Prompt

I need to name a LiveView component. It displays a list of recent user activities, but it also filters out certain activity types based on user preferences, groups activities by date, and has a "load more" button. We use PascalCase for LiveView components and prefer descriptive names. Give me 10 options.

Cursor’s Response

Here are 10 naming options, ordered from most specific to more general:

Most Descriptive:
1. FilteredActivityFeedLive
2. PersonalizedActivityListLive
3. CustomizableActivityTimelineLive
4. UserActivityFeedWithFiltersLive

Balanced:
5. ActivityFeedLive
6. ActivityTimelineLive
7. RecentActivityListLive
8. UserActivityStreamLive

More General:
9. ActivityPanelLive
10. ActivityViewLive

My recommendation: FilteredActivityFeedLive or PersonalizedActivityListLive

Why: They communicate the key differentiator (filtering/personalization) while staying concise. "Feed" implies chronological + load more pattern. If you already have other filtered LiveViews in your codebase, I'd go with PersonalizedActivityListLive to avoid confusion.

If this component might be reused with different filtering logic later, consider the more general ActivityFeedLive and pass filtering configuration as assigns.

Note: The "Live" suffix is Phoenix convention for LiveView modules, distinguishing them from function components.

Accessibility auditor

There are a lot of considerations to account for when building accessible components for our UI, and some of them can easily fall through the cracks. Before I push up a new component or variant, I’ll ask Cursor to audit it for accessibility and provide suggestions on how best to make this component accessible to all of our users.

Example Prompt

Review this LiveView component for accessibility issues:

<div class="modal" phx-click="close_modal">
  <div class="modal-content">
    <span class="close-btn" phx-click="close_modal">×</span>
    <div class="modal-title">Delete User</div>
    <div>Are you sure you want to delete this user?</div>
    <div class="actions">
      <div class="btn cancel" phx-click="close_modal">Cancel</div>
      <div class="btn delete" phx-click="delete_user">Delete</div>
    </div>
  </div>
</div>

Cursor’s Response

Accessibility Issues Found:

Critical:
🔴 Buttons are <div> elements - screen readers won't announce them as clickable
🔴 Close button (×) has no text alternative for screen readers
🔴 Modal has no ARIA role or labels
🔴 No keyboard navigation - users can't Tab to buttons or press Escape to close
🔴 No focus trap - Tab key will navigate to elements behind modal
🔴 phx-click on outer div will close modal if user clicks background, but this isn't keyboard accessible

Important:
🟡 No focus management - should focus first button when modal opens
🟡 Modal title should use proper heading element (<h2>)
🟡 Destructive action (Delete) should require confirmation or have warning styling
🟡 No LiveView hook for handling Escape key

Recommended fixes:

<div 
  role="dialog" 
  aria-labelledby="modal-title"
  aria-modal="true"
  phx-click="close_modal"
  phx-window-keydown="close_modal"
  phx-key="escape"
  id="delete-user-modal"
  phx-hook="FocusTrap"
>
  <div class="modal-content" phx-click="stop_propagation">
    <button 
      class="close-btn" 
      phx-click="close_modal"
      aria-label="Close dialog"
      type="button"
    >
      ×
    </button>
    <h2 id="modal-title" class="modal-title">Delete User</h2>
    <p>Are you sure you want to delete this user?</p>
    <div class="actions">
      <button class="btn cancel" phx-click="close_modal" type="button">
        Cancel
      </button>
      <button class="btn delete" phx-click="delete_user" type="button">
        Delete
      </button>
    </div>
  </div>
</div>

Additional recommendations:
- Create a FocusTrap hook in app.js to handle focus management
- Add phx-hook="AutoFocus" to first button to focus on mount
- Return focus to trigger element when modal closes (store in socket assigns)
- Consider adding aria-describedby for the warning text
- Use phx-click="stop_propagation" on modal-content to prevent bubbling

Example FocusTrap hook:
Hooks.FocusTrap = {
  mounted() {
    this.focusableEls = this.el.querySelectorAll('button, [href], input, select, textarea');
    this.firstFocusable = this.focusableEls[0];
    this.lastFocusable = this.focusableEls[this.focusableEls.length - 1];
    this.firstFocusable.focus();
  }
}

AI tools like Cursor can really make your day-to-day coding tasks a lot smoother and more fun. Whether you’re hunting down files, filling your database with useful test data, compiling thorough QA checklists, or even coming up with names for your components, agents can handle the heavy lifting and let you focus on the creative tasks instead of getting bogged down in the mundane stuff.