<?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: alejandraarochaovalles</title>
    <description>The latest articles on DEV Community by alejandraarochaovalles (@alejandraarochaovalles).</description>
    <link>https://dev.to/alejandraarochaovalles</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4113914%2Fc9839122-e1a2-4af3-93b6-aec4d7ac0ef7.png</url>
      <title>DEV Community: alejandraarochaovalles</title>
      <link>https://dev.to/alejandraarochaovalles</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alejandraarochaovalles"/>
    <language>en</language>
    <item>
      <title>How I Directed an AI Agent Through 3 Real Architecture Decisions, and What I Learned</title>
      <dc:creator>alejandraarochaovalles</dc:creator>
      <pubDate>Mon, 07 Sep 2026 12:29:35 +0000</pubDate>
      <link>https://dev.to/alejandraarochaovalles/how-i-directed-an-ai-agent-through-3-real-architecture-decisions-and-what-i-learned-1p08</link>
      <guid>https://dev.to/alejandraarochaovalles/how-i-directed-an-ai-agent-through-3-real-architecture-decisions-and-what-i-learned-1p08</guid>
      <description>&lt;p&gt;In two weeks, I built Retro Dynamics Agent, an app that generates retrospective activities for teams, facilitates them on a real-time collaborative board, and turns the outcomes into Jira or Azure DevOps tickets.&lt;/p&gt;

&lt;p&gt;I built it working with an AI coding agent, Claude Code, throughout almost the entire process: design, implementation, production debugging, and documentation.&lt;/p&gt;

&lt;p&gt;I do not want to tell another “I used AI and it wrote the code for me” story. We have heard that one enough.&lt;/p&gt;

&lt;p&gt;What I found more interesting were the parts of the project where there was no obvious answer in a tutorial, and how the work was divided in those situations.&lt;/p&gt;

&lt;p&gt;I defined the constraints and made the underlying decisions. The agent proposed concrete technical solutions and implemented them. Then the responsibility for verifying that everything actually worked, not just that it compiled, came back to me.&lt;/p&gt;

&lt;p&gt;Here are three examples from the project.&lt;/p&gt;

&lt;p&gt;1.- Connecting to Jira without server-side sessions or frontend memory&lt;/p&gt;

&lt;p&gt;I wanted any team to be able to connect its own Jira account through OAuth, instead of relying on a global token that only I could configure.&lt;/p&gt;

&lt;p&gt;The problem was that my application runs entirely on serverless functions. Nothing stays in memory between requests, and the frontend does not maintain its own state either.&lt;/p&gt;

&lt;p&gt;No localStorage. No router.&lt;/p&gt;

&lt;p&gt;An OAuth login means leaving the application, authenticating with Atlassian, and then coming back.&lt;/p&gt;

&lt;p&gt;But coming back to what, if nothing remembers which screen you were on?&lt;/p&gt;

&lt;p&gt;Before touching the code, I asked the agent to create a complete implementation plan, including the files that would need to change, the design decisions, and the scope.&lt;/p&gt;

&lt;p&gt;I reviewed that plan as if it were a pull request from another developer.&lt;/p&gt;

&lt;p&gt;I made decisions such as:&lt;/p&gt;

&lt;p&gt;For now, only Jira would use OAuth. Azure DevOps would keep its manual token flow because setting up OAuth there is considerably more involved.&lt;/p&gt;

&lt;p&gt;Tokens would be encrypted before being stored in the database, never saved as plain text.&lt;/p&gt;

&lt;p&gt;And the existing manual connection form would remain available as a fallback instead of being removed.&lt;/p&gt;

&lt;p&gt;The agent solved the specific technical problem by proposing a signed HMAC state parameter.&lt;/p&gt;

&lt;p&gt;Besides validating the OAuth callback, that state contains the ID of the active session.&lt;/p&gt;

&lt;p&gt;Because the frontend does not remember anything on its own, carrying that session ID through the OAuth round trip is what allows the application to restore the correct screen when the user returns from Atlassian.&lt;/p&gt;

&lt;p&gt;I verified the implementation myself in production.&lt;/p&gt;

&lt;p&gt;That is where I found a bug that no code review would have caught.&lt;/p&gt;

&lt;p&gt;Adding a single dependency brought down the entire application, including the health check.&lt;/p&gt;

&lt;p&gt;The reason was that Vercel was installing dependencies using a different lockfile from the one I thought it was using, even though a comment in my own code had been claiming the opposite for months.&lt;/p&gt;

&lt;p&gt;I found the problem by reading real production logs in the dashboard, not by analyzing the code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgybev96u4utfsxpy1ssa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgybev96u4utfsxpy1ssa.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2.- The real-time board: why I did not use the database I already had&lt;/p&gt;

&lt;p&gt;The board needs to synchronize note dragging, votes, and participant cursors in real time.&lt;/p&gt;

&lt;p&gt;I already had Postgres through Supabase, so using the same provider’s real-time system would have been the simplest option from an integration perspective.&lt;/p&gt;

&lt;p&gt;No additional synchronization provider. Less infrastructure.&lt;/p&gt;

&lt;p&gt;I decided not to use it.&lt;/p&gt;

&lt;p&gt;The board is free-form, closer to Miro than to a fixed-column board.&lt;/p&gt;

&lt;p&gt;For that kind of canvas, Supabase Realtime would have required me to implement more synchronization and conflict-handling logic than I wanted to own.&lt;/p&gt;

&lt;p&gt;With free dragging, live cursors, and concurrent edits, two people trying to interact with the same object at the same time is not an edge case. It is something that will happen regularly.&lt;/p&gt;

&lt;p&gt;Liveblocks is specifically designed around collaborative canvas-style experiences.&lt;/p&gt;

&lt;p&gt;I accepted the cost of maintaining two providers rather than building and maintaining that synchronization layer myself.&lt;/p&gt;

&lt;p&gt;The agent proposed the synchronization model:&lt;/p&gt;

&lt;p&gt;Liveblocks is the source of truth while the session is active.&lt;/p&gt;

&lt;p&gt;When the session ends, the final state is persisted to Postgres in a single operation instead of writing to the database on every movement.&lt;br&gt;
The agent also corrected an assumption I had made early on.&lt;/p&gt;

&lt;p&gt;I originally thought notes and groups needed separate database tables.&lt;/p&gt;

&lt;p&gt;They did not.&lt;/p&gt;

&lt;p&gt;They are generated and consumed together, never independently, so separating them would have introduced complexity without giving me any real benefit.&lt;/p&gt;

&lt;p&gt;Verifying this architecture required more than reading the code.&lt;/p&gt;

&lt;p&gt;At that point I did not have a convenient real Liveblocks environment available to test interactively from the browser.&lt;/p&gt;

&lt;p&gt;So we created a script that connects two real Liveblocks clients without a browser.&lt;/p&gt;

&lt;p&gt;One client makes a change.&lt;/p&gt;

&lt;p&gt;The second client must receive it immediately.&lt;/p&gt;

&lt;p&gt;That test validated the architecture better than any code review could.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjulqhhdd32i1m20h3ygm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjulqhhdd32i1m20h3ygm.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3.- Voting without people accidentally overwriting each other&lt;/p&gt;

&lt;p&gt;During the voting phase, any participant can vote for a note or remove their vote at any time.&lt;/p&gt;

&lt;p&gt;Several people can do this simultaneously.&lt;/p&gt;

&lt;p&gt;If the vote total were stored as a single shared counter, concurrent writes could overwrite each other.&lt;/p&gt;

&lt;p&gt;I decided that voting should be reversible and unlimited per participant.&lt;/p&gt;

&lt;p&gt;That sounds like a product decision, and it is.&lt;/p&gt;

&lt;p&gt;But it completely changes the data model.&lt;/p&gt;

&lt;p&gt;Instead of everyone updating the same counter, each participant writes only their own list of voted notes.&lt;/p&gt;

&lt;p&gt;The total for a note is calculated by counting how many participant lists contain that note.&lt;/p&gt;

&lt;p&gt;No two participants ever compete to write the same value.&lt;/p&gt;

&lt;p&gt;Instead of solving a concurrency conflict, the model removes the conflict altogether.&lt;/p&gt;

&lt;p&gt;When the session closes, only the final vote count is persisted. The system does not keep a record of who voted for what.&lt;/p&gt;

&lt;p&gt;The counting logic was tested as standalone functions with no dependency on Liveblocks types.&lt;/p&gt;

&lt;p&gt;That means the correctness of the calculation can be verified without needing a real-time connection running at all.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3dbts7001vhagrpggifu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3dbts7001vhagrpggifu.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What kept repeating across all three decisions&lt;/p&gt;

&lt;p&gt;The valuable part was never that the AI could write the code.&lt;/p&gt;

&lt;p&gt;The same pattern appeared every time.&lt;/p&gt;

&lt;p&gt;Before implementing any non-trivial feature, we discussed the architecture first.&lt;/p&gt;

&lt;p&gt;I defined the constraints, chose which trade-offs were acceptable, and decided which risks I was willing to take.&lt;/p&gt;

&lt;p&gt;The agent was consistently good at proposing and implementing solutions within those constraints.&lt;/p&gt;

&lt;p&gt;But my work increasingly moved away from translating decisions into syntax and toward deciding what to build, which trade-offs to accept, and what evidence I needed before I could say that something actually worked.&lt;/p&gt;

&lt;p&gt;In the OAuth integration, that evidence came from production logs.&lt;/p&gt;

&lt;p&gt;In the real-time architecture, it came from two real connected clients.&lt;/p&gt;

&lt;p&gt;In the voting model, it came from isolated functions that could be tested independently.&lt;/p&gt;

&lt;p&gt;The more capable coding agents become, the less interesting “who wrote the code?” becomes as a question.&lt;/p&gt;

&lt;p&gt;The more interesting question is:&lt;/p&gt;

&lt;p&gt;Who defined the constraints, chose the trade-offs, and decided what counted as proof that the system worked?&lt;/p&gt;

&lt;p&gt;Everything from this project is documented in the repository, including the production incident and the root cause once I found it.&lt;/p&gt;

&lt;p&gt;GitHub - alejandraarochaovalles/retro-dynamics-agent&lt;br&gt;
Contribute to alejandraarochaovalles/retro-dynamics-agent development by creating an account on GitHub.&lt;br&gt;
github.com&lt;/p&gt;

&lt;p&gt;Also, here is the link to try the application in production: &lt;a href="https://retro-dynamics-agent-gcdg.vercel.app/" rel="noopener noreferrer"&gt;https://retro-dynamics-agent-gcdg.vercel.app/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>architecture</category>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
