<?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: Joe Giglio, Chief Remote Officer</title>
    <description>The latest articles on DEV Community by Joe Giglio, Chief Remote Officer (@chiefremote).</description>
    <link>https://dev.to/chiefremote</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F326687%2F17971535-34ef-4f38-861c-cec2c08bd280.jpg</url>
      <title>DEV Community: Joe Giglio, Chief Remote Officer</title>
      <link>https://dev.to/chiefremote</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chiefremote"/>
    <language>en</language>
    <item>
      <title>Part 4 - Using Cursor and Claude to Create Automated Tests with Playwright</title>
      <dc:creator>Joe Giglio, Chief Remote Officer</dc:creator>
      <pubDate>Tue, 05 Nov 2024 01:53:16 +0000</pubDate>
      <link>https://dev.to/chiefremote/part-4-using-cursor-and-claude-to-create-automated-tests-with-playwright-2p7j</link>
      <guid>https://dev.to/chiefremote/part-4-using-cursor-and-claude-to-create-automated-tests-with-playwright-2p7j</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/chiefremote/using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4aek"&gt;Part 1&lt;/a&gt; | &lt;a href="https://dev.to/chiefremote/part-2-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-5hnd"&gt;Part 2&lt;/a&gt; | &lt;a href="https://dev.to/chiefremote/part-3-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4pck"&gt;Part 3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PART 4&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is the Github source code repo for this project: &lt;a href="https://github.com/joegiglio/cursor2-kb" rel="noopener noreferrer"&gt;https://github.com/joegiglio/cursor2-kb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article focuses on using Cursor to create Playwright tests.  If you are interesting in &lt;a href="https://youtu.be/omJo9bDTIaY" rel="noopener noreferrer"&gt;using Windsurf to create Playwright tests&lt;/a&gt; check out these videos: &lt;a href="https://youtu.be/omJo9bDTIaY" rel="noopener noreferrer"&gt;https://youtu.be/omJo9bDTIaY&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;===&lt;br&gt;
It’s been a while… &lt;/p&gt;

&lt;p&gt;Last time we spoke, Cursor seemed to be breaking down and the index of the file structure had become corrupted.  After waiting 23 days for a fix, I am happy to report that the problem does finally seem to be addressed!  The UI is still quirky and it seems to slow down with some type of memory leak after a while which can be fixed with a restart.  But at least now it is making changes to the correct files and I am not faced with a mysteriously corrupted file index. &lt;/p&gt;

&lt;p&gt;While waiting for a fix, I noticed that many Cursor users were complaining about the instability of Cursor and/or Claude.  Yes, it works sometimes and it is impressive when it does but it is a black box of moving parts, constant updates behind the scenes and inconsistent results. &lt;/p&gt;

&lt;p&gt;I decided to put the Help Desk project to the side and wanted to see if I can build a Knowledge Base application instead.  This might be a little simpler - no need for real time updates or complex integration points. &lt;/p&gt;

&lt;p&gt;I used the same technology stack that I am most familiar with - Python, Flask and Bootstrap with a SQLite database.  Everything was coming along swimmingly until I hit a snag with “database migrations”.   Similar to the previous chapter, it generated constraint code that SQLite did not like and it threw an error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Exception during DB migration:
 raise ValueError("Constraint must have a name")
ValueError: Constraint must have a name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That should have been easy enough for Claude to fix but it started spiraling and I ended up rebuilding my database from scratch.  I will blame this on my inexperience with debugging flask-migrate but Claude was not able to clean up the mess without just wiping the database and starting over. &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.amazonaws.com%2Fuploads%2Farticles%2Ffu5jxg31kggjjfnwqt9w.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.amazonaws.com%2Fuploads%2Farticles%2Ffu5jxg31kggjjfnwqt9w.png" alt="Database" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After things settled down, I ended up with a mostly functional knowledge base system, along with an Admin panel, dark / light mode, search (just using the SQL queries) and test data generator.  It was built with Quill which is an open source text editor with support for formatting and images.&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.amazonaws.com%2Fuploads%2Farticles%2Fo6xt6v9zecy75u1lcfm5.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.amazonaws.com%2Fuploads%2Farticles%2Fo6xt6v9zecy75u1lcfm5.png" alt="KB UI" width="800" height="552"&gt;&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2Fxz29lrbb1ks7ia9fppzr.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.amazonaws.com%2Fuploads%2Farticles%2Fxz29lrbb1ks7ia9fppzr.png" alt="KB Create Article" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I say “mostly functional” because I purposely did not complicate it with authentication or mutli-tenancy.  I kept the architecture simple with basic Flask routes and CRUD operations.  No API yet… Perhaps I will revisit these features in phase 2.&lt;/p&gt;

&lt;p&gt;As I was adding features, I kept noticing that Claude would fix one thing but break another - just like a real developer.  Also, there was CSS and Javascript scattered all over the code.  Sometimes, adding new articles would work but editing would not work and vice versa.  Sometimes article formatting code would appear here and there and I had to ask Claude to clean it up.  It was becoming whack-a-mole.  &lt;/p&gt;

&lt;p&gt;The project was getting complex enough that it needed test automation which was briefly discussed in the last chapter.  In most companies, there is very little budget for QE and most Developers hate writing tests, so maybe AI can help?&lt;/p&gt;

&lt;p&gt;I have a respectable amount of experience with Selenium and Cucumber but it has been a while. Playwright has been gaining traction and supposedly has better handling for locators and retries so I asked Claude to create some Playwright tests.  The VS-Code Playwright extensions all seem to assume you are using Javascript and they do not have direct support for Python so I will need to run the tests from the Terminal, like an animal. &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.amazonaws.com%2Fuploads%2Farticles%2Feds0cqplqq6l539a28sr.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.amazonaws.com%2Fuploads%2Farticles%2Feds0cqplqq6l539a28sr.png" alt="Playwright Logo" width="400" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I would like to add end to end browser tests to this project using Playwright and Python.  I would like the tests to use fixtures to seed the necessary data and then delete the data at the end of each test run.  The tests need to clean up after themselves and not leave test data behind.  If you can configure it to setup a test database while running the tests that is even better.   Please let me know which libraries to install, create tests for the top 10 scenarios by looking at the main features of the product and let me know how to run these tests from within Cursor. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;The first attempt was pretty good, providing instructions on how to install the necessary libraries.  The file structure for the tests also seemed accurate and it even added a test for responsiveness by changing the viewport size.  Nice touch…   But I did not like the initial set of tests it generated so I asked it for further refinement:&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Authentication has not been implemented in this product yet.  Please do not create tests for those features.  Instead, focus on Admin functionality like creating, editing and deleting topics; adding, editing and deleting articles.  Also, focus on end user functionality such as searching and viewing articles.  Look at the code to figure out the top 10 features of the product and create tests for them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;The next batch of tests looked a little better but still no Admin functionality.&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Most of those tests look pretty good but I am not seeing anything for Admin functionality in the @admin.html file.  We need to have tests for adding, editing, deleting topics and adding, editing and deleting articles. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;Now it looks like it got it right and created code to test the following app scenarios:&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.amazonaws.com%2Fuploads%2Farticles%2Feilw7j9powi0dp5ifctu.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.amazonaws.com%2Fuploads%2Farticles%2Feilw7j9powi0dp5ifctu.png" alt="Test List 1" width="800" height="574"&gt;&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2Fe85v00mixjhdjs0jjyp9.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.amazonaws.com%2Fuploads%2Farticles%2Fe85v00mixjhdjs0jjyp9.png" alt="Test List 2" width="800" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These look like great starting points.  Now let’s see if the Claude's execution instructions are correct.  Well, unfortunately not…&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I followed your instructions for running the tests and I am running into a couple of problems.&lt;br&gt;
I opened a new terminal and ran the commands “FLASK_ENV=testing flask run” followed by “pytest tests/e2e/”.  I see the following problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When I navigate to the home page, I am seeing the same data I was seeing before.  It did not seem to switch to the test database. &lt;/li&gt;
&lt;li&gt;An exception: ImportError while loading conftest '/Users/joe/cursor2-kb/tests/e2e/conftest.py'.  tests/e2e/conftest.py:12: in  from models import Topic, Article ModuleNotFoundError: No module named 'models'&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT] &lt;/p&gt;

&lt;p&gt;Claude created a &lt;em&gt;models.py&lt;/em&gt; file, duplicating the code in the &lt;em&gt;app.py&lt;/em&gt; file and I questioned why… &lt;/p&gt;

&lt;p&gt;The initial code for this application was all done in the &lt;em&gt;app.py&lt;/em&gt; file, including the models.  This works fine but can leave you with an unwieldy single file application.  Best practice says to separate the models and routes from the config and this is where Claude was taking me, even though it took a long winded route:&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;p&gt;The models.py file you are proposing looks like it is duplicating code from app.py.  Would it make more sense to use the models in app.py instead?  &lt;/p&gt;

&lt;p&gt;[/PROMPT]  &lt;/p&gt;

&lt;p&gt;[RESPONSE]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Actually, it's the other way around - we should move the models out of app.py into models.py to follow the separation of concerns principle. This is a common pattern in Flask applications where:&lt;br&gt;
app.py handles application configuration and initialization&lt;br&gt;
models.py contains all database models&lt;br&gt;
routes are often in separate blueprint files&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/RESPONSE]&lt;/p&gt;

&lt;p&gt;Fair enough.  Let’s go with it!&lt;/p&gt;

&lt;p&gt;Well, not so fast.  Upon closer inspection…&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I like where you are going with separating the models.py file but you also deleted all the routes from the app.py file.  I do not see them in any other file.  They are just gone…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;Now Claude pulled all the routes out of the &lt;em&gt;app.py&lt;/em&gt; file and moved them into a separate file for blueprints.  It is making way too many architectural changes and I want it to revert…  Beware the brilliant new developer that wants to rewrite everything!  Although the suggested changes are considered best practices for a professional Flask codebase, I will not trust those changes until the tests are in place so we can verify they are working properly.  &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I understand that using blueprints is the preferred method for professional level Flask code.  However, I am not comfortable making such refactors right now. I am first trying to get end to end tests in place.  Then we can look at the project structure.  Please do not move the routes out of the app.py file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&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.amazonaws.com%2Fuploads%2Farticles%2Flfbe69rlhstu3q0hnrrt.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.amazonaws.com%2Fuploads%2Farticles%2Flfbe69rlhstu3q0hnrrt.png" alt="Blueprints" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cursor attempted to revert but the merge UI was a sea of green and red and I was not comfortable with the change.  New strategy: Let’s get some simple Playwright tests in place and then work on incrementally improving them.  Maybe this will be better…&lt;/p&gt;

&lt;p&gt;I stashed the proposed test list since I liked where that was going and then closed out of the Cursor Composer window and started a new Composer which I believe removes all content of the previous Composer. &lt;/p&gt;

&lt;p&gt;Let’s try again with a simpler starting point.  Iterative development is usually best anyway.  &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I would like to add end to end browser tests to this project using Playwright and Python.  Please let me know which libraries to install, create tests for the top 10 scenarios by looking at the main features of the product and let me know how to run these tests from within Cursor. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;We had similar problems this time with Claude wanting to test functionality that does not yet exist.  Time to scold Claude!&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I see you are creating tests for authentication functionality.  Although we have a login page, it is only a placeholder and does not actually function.  It does not even have fields to allow anyone to login.  Please review the project code again and come up with the top 10 test scenarios for Playwright.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;This caused Claude to apologize and create a bunch of test scenarios all around the Search functionality on the homepage.  I was hoping not to hand feed the tests I wanted, but instead wanted it to find the features by looking at the code.  No luck though, so I went back with:&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This looks better but is focused too much on search.  We need tests for the following features: search, create topic, edit topic, delete topics, create article, edit article, delete article, view article and some responsive tests to make sure everything looks OK on different screen resolutions. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;We are starting to spiral already…  It created the basic framework for some more tests but it is making too many assumptions about data that will exist.  Make no assumptions.  This is why it is best to have a test database that is pre-seeded but we will try to get there eventually.  For now…&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Some of these tests make assumptions that certain links will be valid and certain content will exist.  This may not be the case if articles or topics are deleted.  Please make each test self contained by creating the data it needs and then deleting it when the test completes. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT] &lt;/p&gt;

&lt;p&gt;So now Claude is right back to creating fixtures anyway!  I guess there is no way around it if you want to do it right… &lt;/p&gt;

&lt;p&gt;Another problem is using test strings like “Test Subject” and “Test Article” which may clash if we run parallel tests which is a common approach to speed up execution.  I wanted the tests to use randomized data so I prompted with this:&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please use random data for the topic name, article name and article content.  It would also be a good idea to add a test for foreign language characters to make sure they appear OK during browsing and searching.   &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&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.amazonaws.com%2Fuploads%2Farticles%2Ff1785e53g045zkb6r0vr.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.amazonaws.com%2Fuploads%2Farticles%2Ff1785e53g045zkb6r0vr.png" alt="Korean" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have a feeling we are going to need a lot more tweaks but this is looking like a very reasonable start.  Claude returned the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These changes were made:&lt;br&gt;
Use Faker to generate random data in multiple languages&lt;br&gt;
Add specific tests for multilingual content&lt;br&gt;
Verify proper display of various character sets&lt;br&gt;
Test search functionality with non-Latin characters&lt;br&gt;
Verify no character encoding issues in display&lt;br&gt;
Test content creation in multiple languages&lt;br&gt;
The tests now verify that your application correctly handles:&lt;br&gt;
Japanese (日本語)&lt;br&gt;
Chinese (中文)&lt;br&gt;
Korean (한국어)&lt;br&gt;
Russian (Русский)&lt;br&gt;
And regular English content&lt;br&gt;
Each test creates its own random data and cleans up after itself, making the tests more reliable and independent.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These are the tests that were created:&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.amazonaws.com%2Fuploads%2Farticles%2F2baxm442q27ve8ww9q19.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.amazonaws.com%2Fuploads%2Farticles%2F2baxm442q27ve8ww9q19.png" alt="Tests 3" width="800" height="366"&gt;&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2F72cqlm88tserprdklcnp.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.amazonaws.com%2Fuploads%2Farticles%2F72cqlm88tserprdklcnp.png" alt="Tests 4" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now to run them.  First, I need to install the &lt;em&gt;faker&lt;/em&gt; library which Claude instructed me to do… &lt;/p&gt;

&lt;p&gt;I was given a bunch of different flags and options for running the tests.  From previous experience, all of these instructions look right but I am going to use the &lt;em&gt;pytest.ini&lt;/em&gt; file Claude created and pass in a few flags for verbose output, screenshots and a slowed down test execution so I can follow along visually…&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.amazonaws.com%2Fuploads%2Farticles%2Fhbhexwlhqby46ptsr7xn.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.amazonaws.com%2Fuploads%2Farticles%2Fhbhexwlhqby46ptsr7xn.png" alt="pytest ini" width="800" height="153"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And now to run &lt;em&gt;pytest tests/e2e/&lt;/em&gt; to actually run the tests!&lt;/p&gt;

&lt;p&gt;All of the tests failed with this same error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;playwright._impl._errors.Error: Protocol error (Page.navigate): Cannot navigate to invalid URL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;em&gt;pytest.ini&lt;/em&gt;, the base_url is set to &lt;a href="http://localhost:5000" rel="noopener noreferrer"&gt;http://localhost:5000&lt;/a&gt; which looks right to me.&lt;/p&gt;

&lt;p&gt;I couldn’t figure out why it was failing so I asked Claude. He made a few small tweaks and then suggested I move the &lt;em&gt;pytest.ini&lt;/em&gt; file to the ROOT directory of the project and out of the tests/e2e directory where he originally placed it.  I pushed back on this and he said it was fine where it is.  OK then…&lt;/p&gt;

&lt;p&gt;He also suggested I use absolute URLs in the tests instead of the URL set in the INI file and text fixtures.  Wrong.  I also pushed back on that and he agreed and fixed it.  Losing faith here…&lt;/p&gt;

&lt;p&gt;With these changes, I ran the tests again and now I see the browser open up and go to the base URL which is the homepage of the knowledge base but all tests are still failing.  I went a few more rounds with Claude and it looks like the root page issues may be fixed but now we are failing with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FAILED tests/e2e/test_admin.py::test_create_topic[chromium] - playwright._impl._errors.TimeoutError: Timeout 30000ms exceeded.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which looks like more of a locator issue.&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Now all the admin tests in test_admin.py are failing with this error: admin_page.fill("#topic-title", data["title"]).  That is not the correct locator.  Please fix.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude fixed one test but the others are still failing with locator errors.  I got more explicit:&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Other than test_create_topic, the rest of the tests in @test_admin.py fail with locator errors. Please review all the locators in the tests and correct them.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude made a few changes and now we have another locator issue… &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Now all tests are failing with: &lt;br&gt;
tests/e2e/test_admin.py::test_create_topic[chromium] - AssertionError: Locator expected to be visible&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;It is obvious we will be here for a while, going round and round while Claude makes the necessary fixes.  What is also obvious and unfortunate is that Claude does not have the proper context of the application and page elements without me having to be very explicit.  Just asking Claude to “look at the code and create tests” is not good enough.  You will need to be very familiar with feature functionality and page structure so you can nurse it along.&lt;/p&gt;

&lt;p&gt;Claude was helpful in setting up the architecture of tests with &lt;em&gt;pytest.ini&lt;/em&gt; and &lt;em&gt;conftest.py&lt;/em&gt; but even so, it needed several tweaks for a basic test to run without an immediate failure.  &lt;/p&gt;

&lt;p&gt;This project uses Bootstrap on the front end along with Javascript confirmation and modal dialogs.  Claude seems to have a very difficult time with these if there are multiple modals in the source code, where only one is visible, which is a common design pattern.  After several iterations and guiding it with pseudo-code, we eventually came to an understanding and a passing test.&lt;/p&gt;

&lt;p&gt;Throughout these tests, Claude made many assumptions about the names of locators, most of which did not exist anywhere in the source code.  Only after explicitly telling it to look in certain files was it able to clean up but why make assumptions?  Perhaps I did not feed it the correct files to begin with?  I am still not sure how all of that is supposed to work.  &lt;/p&gt;

&lt;p&gt;Sometimes it seems to have access to the entire project while other times I need to be much more explicit.  If it needs access to a file it should ask and not just create bullshit code.  Remember, each back and forth costs you API credits. &lt;/p&gt;

&lt;p&gt;Besides lots of test failures, I am also having issues with screenshots not being saved even though I am passing the flag in the &lt;em&gt;pytest.ini&lt;/em&gt; file. Claude offered me a few permutations but none of them fixed the problem.  I looked at the Playwright documentation and still no resolution.  This seems like another one of those issues that “should be easy to fix” but you can easily burn a dozen Claude requests and get nowhere quickly.  I will move on for now, using a workaround that Claude suggested.&lt;/p&gt;

&lt;p&gt;After spending WAY TOO much time making tweaks with Claude, I now have only two tests that are passing and a third that starts out as PASS but ultimately ends up as FAIL due to some conflict between the test code and fixture code.  It is becoming exhausting to debug and I feel like I am having circular conversations.  I have gotten to a point where I just blindly merging suggested code changes and hoping for a miracle. &lt;/p&gt;

&lt;p&gt;Earlier in this chapter, my intention was to build a test harness that seeded and removed test data along with reusable fixtures and functions to keep the data and test code clean.  Those intentions are long out the window and now I just want the tests to pass and I will try to clean them up later.  Let me know if any of that sounds familiar…&lt;/p&gt;

&lt;p&gt;Even something seemingly as simple as maximizing the browser window when launched is proving to be way too difficult.  Claude has made attempts with Python and Javascript and it just doesn’t work.  He doesn’t know why and the geniuses on Stack Overflow have answered that question several times and their suggestions do not work either.  My guess is there is some code conflict among the files but I don’t know the code well enough to figure it out right now.  &lt;strong&gt;Where is AI when you need it!?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I found that some of the generated test code had more than one expect/assert.  I believe it to be best practice to have only ONE assert per test but know that is not always a realistic case especially when the tests are new and you don’t trust them yet.  &lt;/p&gt;

&lt;p&gt;I found myself being a “prompt engineer” trying to figure out how to nudge things in the right direction.  Since I did not write any of the product code myself I was not familiar with its inner workings and was hoping Claude could pick it up and run with it.  After all, he wrote it but he seems to have a short memory.  He gives you enough to get going but certainly not enough to ask once and collect the money.  &lt;/p&gt;

&lt;p&gt;What would make life easier is to have APIs to call for CRUD functions that create and delete data, leaving the end to end tests to only test their intended functionality.  The shortcomings and missing features of this test project may sound all too familiar if you have ever written automated tests for a software application.  You often end up having to work around &lt;strong&gt;product shortcomings&lt;/strong&gt; before you actually get around to testing &lt;strong&gt;product functionality&lt;/strong&gt;.  You may recall way back in the first chapter that I intended to build the product API-First and that quickly spiraled out of control.  Absent of APIs, perhaps direct SQL calls would have made more sense for setup and teardown. &lt;/p&gt;

&lt;p&gt;If you have automated tests working in another project and are familiar with the code and page structure of a new project, copy/paste/tweak will likely get you further faster than the Claude Playwright approach outlined here.  At least then you will have some familiarity with the code and can tweak if with some confidence.  As of now (November, 2024), I find asking Claude to generate end to end tests with Playwright to be a painful exercise.&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.amazonaws.com%2Fuploads%2Farticles%2F9ga2htzuky7whn3evmpe.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F9ga2htzuky7whn3evmpe.jpg" alt="Frustrated" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude20241022 Supplement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While writing this article, Anthropic released a new version of Claude Sonnet 3.5, dated 10/22/2024, which also became available in Cursor.  They claim there are some important advancements in coding so I figured I would re-do my testing to see if there were any improvements.&lt;/p&gt;

&lt;p&gt;After clearing up some virtual environment and dependency issues caused by changes Claude made to the &lt;em&gt;requirements.txt&lt;/em&gt; file, I was on my way.  I wiped out my database, created a new branch and went with the same prompt we started with earlier in the chapter:&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I would like to add end to end browser tests to this project using Playwright and Python.  I would like the tests to use fixtures to seed the necessary data and then delete the data at the end of each test run.  The tests need to clean up after themselves and not leave test data behind.  If you can configure it to setup a test database while running the tests that is even better.   Please let me know which libraries to install, create tests for the top 10 scenarios by looking at the main features of the product and let me know how to run these tests from within Cursor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;This resulted in Claude generating a &lt;em&gt;tests/e2e&lt;/em&gt; directory and all the expected files but when I attempted to run the tests, they all failed.   If I try to go to the website, all pages returned a 500.  I noticed &lt;em&gt;conftest.py&lt;/em&gt; has code that is supposed to switch the application to use a test database.  This is great but it looks like it never initialized.   The 'sqlite:///test.db' does not exist even though I see it referenced in the code.&lt;/p&gt;

&lt;p&gt;If I restart the server, this also throws exceptions.  I noticed all the tables and all my data has been removed from the original topics.db file.  All my data and schema has been wiped without warning!  Thankfully, this was just test data.&lt;/p&gt;

&lt;p&gt;After complaining to Claude, he made some changes and created a Python file to initialize the database which I ran.   &lt;/p&gt;

&lt;p&gt;Now when I run the tests, they all throw an exception about missing constraints. &lt;/p&gt;

&lt;p&gt;When I hit site manually, I get a database exception:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: topic
[SQL: SELECT topic.id AS topic_id, topic.name AS topic_name, topic.sort_order AS topic_sort_order, topic.description AS topic_description, article_1.id AS article_1_id, article_1.title AS article_1_title, article_1.content AS article_1_content, article_1.keywords AS article_1_keywords, article_1.topic_id AS article_1_topic_id, article_1.sort_order AS article_1_sort_order 
FROM topic LEFT OUTER JOIN article AS article_1 ON topic.id = article_1.topic_id ORDER BY topic.sort_order]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The act of running the tests has wiped my database again without warning!  Something ain’t right around here…. &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I am still having some serious database issues:  If I use the @init_db.py script, it restores my database tables and the app functions fine.  However if I run the tests with pytest tests/e2e/ each test fails with: ERROR tests/e2e/test_app.py::test_reorder_topics[chromium] - sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) NOT NULL constraint failed: article.topic_id.  Then when I try to use my main DB again, all the tables are removed again!  It does not seem to properly setup the test database which also breaks my other database somehow! &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude made some changes.  Next prompt:&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We are still having issues. Now all tests fail with ERROR tests/e2e/test_app.py::test_create_article[chromium] - sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: topic andit is still siping out my other database!  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude made a bunch of changes and when I try to run the database initialization script again, it fails with: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;(.venv) joe@Joes-MacBook-Pro cursor2-kb % python init_db.py&lt;br&gt;
Traceback (most recent call last):&lt;br&gt;
  File "/Users/joe/cursor2-kb/init_db.py", line 1, in &amp;lt;module&amp;gt;&lt;br&gt;
    from app import app, db&lt;br&gt;
  File "/Users/joe/cursor2-kb/app.py", line 40, in &amp;lt;module&amp;gt;&lt;br&gt;
    app = create_app()&lt;br&gt;
          ^^^^^^^^^^^^&lt;br&gt;
  File "/Users/joe/cursor2-kb/app.py", line 34, in create_app&lt;br&gt;
    db.init_app(app)&lt;br&gt;
    ^^&lt;br&gt;
NameError: name 'db' is not defined&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I also can not start the server since it generates the same error. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TIME FOR A RESET!&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Let’s simplify our initial prompt, again re-using one from earlier in this chapter.  I restored the database manually, created a new branch, fixed the virtual environment and went with: &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I would like to add end to end browser tests to this project using Playwright and Python.  Please let me know which libraries to install, create tests for the top 10 scenarios by looking at the main features of the product and let me know how to run these tests from within Cursor. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;The initial list of tests look pretty good: &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.amazonaws.com%2Fuploads%2Farticles%2Fdk7g11qvny4yyz8y4xps.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.amazonaws.com%2Fuploads%2Farticles%2Fdk7g11qvny4yyz8y4xps.png" alt="List of tests" width="469" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two passed without any intervention, another positive sign: &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.amazonaws.com%2Fuploads%2Farticles%2F42tmmfwj31i78dyullbc.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.amazonaws.com%2Fuploads%2Farticles%2F42tmmfwj31i78dyullbc.png" alt="Test run" width="512" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is an odd quirk though where passing the &lt;em&gt;–-headed&lt;/em&gt; flag does not allow me to view the tests as they run.  Claude was able to find a conflict between the &lt;em&gt;pytest.ini&lt;/em&gt; and one of the &lt;em&gt;conftest.py&lt;/em&gt; fixtures:&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.amazonaws.com%2Fuploads%2Farticles%2Fceicowoj5gn5t6tklay6.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.amazonaws.com%2Fuploads%2Farticles%2Fceicowoj5gn5t6tklay6.png" alt="Fixture" width="512" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Claude instructed me to change the code here if I wanted to not run headless.  I pushed back: &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This change is working but I do not want to pass a headless directive here.  I want it to be handled in the @pytest.ini file in the addopts section.&lt;br&gt;
[/PROMPT]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude then recommended I make changes in two files every time I want to run headless.  Why?&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is not correct.  I want to control the head/headless flag in the @pytest.ini file.  Your solution will force me to change this setting in two places.  Please fix.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;We then ended up with this snippet of code which seemed odd to me.  Why do we care about the –help flag?&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.amazonaws.com%2Fuploads%2Farticles%2F0i51uphhb84zaauekyak.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.amazonaws.com%2Fuploads%2Farticles%2F0i51uphhb84zaauekyak.png" alt="Fixture --help" width="800" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This resulted in a new error which Claude was able to fix when prompted:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;TypeError: argument of type 'bool' is not iterable&lt;br&gt;
tests/conftest.py:45: TypeError&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Now the tests are running but I am still not seeing a visible browser when they run. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[/PROMPT]&lt;/p&gt;

&lt;p&gt;The new Sonnet version seems to be stumbling like the previous version.  I am sure I can keep plugging away at it and eventually it will tighten up but I am not seeing any dramatic differences for our purposes here.&lt;/p&gt;

&lt;p&gt;I am frustrated with this experiment and will end it here.  Next chapter, let’s see if Claude does any better with &lt;strong&gt;Selenium&lt;/strong&gt; which has been around for much longer than Playwright.  Perhaps there are more examples out there that Claude was able to consume.  Playwright may be preferred these days but I find the Playwright / Claude pairing to be exhausting.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;MARCH 2025 UPDATE:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I tried a similar experiment using Windsurf with Claude 3.5.  Was it any better?&lt;br&gt;&lt;br&gt;
The only way to know for sure is to watch my video series, &lt;a href="https://www.youtube.com/playlist?list=PLLRCLXxv4S0fYqYMJfawS8TyY_S78YEkg" rel="noopener noreferrer"&gt;"The Truth about Vibe Coding with Windsurf… Better than Cursor?”&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://dev.to/chiefremote/using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4aek"&gt;Part 1&lt;/a&gt; | &lt;a href="https://dev.to/chiefremote/part-2-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-5hnd"&gt;Part 2&lt;/a&gt; | &lt;a href="https://dev.to/chiefremote/part-3-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4pck"&gt;Part 3&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;ABOUT THE AUTHOR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Joe Giglio is a 25+ year veteran of the software industry. In his career, he has worked for a local dial-up ISP, startups of all sizes and a well established, slow moving enterprise. There were important lessons learned along every stop.&lt;/p&gt;

&lt;p&gt;His recent projects include:&lt;/p&gt;

&lt;p&gt;Remote work training and consulting: &lt;a href="http://chiefremoteofficer.com" rel="noopener noreferrer"&gt;chiefremoteofficer.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kindle book "&lt;a href="https://amzn.to/3YHp4AK" rel="noopener noreferrer"&gt;Making Remote Work, Work For You&lt;/a&gt;"&lt;/p&gt;

&lt;p&gt;Remote company rankings. Think "Glassdoor for remote companies": &lt;a href="https://www.remotescorecard.com/" rel="noopener noreferrer"&gt;remotescorecard.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Joe’s guiding principles are: Remote first, quality driven, customer champion and lifelong learning. He was an introvert and practiced social distancing long before it was cool!&lt;/p&gt;

&lt;p&gt;He currently resides in North Carolina and is always interested in new opportunities, meeting quality people and learning about exciting projects.&lt;/p&gt;

&lt;p&gt;Contact Joe Giglio: joe -AT- joegiglio.org | &lt;a href="https://x.com/ChiefRemote" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; | &lt;a href="https://www.linkedin.com/in/joegiglio/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>cursor</category>
      <category>playwright</category>
      <category>testing</category>
    </item>
    <item>
      <title>Part 3 - Using Claude, Claude-Dev and Aider to Build a Ticketing System (Cursor too!)</title>
      <dc:creator>Joe Giglio, Chief Remote Officer</dc:creator>
      <pubDate>Tue, 27 Aug 2024 18:00:40 +0000</pubDate>
      <link>https://dev.to/chiefremote/part-3-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4pck</link>
      <guid>https://dev.to/chiefremote/part-3-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4pck</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/chiefremote/using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4aek"&gt;Part 1&lt;/a&gt; | &lt;a href="https://dev.to/chiefremote/part-2-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-5hnd"&gt;Part 2&lt;/a&gt; | &lt;a href="https://dev.to/chiefremote/part-4-using-cursor-and-claude-to-create-automated-tests-with-playwright-2p7j"&gt;Part 4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project has been open sourced if you would like to play along at home: &lt;a href="https://github.com/joegiglio/helpdesk-claude-dev-ai" rel="noopener noreferrer"&gt;https://github.com/joegiglio/helpdesk-claude-dev-ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PART 3 -&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I would now like to add a couple of basic features to the Knowledge Base.  Right now, we only have a skeleton UI. Let’s see if we can have Claude do something useful with it.&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I would now like to add a couple of basic features to the Knowledge Base.  Right now, the knowledge-base URL shows a placeholder UI but let’s start to make it do something useful.  Let’s start with the following:&lt;br&gt;
Add a link in the lefthand navigation bar for “Knowledge Base Settings”.  This should link to a new template that contains these settings. &lt;br&gt;
Inside the Knowledge Base Settings page, add a placeholder image and placeholder text. &lt;br&gt;
Inside the Knowledge Base Settings page, add a link for “Topics”, which will be created by the end user.  These topics will contain articles in a future step.  Make the necessary database updates to support these changes.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude made the necessary changes but had issues with missing libraries.  It once again lost track of the virtual environment, &lt;code&gt;.venv&lt;/code&gt;, which I needed to remind it of.  &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Please make sure you are using the virtual environment, directory named .venv&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;We ended up with this UI which was missing an image, had a couple of different fonts and the Manage Topics button was not functional.  I asked Claude to clean it up. &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.amazonaws.com%2Fuploads%2Farticles%2Fslw3tqpch3menzjx2gtn.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.amazonaws.com%2Fuploads%2Farticles%2Fslw3tqpch3menzjx2gtn.png" alt="KB Settings" width="800" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
We need to make some changes to the UI of the knowledge base settings page.  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; The placeholder image is missing.&lt;/li&gt;
&lt;li&gt; There are a couple of different fonts.  Please pick one and stay with it. &lt;/li&gt;
&lt;li&gt; The Manage Topics button does not do anything.  It looks like there is no framework for it so let’s make it functional.
&lt;/li&gt;
&lt;li&gt; Update the database by creating a table to hold the Topics. It only needs one field for now, named Topic.&lt;/li&gt;
&lt;li&gt;Create a page so a user can create and delete new topics.  Confirm deletions. 
[/PROMPT]&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Claude tried to use a local placeholder image again but I reminded it to use the via.placeholder.com service as discussed in part 2.&lt;/p&gt;

&lt;p&gt;Watching the output, I noticed a DB migration error which Claude was able to fix:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Exception during DB migration:&lt;br&gt;
 raise ValueError("Constraint must have a name")&lt;br&gt;
ValueError: Constraint must have a name&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After some clean up, this was the UI, which I did not care for:&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.amazonaws.com%2Fuploads%2Farticles%2F3p0i25jv62n1xrki1xx1.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.amazonaws.com%2Fuploads%2Farticles%2F3p0i25jv62n1xrki1xx1.png" alt="KB 2" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Please update the UI for the knowledge-base/settings page using the integrations/slack page as a guide. Improve the fonts and replace the placeholder image with a local image that represents a Knowledge Base - perhaps a book?&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;API limits are tightening up!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your per-minute rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Watching the requests go by, I saw Claude using a cURL command to download an icon to represent the Knowledge Base. However, it was not loading.  When asked, Claude says an SVG file was downloaded but saved as a PNG.  That’s a new one.  One more iteration and it was fixed, leaving me with:&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.amazonaws.com%2Fuploads%2Farticles%2F009tr7j3u421qhges90n.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.amazonaws.com%2Fuploads%2Farticles%2F009tr7j3u421qhges90n.png" alt="KB 3" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am not sure if I love the layout with the big Manage Topics button but it will do for now.  Moving on to managing topics:&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.amazonaws.com%2Fuploads%2Farticles%2Femycky45obzht7lhvs7s.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.amazonaws.com%2Fuploads%2Farticles%2Femycky45obzht7lhvs7s.png" alt="KB 4" width="800" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not bad, but if I try to add a topic name that already exists, I hit an exception:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: knowledge_base_topic.name&lt;br&gt;
[SQL: INSERT INTO knowledge_base_topic (name) VALUES (?)]&lt;br&gt;
[parameters: ('topic 1',)]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is the same constraint it had a problem creating earlier.  Let’s see if Claude can fix it.&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
If I try to create a topic name that already exists, I get an exception.  Please fix?  sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: knowledge_base_topic.name&lt;br&gt;
[SQL: INSERT INTO knowledge_base_topic (name) VALUES (?)]&lt;br&gt;
[parameters: ('topic 1',)]&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;…and another 429 error:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your per-minute rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Claude must be getting hit very hard!  Almost unusable tonight…&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I am now blocked from creating multiple topics with the same name but there are a couple of problems: 1.  Missing styling for the “error” flash message.  The background color should probably be red.  2.  The topic names should be case insensitive.  If “topic” already exists, “I should not also be allowed to create “TOPIC”. &lt;br&gt;
[/PROMPT]&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.amazonaws.com%2Fuploads%2Farticles%2Fmjota5aokwqlp0ynhxc3.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.amazonaws.com%2Fuploads%2Farticles%2Fmjota5aokwqlp0ynhxc3.png" alt="KB 5" width="800" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another 429 error.  This is grueling…&lt;/p&gt;

&lt;p&gt;I was able to sneak in one more request until I supposedly hit my DAILY limit:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your daily rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I did not do much with Claude tonight but quickly hit my token limit.  I am not really sure how that is calculated but the API seems very restrictive tonight.  All I can do is smile and wait til tomorrow. &lt;/p&gt;

&lt;p&gt;Next day:&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Let’s continue to improve the Knowledge Base topics UI by making the following changes: 1.  The topic names should be case insensitive.  If “topic” already exists, “I should not also be allowed to create “TOPIC”.  2.  Put a limit of 10 on how many topics can be created and display this count in the UI.  Disable the Create Topic button if there are 10 topics and display an appropriate message.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude came up with some fancy class function code to check for number of topics and case insensitivity.  Pretty elegant:&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.amazonaws.com%2Fuploads%2Farticles%2Fe7m8qsf9z2qnee66vnia.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.amazonaws.com%2Fuploads%2Farticles%2Fe7m8qsf9z2qnee66vnia.png" alt="KB 6" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I noticed that a maxlength was not being enforced for the topic name, even though I tell Claude to do so in my system prompt which is supposed to apply to every prompt I send.  Disappointing… &lt;/p&gt;

&lt;p&gt;Even though the field in the database is configured to accept 100 characters, I was able to submit a topic name with thousands and nothing blew up. I am not sure how that all works but from where I come from, a lack of enforced limits leads to trouble. &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.amazonaws.com%2Fuploads%2Farticles%2Fqwd082uynpq5ekg3d648.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.amazonaws.com%2Fuploads%2Farticles%2Fqwd082uynpq5ekg3d648.png" alt="KB 7" width="800" height="867"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
It does not look like you are enforcing any length limit on a topic name. Is that correct?&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You're right, and I apologize for overlooking this important detail. Let's add a length limit to the topic names. We'll set a maximum length of 50 characters for topic names. I'll make the necessary changes to enforce this limit both in the backend and frontend.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude added some code but it was plain Javascript and I wanted jQuery which is already part of the project.  I also have jQuery in my system prompt but it seems to ignore that too.  Claude changed it to jQuery and even added a character counter (nice touch!).  But… it doesn’t work!&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I see you added a character counter but it doesn’t work.  I do not see any errors in the web console.  Please fix.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude made a few changes to the order of script tags and now it works.  Again, similar issues to what we had before.&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Let’s make a couple more UI tweaks on the manage-topics page.  1.  Sort the topics in alphabetical order, case insensitive.  2.  Move the Topic count next to the “Existing Topics” header, removing it from below the Create Topic button.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;In the middle of this iteration, I hit my daily API limit AGAIN.  Whatever Anthropic recently changed with “prompt caching” has done nothing to help me.  It seems to have gotten worse.  &lt;/p&gt;

&lt;p&gt;And, of course:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;400 {"type":"error","error":{"type":"invalid_request_error","message":"Your credit balance is too low to access the Claude API. Please go to Plans &amp;amp; Billing to upgrade or purchase credits."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is the current UI.  Not bad!&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.amazonaws.com%2Fuploads%2Farticles%2F04yl03sp1x9gjqyfvyl5.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.amazonaws.com%2Fuploads%2Farticles%2F04yl03sp1x9gjqyfvyl5.png" alt="KB 8" width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To the next day…  Next, I want to create the code to add articles to the knowledge base.&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Now I would like to create another feature where we can add articles to the knowledge base. Some requirements: &lt;br&gt;
Each article must be in a topic.&lt;br&gt;
If a topic has articles, the articles should also be deleted when its parent topic is deleted.  The deletion confirmation should warn the user of how many articles will also be deleted. The user needs to type the word “delete” (case insensitive) to confirm the topic deletion, if it has articles in it. &lt;br&gt;
Click a topic name to view the articles within it.&lt;br&gt;&lt;br&gt;
In the next prompt, we will build out the UI for the article creation page.  For now, put together a placeholder page with placeholder images and text.&lt;br&gt;&lt;br&gt;
Please make the necessary changes to the files and database structure to support this feature. &lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;This is a pretty meaty prompt.  Let’s see how Claude does… &lt;/p&gt;

&lt;p&gt;There were a couple of issues with the database migration which seemed to be caused by Claude again not detecting the &lt;code&gt;.venv&lt;/code&gt; &lt;br&gt;
environment.  I am going to add that to the System Prompt setting in Claude-Dev.  Hopefully it helps.  &lt;/p&gt;

&lt;p&gt;After those issues were straightened out, I found the results to be pretty good.  Of course it needs a few tweaks after some quick testing.  I will pick these off in the next prompt:&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
We need a few tweaks to the article creation implementation.  Please make these changes:&lt;br&gt;
When deleting topics, we should always show a confirmation.  However, only if a topic contains articles should we ask for a confirmation that requires the user to type the word “delete”, case insensitive.&lt;br&gt;
Add a mechanism to delete articles and confirm these deletions. &lt;br&gt;
On the main knowledge-base page, hide the search bar and placeholder messages if there are no topics.  Add placeholder text that says there are no topics yet.&lt;br&gt;&lt;br&gt;
Add a more advanced article editor so users can format their articles during creation and editing.  Protect against potentially dangerous characters by encoding and decoding article text upon saving and retrieval.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;I was curious to see which article editor Claude would select.  It went with TinyMCE.  However it did not appear.  &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Some more tweaks are needed: &lt;br&gt;
 The manage-topics page should show how many articles are in each topic.&lt;br&gt;
“View All Articles” button should not appear if there are no articles in a topic. Instead, show text like “There are no articles in this topic”. &lt;br&gt;
You attempted to add the TinyMCE editor for adding and editing articles but it does not appear.  I see no errors in the console.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;TinyMCE is still not working.  This feels like another websocket and JIRA ticket issue where Claude can’t fix the issue and I run out of requests.  I hope not.  More tweaks needed!&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Some more tweaks are needed: &lt;br&gt;
If there are no articles in a topic, the manage-topics shows both an article counter and the text “There are no articles in this topic”.  There is no need to show both so remove the text “There are no articles in this topic”.&lt;br&gt;&lt;br&gt;
On the “knowledge-base” page, we are still displaying the “View All Articles” button if there are no articles in the topic.  Instead, show text like “There are no articles in this topic”. &lt;br&gt;
The TinyMCE editor still does not appear for adding or editing articles.  I see no errors in the console.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;The TinyMCE UI is loading now but it is asking for an API key.  I will ask Claude if there is a simpler, free editor available instead. &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.amazonaws.com%2Fuploads%2Farticles%2Fs404xnccwolkz0l4xq4b.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.amazonaws.com%2Fuploads%2Farticles%2Fs404xnccwolkz0l4xq4b.png" alt="KB 9" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
The TinyMCE editor is appearing now but it is asking for an API key.  Is there another editor we can use that does not require a key?  Basic formatting options should be fine for now.  If you can find one, please replace TinyMCE with it.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude replaced TinyMCE with CKEditor and now it loads!  However, it is not without its issues.  I am not able to upload an image or save the article.  Errors in the dev console:&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.amazonaws.com%2Fuploads%2Farticles%2Fin4ecrt5xmb67jmuezk8.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.amazonaws.com%2Fuploads%2Farticles%2Fin4ecrt5xmb67jmuezk8.png" alt="KB 10" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I am able to view CKEditor but I am having a couple of issues:&lt;br&gt;
I can not save an article.  Dev console shows this error: new:1 An invalid form control with name='content' is not focusable. &lt;br&gt;
I can not upload an image.  Dev console shows this error:  ckeditorerror.ts:140 filerepository-no-upload-adapter &lt;br&gt;
Please fix?&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I apologize for the issues you're experiencing. Let's address both problems:&lt;br&gt;
The error "An invalid form control with name='content' is not focusable" is likely due to the CKEditor replacing the textarea with its own element, causing issues with form validation. We'll need to update our form submission process to handle this.&lt;br&gt;
The "filerepository-no-upload-adapter" error occurs because we haven't configured an upload adapter for CKEditor. We'll need to implement a simple upload adapter to handle image uploads.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first fix looked easy but Claude was adding some very complex Javascript code to accommodate file uploads.  I pushed back:&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
That looks like some very complicated code for the upload adapter. Are you sure there is not a simpler solution, perhaps something built into CKEditor?&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I apologize for the complexity. You're right, there is a simpler solution using CKEditor's built-in features. Let's simplify our approach by using CKEditor's Basic package, which doesn't include image uploads but provides basic formatting options. This should resolve both issues without requiring a complex upload adapter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I want file upload capabilities but can live without it during this exercise.  Unfortunately, I hit my daily API limit so that’s it for today’s activities.   Such a momentum killer… &lt;/p&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your daily rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;However, I did preview some of Claude’s fixes.  I am able to save an article now but the preview is showing HTML code.  There is also no way to actually view an entire article.  An oversight on my part.  Will need to fix!&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.amazonaws.com%2Fuploads%2Farticles%2Fv9czvey6xbysner0k0a8.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.amazonaws.com%2Fuploads%2Farticles%2Fv9czvey6xbysner0k0a8.png" alt="KB 11" width="800" height="137"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Due to some shortcomings in my earlier prompts when building the UI, pages and functions intended for an Admin are getting mixed with those of an end user.  I am going to have to clean that up one of these days.  For now, let’s continue on with some fixes and tweaks…  Here is another meaty one.  I am about to run out of credits but here we go!&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
There are still some bugs and shortcomings that need to be fixed:&lt;br&gt;
 I still have an option to upload images when creating and editing an article.  Trying to upload an image shows an error: ckeditorerror.ts:140.  I would like to be able to upload images using the editor so please fix.  We can use the /static/uploads/ directory to store uploaded images if necessary.&lt;br&gt;&lt;br&gt;
When I go to the topic/[topic number] page, I see article previews but they appear with visible HTML code.  This page should act as an article preview and we should perhaps see a plain text version of the beginning of this article.  We may have to tweak this later. &lt;br&gt;
We need a new route to view an article, and the article should appear properly formatted.  Right now, when you click an article it brings you to edit mode.  We need to separate viewing from editing.&lt;br&gt;&lt;br&gt;
There should be a way to create a new article in each topic from the manage-topics page.&lt;br&gt;
When creating a new article, there is a topic dropdown at the bottom of the page.  This dropdown is not contextually aware of the topic the user is in.  The dropdown should reflect the correct topic.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;While watching Claude build the code for the file upload feature, I noticed it was creating the same block of Javascript in a couple of different files. &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
It looks like there is some similar Javascript code in the new_article.html and edit_article.html files.  Can we create this in a common file and share the code instead?&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You're right, and that's a great suggestion. Let's create a common JavaScript file for the CKEditor configuration and use it in both new_article.html and edit_article.html.&lt;br&gt;
First, let's create a new file called ckeditor_config.js in the static/js directory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That was a lot of changes.  While reviewing the code changes, I noticed the diff showed a bunch of code being removed from the app.py file and being replaced with the text “# … (rest of the existing code)”.  I had never seen this before and though it was maybe how Claude dealt with a large file and it was not really going to delete existing code.  Well, I was wrong!&lt;/p&gt;

&lt;p&gt;When Claude completed these tweaks, I tried to hit the home page and it was 404.  Lots of code and routes were removed and line 80 is literally "# … (rest of the existing code)”.  Wow, that’s bad!  Hopefully we can fix this but I smell API limits lurking!&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.amazonaws.com%2Fuploads%2Farticles%2Fsul0ll1chl6wsl6lw6ui.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.amazonaws.com%2Fuploads%2Farticles%2Fsul0ll1chl6wsl6lw6ui.png" alt="KB 12" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Oh no!  I seem to have lost a lot of code from the app.py file after your last change.  Many of the routes are gone and have been replaced with "# ... (rest of the existing code)" on line 29 and 80 of app.py.  Please fix!&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I apologize for the oversight. You're absolutely right, and I'll fix this issue immediately. Let's restore the missing code in the app.py file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude was able to fix the code but Wow - that’s a bad one.  What the hell was that all about?&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
If I try to create the “New Article” button, I get this error: jinja2.exceptions.UndefinedError: 'csrf_token' is undefined&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude says we now need the Flask-WTF package and it will install it using pip.  Let’s see if the system prompt to use the &lt;code&gt;.venv&lt;/code&gt; directory will work…&lt;/p&gt;

&lt;p&gt;No way!  Claude did it again, deleting all the code during the code merge!  You really need to pay attention and not just accept the generated 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.amazonaws.com%2Fuploads%2Farticles%2Fp28ekodd4vv12uiin9v4.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.amazonaws.com%2Fuploads%2Farticles%2Fp28ekodd4vv12uiin9v4.png" alt="KB 13" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I can not accept this code!  Line 31 “has # ... (rest of the existing code)” and you removed the rest of the code again!&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;When Claude was done, the server tried to restart but failed with “ModuleNotFoundError: No module named 'flask_wtf'” which indicates that it was not using the &lt;code&gt;.venv&lt;/code&gt; directory so I don’t believe the System Prompt is working.  This may be an issue with the Claude-Dev extension. &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I am getting the error "ModuleNotFoundError: No module named 'flask_wtf'" so please make sure you are using the .venv virtual directory when adding new libraries!&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I apologize for the oversight. You're right, we need to install Flask-WTF in the virtual environment. Let's do that now.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And… like clockwork:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your daily rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The good news is that Claude was able to use the correct virtual environment and the server started. &lt;/p&gt;

&lt;p&gt;The bad news is that if I try to submit a new article, I am hit with another CSRF error.  Wake up, Claude.  You have some work to do!&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.amazonaws.com%2Fuploads%2Farticles%2Fdklhxhkj6fl3j7mdimxf.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.amazonaws.com%2Fuploads%2Farticles%2Fdklhxhkj6fl3j7mdimxf.png" alt="KB 14" width="432" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Please fix the following bugs:&lt;br&gt;
 If I try to submit a new article, I get an error: “Bad Request.  The CSRF token is missing.”&lt;br&gt;
If I try to view an article, HTML tags are visible.  The article should display formatted without the tags.&lt;br&gt;&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Someone woke up in a bad mood… I am barely using it and I am getting hit with rate limits already.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your per-minute rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I am still finding some bugs.  These are all very basic and should not have made it into the code.  Please check your code more carefully as these are costing my money each time you need to fix them!  Perhaps the application is getting complicated enough that it is time to add some automated testing that will run on each code change?  The issues I am finding: &lt;br&gt;
When I try to view an article such as the one found at article/2, it is still showing HTML markup and not rendering the formatted article.  Perhaps this is breaking when the article is saved?   I am seeing lt; and gt; in the database and notice you have “content = html.escape(content)” on app.py line 416. &lt;br&gt;
If I try to create a new topic, I am now getting “Bad Request.  The CSRF token is missing.”&lt;br&gt;
If I try to create a new article, I am getting “UndefinedError jinja2.exceptions.UndefinedError: 'form' is undefined” &lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Watching Claude make code changes, I think it is melting down.  Why is it deleting all this code again??&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.amazonaws.com%2Fuploads%2Farticles%2F4u3wriss22u80bumw737.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.amazonaws.com%2Fuploads%2Farticles%2F4u3wriss22u80bumw737.png" alt="KB 15" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Why are you deleting all that code again?  Line 35 has # ... (keep all the existing model definitions and helper functions) and all the other code is deleted?  Be careful!&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I apologize for the confusion. You're absolutely right, and I appreciate your attention to detail. Let's make the necessary changes while keeping all the existing code intact. We'll only update the specific parts that need to be modified.&lt;br&gt;
Let's update the app.py file, focusing only on the parts that need to be changed&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your per-minute rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Sigh…&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Lines 35, 37 and 46 still have those comments and you are deleting huge blocks of code. Why?&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And of course -&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your daily rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I can’t be the only one having these problems.  Everyone else says they are making millions with Claude and I seem to be finding all the bugs!  I opened an issue in the Claude-Dev Github project since I can’t live like this: &lt;a href="https://github.com/saoudrizwan/claude-dev/issues/170" rel="noopener noreferrer"&gt;Github link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After doing some more research, it does sound like my project is hitting some type of token limit which is documented here: &lt;a href="https://github.com/saoudrizwan/claude-dev/issues/14" rel="noopener noreferrer"&gt;Github issue&lt;/a&gt;.  This really limits the complexity of the project you can work with and is the likely cause of so many API limit errors as the project became more complex.&lt;/p&gt;

&lt;p&gt;If I understand the problem correctly, in order to increase code quality, Claude-dev sends the entire contents of the active file back and forth in requests.  This eats up tokens and at some point, my app.py file became too large to manage.  One suggestion is to break the code into smaller files.  Way back in Part 1, this was the direction we were going but had some issues with circular imports and Uvicorn so here we are… &lt;/p&gt;

&lt;p&gt;I guess I will put this project to bed for now and follow the Github thread for updates.  This gives some hope that an upcoming Claude update will ease the pain: &lt;a href="https://github.com/saoudrizwan/claude-dev/issues/170#issuecomment-2309306750" rel="noopener noreferrer"&gt;Github comment&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next up: &lt;a href="https://www.cursor.com/" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt;?  Last time I tried, I did not like the UX as much but a lot of people seem to have made the switch.  Cursor seems to be the new kid in town for Developers that are using UI to increase their productivity.  Because what we need right now is another IDE. &lt;/p&gt;

&lt;p&gt;Round and round we go…&lt;/p&gt;

&lt;p&gt;So, some conclusions?&lt;/p&gt;

&lt;p&gt;Is Claude ready to replace software Engineers?  Eh, not quite yet but it can make existing Engineers more productive.  The API limits are restrictive for anything more than a small project, refactoring, bug fixes and use as a virtual pair programmer.&lt;/p&gt;

&lt;p&gt;I have read that Claude can read complex codebases and fix bugs within it.  In my experience, it ran into a couple of bugs it could not fix in a fairly simple project on code that it created itself so that did not give me the warm and fuzzies.  How would it fare on an old codebase written by dozens of people with a complicated file structure?  Claude would not have any business context and if asked to fix a UI bug, it did not do a great job at matching already existing UI and UX flow in this simple prooject.  It needed several iterations to clean up after itself. &lt;/p&gt;

&lt;p&gt;I find backend code “easier” than front end code so I would personally use it to help me build project structure and a skeleton UI.  One of Claude’s strengths is “computer vision” which enables you to upload a file and ask Claude to recreate it in code.  If you like the UI of a website, this should give you a great starting point.  Perhaps this is the new “View Source”.  Embrace and enhance, as they say.&lt;/p&gt;

&lt;p&gt;Although one of my earliest prompts asked Claude to use Bootstrap to make a Responsive UI, I just checked the mobile view for the first time and found that it is not really functional in anything smaller than IPad Mini resolution and that doesn’t look great either.  So make no assumptions.  Claude’s code needs the same amount of testing as any other code.  &lt;/p&gt;

&lt;p&gt;In fact, it would make sense to have it build out an automated testing harness which can run prior to code check in.  Nobody likes doing THAT work.  Make Claude responsible for writing, maintaining and running tests.  Definitely an avenue worth exploring.  &lt;/p&gt;

&lt;p&gt;I asked Claude to create some automated tests in one of my final prompts but the token and API limits put an end to this experiment before we ever got there.   &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;QUICK ADDENDUM REGARDING CURSOR.AI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While I was working on this document, Cursor started heating up so I figured I would try it to see if it was any better.  Well, it was at first. &lt;/p&gt;

&lt;p&gt;They give you a free trial which includes 50 API calls and it was damn fast with no API limits.  Great!  I bought a monthly subscription and that's where the good news ends.  Just like before, once the project becomes more than trivial, say your prayers.  It's gonna be a long night...   &lt;/p&gt;

&lt;p&gt;I found that Cursor appeared to be making code changes but when I ran the project, the new code was not actually being applied to the correct files.  I noticed lots of errors in the debug console about files missing and it was attempting to create directories that already existed.  It seemed like the index had gotten corrupted somehow.  &lt;/p&gt;

&lt;p&gt;I posted this problem to the Cursor support forums, hoping for a quick workaround but never received one.  Cursor developers have acknowledged this issue and at least one other person is seeing it too.  They claim it will be fixed in the "next build".  It has been 20 days and still no updates.  I am crippled until then.   &lt;/p&gt;

&lt;p&gt;Read more about it in my forum &lt;a href="https://forum.cursor.com/t/composer-has-gotten-wacky/14685" rel="noopener noreferrer"&gt;post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next up: &lt;a href="https://dev.to/chiefremote/part-4-using-cursor-and-claude-to-create-automated-tests-with-playwright-2p7j"&gt;Part 4&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/chiefremote/using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4aek"&gt;Part 1&lt;/a&gt; | &lt;a href="https://dev.to/chiefremote/part-2-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-5hnd"&gt;Part 2&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ABOUT THE AUTHOR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Joe Giglio is a 25+ year veteran of the software industry. In his career, he has worked for a local dial-up ISP, startups of all sizes and a well established, slow moving enterprise. There were important lessons learned along every stop.&lt;/p&gt;

&lt;p&gt;His recent projects include:&lt;/p&gt;

&lt;p&gt;Remote work training and consulting: &lt;a href="http://chiefremoteofficer.com" rel="noopener noreferrer"&gt;chiefremoteofficer.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kindle book "&lt;a href="https://amzn.to/3YHp4AK" rel="noopener noreferrer"&gt;Making Remote Work, Work For You&lt;/a&gt;"&lt;/p&gt;

&lt;p&gt;Remote company rankings. Think "Glassdoor for remote companies": &lt;a href="https://www.remotescorecard.com/" rel="noopener noreferrer"&gt;remotescorecard.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Joe’s guiding principles are: Remote first, quality driven, customer champion and lifelong learning. He was an introvert and practiced social distancing long before it was cool!&lt;/p&gt;

&lt;p&gt;He currently resides in North Carolina and is always interested in new opportunities, meeting quality people and learning about exciting projects.&lt;/p&gt;

&lt;p&gt;Contact Joe Giglio: joe -AT- joegiglio.org | &lt;a href="https://x.com/ChiefRemote" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; | &lt;a href="https://www.linkedin.com/in/joegiglio/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Part 2 - Using Claude, Claude-Dev and Aider to Build a Ticketing System</title>
      <dc:creator>Joe Giglio, Chief Remote Officer</dc:creator>
      <pubDate>Mon, 19 Aug 2024 21:07:00 +0000</pubDate>
      <link>https://dev.to/chiefremote/part-2-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-5hnd</link>
      <guid>https://dev.to/chiefremote/part-2-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-5hnd</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/chiefremote/using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4aek"&gt;Part 1&lt;/a&gt; | &lt;a href="https://dev.to/chiefremote/part-3-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4pck"&gt;Part 3&lt;/a&gt; | &lt;a href="https://dev.to/chiefremote/part-4-using-cursor-and-claude-to-create-automated-tests-with-playwright-2p7j"&gt;Part 4&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;The project has been open sourced if you would like to play along at home: &lt;a href="https://github.com/joegiglio/helpdesk-claude-dev-ai" rel="noopener noreferrer"&gt;https://github.com/joegiglio/helpdesk-claude-dev-ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PART 2-&lt;/strong&gt;&lt;br&gt;
I wanted Claude to work on some simple integrations with popular, third party products.  But first, I needed to clean up the UI a bit… &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I don’t like how the “delete icon” looks in the ticket list view.  It is just a small red box.  Can you verify it looks as intended?&lt;br&gt;
[/PROMPT]&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.amazonaws.com%2Fuploads%2Farticles%2F0mecbqb35mia3bbmvqdn.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.amazonaws.com%2Fuploads%2Farticles%2F0mecbqb35mia3bbmvqdn.png" alt="Image" width="800" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After some back and forth, it was determined that the CSS file from Font Awesome was not loading correctly.  Claude made the necessary changes and it was addressed.  This did cost me another 20 cents and API credits though.  Again, you have to pay for Claude to clean up after itself. &lt;/p&gt;

&lt;p&gt;I added another $5 and wanted to switch gears towards Integrations. &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I would like to make some changes to the Integrations page. 1. Add a fourth column for "Webhooks", with a placeholder image and short description text. 2. Make sure the height of all of the cards is equal. Right now, the Salesforce card is shorter than the others.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude fixed it and came back with:&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.amazonaws.com%2Fuploads%2Farticles%2Fyrfxyrfol70hclnvoigd.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.amazonaws.com%2Fuploads%2Farticles%2Fyrfxyrfol70hclnvoigd.png" alt="Image" width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
This looked better but the text in the cards are not aligned. &lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;I found Claude littering HTML files with inline styles like an animal.  I asked it to create a styles.css file and move all CSS into it.  I was surprised this was not done earlier in the project but it was quickly addressed.  &lt;/p&gt;

&lt;p&gt;I also did not like the image used for the Webhooks column since it was intended to represent a WAV file. Odd choice… &lt;/p&gt;

&lt;p&gt;Image changes took a couple of tries to get right and I am paying for each request.  I don’t want to come across as not being impressed by the power of this technology at my fingertips, so please don’t take it that way…  But each request costs money and the daily API requests are limited so I hate having to waste them on follow-up clean up requests, especially on items that are seemingly “simple”.  &lt;/p&gt;

&lt;p&gt;Final result:&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.amazonaws.com%2Fuploads%2Farticles%2Ffdeeoo6v0v60jqgif35r.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.amazonaws.com%2Fuploads%2Farticles%2Ffdeeoo6v0v60jqgif35r.png" alt="Image" width="800" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have a decent looking UI, I wanted to try to build simple integrations into a couple of these services. &lt;/p&gt;

&lt;p&gt;It has been a while since I played with Slack Apps.  From what I remember, the easiest way to get started was with a webhook. Slack assigns you a URL, you post JSON data to it and the text appears in a chat room.  I did not want to waste my Claude credits yet so I spent some time refamiliarizing myself with Slack’s Admin and working with Gemini’s AI in a browser tab.  &lt;/p&gt;

&lt;p&gt;Turns out posting to a Webhook is still an option and you can find it among all the other bloated Slack app settings. Slack is looking more and more like a Salesforce product; death by 1,000 settings.  &lt;/p&gt;

&lt;p&gt;Now that I knew how to build the integration, I asked Claude to do the heavy lifting so I could critique his work… &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I want to begin work on the Integrations feature of this application and want to start with Slack.&lt;/p&gt;

&lt;p&gt;Whenever a new ticket is created in this application, I want to send it to a Slack chat room.  I am not sure how to do this and need your guidance step-by-step.  These steps will include configuration in Slack’s Admin.  Let’s start there and then we will create the necessary code in our ticketing system to send data to Slack. &lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude’s answer regarding the necessary set up in Slack’s Admin was correct:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Certainly! I'll guide you through the process of integrating Slack with your ticketing system to send notifications about new tickets. We'll start with the Slack configuration and then move on to implementing the necessary code in your application. Let's break this down into steps:&lt;br&gt;
Step 1: Slack Configuration&lt;br&gt;
To set up the Slack integration, we need to create a Slack app and configure it to receive incoming webhooks. Here's how to do that:&lt;br&gt;
Go to the Slack API website (&lt;a href="https://api.slack.com/apps" rel="noopener noreferrer"&gt;https://api.slack.com/apps&lt;/a&gt;) and sign in with your Slack account.&lt;br&gt;
Click on "Create New App" and choose "From scratch".&lt;br&gt;
Give your app a name (e.g., "Ticketing System") and select the workspace where you want to install it.&lt;br&gt;
Once the app is created, go to "Incoming Webhooks" in the left sidebar and turn on "Activate Incoming Webhooks".&lt;br&gt;
Scroll down and click on "Add New Webhook to Workspace".&lt;br&gt;
Choose the channel where you want the notifications to appear and click "Allow".&lt;/p&gt;

&lt;p&gt;You'll be given a Webhook URL. Keep this URL safe and secret, as we'll need it later in our code.&lt;br&gt;
Step 2: Prepare the Application&lt;br&gt;
Now that we have the Slack webhook URL, let's prepare our application to send notifications. We'll need to:&lt;br&gt;
Install the requests library to send HTTP requests to the Slack webhook.&lt;br&gt;
Store the webhook URL securely.&lt;br&gt;
Modify the ticket creation process to send a notification to Slack.&lt;br&gt;
Let's start by installing the requests library&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I allowed Claude to proceed with making the necessary code changes to support this feature. &lt;/p&gt;

&lt;p&gt;The code changes looked correct at first glance but I did not like that the &lt;code&gt;WEBHOOK_URL&lt;/code&gt; variable was added to the &lt;code&gt;app.py&lt;/code&gt; file.  I thought it was more secure to add it to a separate file and remove that file from the code repo through &lt;code&gt;.gitignore&lt;/code&gt;.  Claude agreed, apologized for the oversight and cleaned up the code. &lt;/p&gt;

&lt;p&gt;Attempting to start the server failed because it was trying to import the &lt;code&gt;requests&lt;/code&gt; library which was never installed.  It turns out that Claude was not aware that the project was using a virtual environment. &lt;/p&gt;

&lt;p&gt;I prompted Claude to use the virtual environment named “.venv” but made a typo and told it to use “.env” instead which added more confusion.  After requesting access to the top level of the project directory, it discovered the virtual environment at “.venv” and was able to install &lt;code&gt;requests&lt;/code&gt; which cleaned up the problem.&lt;/p&gt;

&lt;p&gt;I verified that creating a new ticket automatically posted it to the Slack room:&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.amazonaws.com%2Fuploads%2Farticles%2Frnvdwrixxke24rx50wp6.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.amazonaws.com%2Fuploads%2Farticles%2Frnvdwrixxke24rx50wp6.png" alt="Image" width="574" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, I would like the payload to also have a link to the ticket so whoever is using Slack can click the link to view the ticket in my system.  This one is tricky because there is no mechanism yet to view an individual ticket other than the ticket edit screen.  I wonder where this will take me… &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
This is working but I would like to change the message payload in the send_slack_notification function.  I want to add a link to the new ticket so the viewer of the Slack message can click the link and view the ticket in this system. &lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude indeed suggested linking to the edit_ticket URL…&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.amazonaws.com%2Fuploads%2Farticles%2Fjxm7sy2tcfdglwylh5tw.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.amazonaws.com%2Fuploads%2Farticles%2Fjxm7sy2tcfdglwylh5tw.png" alt="JIRA 1" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Claude also took the liberty of improving the UI a bit, adding a View Ticket button.  Nice job!&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.amazonaws.com%2Fuploads%2Farticles%2Fnm2jyya4xzm7ims0ho6s.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.amazonaws.com%2Fuploads%2Farticles%2Fnm2jyya4xzm7ims0ho6s.png" alt="JIRA 2" width="582" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I noticed that the sort order for the All Tickets page was not specified so tickets were displayed as “oldest first”.  I prefer “newest first” and asked Claude to fix this.&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
In the tickets function, please change the sort order to "newest first".&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;The query to retrieve all tickets was correctly updated to&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tickets = Ticket.query.filter((Ticket.deleted == False) | (Ticket.deleted == None)).order_by(Ticket.created_at.desc()).all()&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But how far could I push this?  I asked Claude to update the UI to offer a sort dropdown:&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
On the Tickets page, tickets are now being sorted by newest first.  This works OK but I would like to add a sort feature to this page.  Please add a dropdown list so the tickets can be sorted by Newest First, Oldest First, Assigned To, Priority, Status and Last Updated.  Do the sorting client side to avoid having to reload the page.  Retain the current default.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude gave me a preview of the changes and it looked like some very complex Javascript that would be difficult to maintain.  I fired back with:&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
This looks like it will work but also looks like complex code.  Is there a way to achieve this functionality with built in features from Bootstrap or jQuery instead?&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude agreed:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You're absolutely right, and I apologize for suggesting an overly complex solution. Using Bootstrap and jQuery can indeed simplify this process and make the code more maintainable. Let's revise our approach using Bootstrap's built-in sorting functionality with the DataTables plugin, which works well with jQuery and Bootstrap.&lt;br&gt;
First, we need to include the necessary CSS and JavaScript files for DataTables. We'll add these to the base.html template. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Its next iteration added some Bootstrap / jQuery plugins which added striping to the table but the sort dropdown was not visible. &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I do not see any dropdown to sort the tickets.  Please double check?&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude replies that it did not add a dropdown but instead added functionality to allow sorting by clicking the column heading which is a feature of Bootstrap’s Datatable.  That is not what I asked for but it sounded like a potentially better solution.  But it was not working!&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
If your intention was to allow sorting by clicking the column headers, I would be OK with that but that is not working either.  Please add that functionality instead of the dropdown I originally requested. &lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude thanked me for my flexibility, claimed to fix a few things and gave a nice summary of changes… but it was still not working!&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I like these proposed changes but I am still not seeing them in the UI.  There is no mechanism for sorting or searching.  Please double check?&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;In the middle of debugging this, I got hit with the dreaded:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your per-minute rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Continuing on after a few minutes… Claude added some &lt;code&gt;console.log&lt;/code&gt; statements and asked me to check the server console for these messages.  In doing so, I noticed a script error which I reported back.&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Viewing the console, I see "Script in tickets.html is running", but this is followed by an exception: tickets:160 Uncaught ReferenceError: $ is not defined at tickets:160:1&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude moved some script tags to the top of the &lt;code&gt;base.html&lt;/code&gt; file and everything was working now with a much improved UI!&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.amazonaws.com%2Fuploads%2Farticles%2F8w6tl68tz57ox1jsruuk.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.amazonaws.com%2Fuploads%2Farticles%2F8w6tl68tz57ox1jsruuk.png" alt="Tickets" width="800" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, it left the debug statements in the console.  &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
This is looking much better but you left the console.log debug statements.  Please remove them.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude apologized and removed the debug statements:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I apologize for overlooking the debug statements. You're absolutely right, and we should remove them for a clean production-ready code. Let's update the tickets.html file to remove the console.log statements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I did not like the date and time format being used for the ticket list so I asked Claude to make these more human friendly.  This seemed to break with the new Datatable component.&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.amazonaws.com%2Fuploads%2Farticles%2Fbm87zx5mhlwrmv3sufb6.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.amazonaws.com%2Fuploads%2Farticles%2Fbm87zx5mhlwrmv3sufb6.png" alt="Tickets" width="800" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
When viewing the ticket list, the date/time format used for the Created At and Updated At columns are not user friendly.  Please use the format Month/Day/Year Hour:Minute AM/PM.  We will also need to handle timezone considerations so I need you to suggest a fix for that too. &lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude made the necessary changes to the ticket view, added the &lt;code&gt;pytz&lt;/code&gt; library and is now displaying tickets in the Pacific time zone.  Timezone should be relative to the viewer so we will revisit this when we get to the User Settings page, one of these days.  &lt;/p&gt;

&lt;p&gt;Just some more cleanup to the Tickets page before we go back to Integrations!&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
In the ticket listing, please update the search box to only search the "Title" column. Right now, all fields are being searched.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude’s response:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The ticket list will now display dates in the format "Month/Day/Year Hour:Minute AM/PM" in the US/Pacific timezone, and the search box will only search the "Title" column of the tickets.&lt;br&gt;
These changes provide a more user-friendly date/time format, address timezone considerations, and implement the requested search functionality improvement.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nice work, Claude.  Final UI from this segment: &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.amazonaws.com%2Fuploads%2Farticles%2Fzatyn15rkop6pahpoaiz.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.amazonaws.com%2Fuploads%2Farticles%2Fzatyn15rkop6pahpoaiz.png" alt="Tickets" width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s revisit Integrations.  I had to put another $5 in the tip jar but it is well worth the small investment.  I am learning a lot and the project is progressing.   &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I would like to do some more work on the Integrations part of this project.  I think it would make sense for each Integration to have its own template page with its own settings that are stored in a new database table.  For example, the Slack page should have a checkbox toggle for the user to decide whether to send new ticket data to Slack.  It should also have a text field for the Slack Webhook URL, which should be used instead of the hardcoded URL that is now found in the config.py file. &lt;br&gt;
The other Integrations - Salesforce, JIRA and Webhook should also have their own pages and settings, all stored in the database, which we will be building out once changes to the Slack page are satisfactory. &lt;br&gt;
Each of these pages should inherit the lefthand navigation bar which should always remain visible during navigation. &lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude made the necessary changes to the files and database and it worked fine.  Nice job but it needed some UI tweaks.  &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
This setting should be more descriptive, asking if the user would like to send newly created tickets to Slack.  Also, enforce logic that if this setting is enabled, the URL field must have a valid URL before saving. &lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude showed its proposed changes but I did not like that it was using plain Javascript.  I would rather use jQuery and I asked for the change… &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
It looks like you are using plain Javascript.  Please use jQuery for the Javascript portion.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;This change was working but I still wanted some more UI tweaks… &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Those changes to the Slack integration page are working great but I would like some UI tweaks:  1.  The spacing in the integrations/slack URL is too tight and needs to be improved.  2.  Please use a flash message to show a success message when changes are saved.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude showed its proposed changes but I did not like that it was putting the code for the Flash messages on the Integrations page.  It should go in the &lt;code&gt;base.html&lt;/code&gt; file.  &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
That flashed_messages code might be better off in the base.html file so it can be used on any page that inherits it. Please confirm.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude agreed… &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
That is working but can you use the type of Flash message that disappears automatically after a few seconds?&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Looking good.  One more UI tweak and we should be there…&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.amazonaws.com%2Fuploads%2Farticles%2F5cm9qrt2mw7e2jnahc3w.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.amazonaws.com%2Fuploads%2Farticles%2F5cm9qrt2mw7e2jnahc3w.png" alt="Integrations" width="800" height="279"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
This is looking good but I would like to add a Slack logo to the integrations/slack page.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude wants to make a new “&lt;code&gt;static/images&lt;/code&gt;” directory with the file which makes sense to me.  This is when I realized that the images being used so far were not stored locally.  They were A HREFs pulling images from across the web.  I want to use local images instead and requested this change… &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
This makes sense.  I see there are images in the integrations.html file that are linked from the web and not local.  All of those images should be stored locally in this new static/images directory.  The code should be updated to use them.  Please also make this change.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude made the necessary code changes and ran a cURL command to copy the images locally.  Nicely done!&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.amazonaws.com%2Fuploads%2Farticles%2F2p01uk999odlw90u51s1.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.amazonaws.com%2Fuploads%2Farticles%2F2p01uk999odlw90u51s1.png" alt="Files" width="522" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Now that this is done, I want to follow the same format for the other integrations on the Integrations page - Salesforce, JIRA and Webhook.  Please use the same Configure button which should link to each Integration page in the templates directory.  Add the relevant logo and placeholder text since there are no settings for the other integrations yet. &lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;I hit an API limit while Claude was iterating so needed to take a break.  Here is the UI from the final iteration: &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.amazonaws.com%2Fuploads%2Farticles%2Fdk7lfj2loqstyil3fuc7.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.amazonaws.com%2Fuploads%2Farticles%2Fdk7lfj2loqstyil3fuc7.png" alt="UI" width="800" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-&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.amazonaws.com%2Fuploads%2Farticles%2Fn3nmjpoxl1z8slzg92fi.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.amazonaws.com%2Fuploads%2Farticles%2Fn3nmjpoxl1z8slzg92fi.png" alt="UI" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;h2&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.amazonaws.com%2Fuploads%2Farticles%2Fw1jecyqu3av4tbonj0ws.png" alt="UI" width="800" height="206"&gt;
&lt;/h2&gt;

&lt;p&gt;Now on to JIRA integration.  To keep it simple, I want to do the same as the Slack integration - namely create a new JIRA ticket using an API or webhook.  The JIRA Admin and API docs are a maze of settings, so once again I asked Gemini for a head start:&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
You are an expert Python and Flask developer.  I am developing an application in Python and Flask and I need to integrate with JIRA. I want to use the JIRA API to create new tickets.  How can I do so?  Is there a Python JIRA package or a webhook I should be calling?  Please let me know what I need to enable in the JIRA Admin and give me some code examples.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;It gave me a couple of pointers on where to create an API key but I did not love this answer: “Depending on your JIRA instance (Cloud or Server), you might need to enable specific API permissions for your user or application. Refer to your JIRA administration documentation for details.”&lt;/p&gt;

&lt;p&gt;If I was that smart, I wouldn’t need AI. 🙂&lt;/p&gt;

&lt;p&gt;It did generate a Python code sample making use of the &lt;code&gt;jira&lt;/code&gt; Python package. Let’s see what Claude has to say.&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I would now like to create an integration into JIRA with this ticketing application.  We need to create functionality similar to what was created for the Slack Integration piece, namely sending newly created tickets to JIRA.&lt;br&gt;&lt;br&gt;
How can I do so?  Is there a Python JIRA package or a webhook I should be calling?  Please let me know what I need to enable in the JIRA Admin and then make the necessary changes to this project.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude made a bunch of code and database changes to accommodate my request.  At first glance, they looked OK but the UI for the JIRA settings page removed the JIRA logo so I asked for it to be restored. &lt;/p&gt;

&lt;p&gt;I also did not like the wording for the toggle, asking the user if he wanted to enable JIRA integration with no further context.  I wanted it to match the wording on the Slack integration page:&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I want the UX to match the one you created for the Slack integration page where the checkbox toggle reads "Send newly created tickets to Slack".  Please do the same for the JIRA page.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude made the change but each roundtrip costs money.  A tweak like this could have easily been done manually but I am trying to see how much I can build with only AI prompts and I was curious to see if it would use existing UIs it already created as a guideline.  It did not. &lt;/p&gt;

&lt;p&gt;It also did not do a great job of telling me how to enable the API on the JIRA side whereas Gemini spelled out at least some of it.&lt;/p&gt;

&lt;p&gt;Claude:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the JIRA Admin panel:&lt;br&gt;
Create a new project for your helpdesk tickets (note down the project key)&lt;br&gt;
Create an API token for your JIRA account&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I asked for clarification on how to create the JIRA API key but hit my daily API limit as it was coming up with an answer:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your daily rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With some trial and error, I was able to create the API key and learned that the JIRA API URL is just the URL for your instance of JIRA.  Easy enough.  I put these entries in my system’s admin page and tried to create a ticket.  Ticket creation worked but I saw this exception in the console:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;response text = {"errorMessages":[],"errors":{"priority":"Field 'priority' cannot be set. It is not on the appropriate screen, or unknown."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The code generated by Claude was trying to set the Priority of the ticket in JIRA but that field does not exist in a default JIRA task list.  I commented out this line, tried again and it worked!  You can also add the field in the JIRA project settings as another possible fix.  A more robust JIRA integration would need to have context of the JIRA project, available fields, etc. &lt;/p&gt;

&lt;p&gt;I did see a new field was created in the database for “&lt;code&gt;jira_issue_key&lt;/code&gt;” but it is always blank.  It would be a nice touch to record this and have it visible in the view / edit ticket screen.  I will try to clean this up once my daily API limits reset.&lt;/p&gt;

&lt;p&gt;On to the next day.  I hope Claude is feeling refreshed… &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
During the last task, you created the ability to send new tickets to JIRA.  That is working now but it looks like the feature may be incomplete.  You created a new database field in the ticket table named “jira_issue_key” but it is always blank.  Can you fix this? &lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude added some new code but it still didn’t work… &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I just tried to create a new ticket in our system but the jira_issue_key field is still always blank in the ticket table.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude is very slow today and is returning lots of 500 errors: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;500 {"type":"error","error":{"type":"api_error","message":"Internal server error"}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I went through about a dozen iterations with Claude trying to fix the problem.  It added lots of logging and then some very complex database code that was way above my head.  It was still not working. &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Here is the latest log: INFO:&lt;strong&gt;main&lt;/strong&gt;:New ticket created: #20&lt;br&gt;
INFO:&lt;strong&gt;main&lt;/strong&gt;:Slack notification sent for ticket #20&lt;br&gt;
INFO:&lt;strong&gt;main&lt;/strong&gt;:JIRA issue created: KAN-9 for ticket #20&lt;br&gt;
INFO:&lt;strong&gt;main&lt;/strong&gt;:JIRA issue key KAN-9 assigned to ticket #20&lt;br&gt;
INFO:&lt;strong&gt;main&lt;/strong&gt;:Before commit: Ticket #20 JIRA issue key: KAN-9&lt;br&gt;
INFO:&lt;strong&gt;main&lt;/strong&gt;:All changes committed for ticket #20&lt;br&gt;
INFO:&lt;strong&gt;main&lt;/strong&gt;:After commit: Ticket #20 JIRA issue key: KAN-9&lt;br&gt;
ERROR:&lt;strong&gt;main&lt;/strong&gt;:Failed to retrieve ticket #20 from database after commit And I have noticed that the ticket is no longer being created in the database although I am getting a Success Flash message.  This is worse than the original problem.  Before, I had an empty column but now I have an empty row and a false success message.  Data is being lost without warning in the UI!&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;I am probably going to run out of API requests soon and Claude can’t seem to solve this one and the code is in an ugly place now.  &lt;/p&gt;

&lt;p&gt;Thankfully I saved a commit as a restore point and if I disable JIRA I am still able to create tickets so the system is not completely crippled.  I will put JIRA integration to bed for now and see if Claude can help me with some other features. &lt;/p&gt;

&lt;p&gt;Or maybe not.  Look who it is: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your daily rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After looking at Claude’s code and the logs being generated, I vaguely remember having a similar problem in an old project.  It would create a database entry and then needed to update the row immediately but Flask could not find the record.  The problem was fixed with a &lt;code&gt;db.session.flush()&lt;/code&gt; in my old project and I thought I would look like a genius by adding the fix here, but no luck.  But I figured I would suggest it to Claude as a clue...  Maybe he knows what to do with it.  &lt;/p&gt;

&lt;p&gt;The next day: &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
Yesterday, when we left off I was able to use this system to create a new ticket.  However, if JIRA integration is enabled the jira_issue_key is always blank in the tickets table.  You tried a bunch of different code and logging options but were not able to fix it.  Having to try so many times has cost me some money with the API so I want to make sure we are going down the right path.  In trying to debug it myself, I tried to use db.session.flush() before db.session.commit() but that also had the same problem.  The ticket is created, but the jira_issue_key field is always blank.  Can you try to fix this again?  I can only allow 3 more tries though since this is getting expensive!&lt;br&gt;
[PROMPT]&lt;/p&gt;

&lt;p&gt;I hoped that would light a fire under his ass and keep him focused!&lt;/p&gt;

&lt;p&gt;I told Claude he only had 3 tries but I gave him 8.  The issue is still not fixed.  I am stumped and he is stumped but I need to move on.  This will likely be throwaway code anyway but issues like this drive me crazy!&lt;/p&gt;

&lt;p&gt;I did find that if the table had an entry for the JIRA ticket ID, a button appeared that properly linked to the JIRA ticket which opened in a new window.  So close, yet so far…&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.amazonaws.com%2Fuploads%2Farticles%2F6gp3sdys8a4yo1dlp6sg.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.amazonaws.com%2Fuploads%2Farticles%2F6gp3sdys8a4yo1dlp6sg.png" alt="View JIRA issue" width="612" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I would like to add a couple of new features: A knowledge base and “customer portal” where customers can submit tickets.  &lt;/p&gt;

&lt;p&gt;As a multi-channel ticketing system, customers should be able to submit support cases through email, webform, phone, Twitter, Facebook, SMS, etc.  Webform via customer portal is the easiest so let’s start there… &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I would like to create a new feature in the product and we will need to do it in several steps.  The feature will allow end users to submit support tickets through a webform in our portal, neither of which exist yet.  Please create new templates for customer facing pages: 1.  A knowledge base with placeholder graphics and text.  2.  This page should link to a webform where a user can submit a support case.  The required fields are name, email address, subject and description.  When a user submits the webform, it should create a new case in our system.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;While reviewing the proposed code, I noticed Claude was creating a local placeholder image. Normally I would be fine with this but other placeholder images throughout the product were done using &lt;code&gt;via.placeholder.com&lt;/code&gt;.  I asked Claude to re-use that service to keep the code consistent. I know that earlier I wanted Claude to use local images.  This time I wanted to see if it would continue using the design pattern it started using earlier.  It did not…   &lt;/p&gt;

&lt;p&gt;Claude was also creating some custom CSS for card sizing and I suggested he use the built in Bootstrap classes and he agreed that would be a better idea.  His initial suggestions may work but they are not always best practices or consistent with the rest of the code base… and this is a simple codebase that Claude has created himself.  Always double check the code before accepting it!&lt;/p&gt;

&lt;p&gt;Here is the proposed UI for the Knowledge Base skeleton: &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.amazonaws.com%2Fuploads%2Farticles%2Fk27dm4gt3qmnpqexlfns.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.amazonaws.com%2Fuploads%2Farticles%2Fk27dm4gt3qmnpqexlfns.png" alt="KB" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even though that looked OK, I took a screenshot of a Knowledge Base UI that I liked and asked if Claude could build a UI similar to it.  Computer Vision is supposedly one of Claude’s strengths and I have not used it yet.  So I asked…&lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I would like to change the Knowledge Base UI found in the knowledge-base URL to be more like this image.  Can you emulate this?&lt;br&gt;
[/PROMPT]&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.amazonaws.com%2Fuploads%2Farticles%2Fjepyip0lz0rscsy5vzme.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.amazonaws.com%2Fuploads%2Farticles%2Fjepyip0lz0rscsy5vzme.png" alt="KB" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is what Claude came up with.  Simple, clean and minimalistic… Not bad!&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.amazonaws.com%2Fuploads%2Farticles%2Fhi95ouy37cwyt6fvlvp6.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.amazonaws.com%2Fuploads%2Farticles%2Fhi95ouy37cwyt6fvlvp6.png" alt="Image" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Moving on, I asked Claude to create a webform so users can submit new tickets.  This worked fine but I wanted to modernize the ticket list UX so it shows new tickets without having to refresh.  Off the rails we go! &lt;/p&gt;

&lt;p&gt;[PROMPT]&lt;br&gt;
I would like the tickets table to automatically refresh if the system receives a new ticket. Maybe we can use something like a websocket? New tickets should also flash yellow when they appear.&lt;br&gt;
[/PROMPT]&lt;/p&gt;

&lt;p&gt;Claude added the usual code for &lt;code&gt;sockets-io&lt;/code&gt;, etc.  The first attempt did not work - new tickets were created but the tickets Datatable did not update so Claude added some logging.  Funny, I have this problem all the time with websockets too.  I find it very confusing and it never works without some hair pulling. &lt;/p&gt;

&lt;p&gt;Claude:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Thank you for providing the error message. It appears that there's an issue with the WebSocket connection. Let's try to resolve this by making some adjustments to our WebSocket configuration.&lt;br&gt;
First, let's update the app.py file to ensure that CORS (Cross-Origin Resource Sharing) is properly configured for the WebSocket connection&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;API Request Failed&lt;/p&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your daily rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This API limit is going to kill me.&lt;/p&gt;

&lt;p&gt;On to a new day...&lt;/p&gt;

&lt;p&gt;We went round and round about a dozen times with websocket errors and logging but Claude can’t seem to fix this one.  &lt;/p&gt;

&lt;p&gt;The console logging suggest that it should be working fine but when I submit a new ticket, a Javascript alert pops up:&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.amazonaws.com%2Fuploads%2Farticles%2F564tbt1tct7aw4g7807t.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.amazonaws.com%2Fuploads%2Farticles%2F564tbt1tct7aw4g7807t.png" alt="Image" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I asked Claude if he had access to view live pages on the web and suggested he review the following URLs for potential fixes: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://datatables.net/forums/discussion/42814/requested-unknown-parameter-object-object" rel="noopener noreferrer"&gt;https://datatables.net/forums/discussion/42814/requested-unknown-parameter-object-object&lt;/a&gt;&lt;br&gt;
And &lt;a href="http://datatables.net/tn/4" rel="noopener noreferrer"&gt;http://datatables.net/tn/4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;He reviewed the pages, changed the format of the data being passed to the Datatable but still no luck!  Similar to the JIRA ticket issue, it looks like Claude is stumped, my API credits are about to run out and I am left with code that is littered with attempted fixes and logging.  Again, good thing I committed code of the last good build.&lt;/p&gt;

&lt;p&gt;Hey, guess who came to dinner:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;API Request Failed&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your daily rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;[SIDEBAR]&lt;/p&gt;

&lt;p&gt;I asked Gemini if it could build a UI that emulated the same knowledge base UI that I fed to Claude.  As a reminder, this way the image I used:&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.amazonaws.com%2Fuploads%2Farticles%2Fjepyip0lz0rscsy5vzme.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.amazonaws.com%2Fuploads%2Farticles%2Fjepyip0lz0rscsy5vzme.png" alt="KB" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was Gemini’s interpretation after several iterations.  The styling is all off, everything is off center, etc.  I am surprised that the results are so poor.  I did not spend more than 15 minutes on it since it was not progressing much…&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.amazonaws.com%2Fuploads%2Farticles%2F7anb8c8ssquugrsabnll.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.amazonaws.com%2Fuploads%2Farticles%2F7anb8c8ssquugrsabnll.png" alt="Gemini KB" width="800" height="1098"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am trying to use Gemini to fill in the gaps when Claude hits me with API limits.  I guess its Computer Vision is not yet up to snuff though… &lt;/p&gt;

&lt;p&gt;[/SIDEBAR]&lt;/p&gt;

&lt;p&gt;Painful.  To be continued when I regain my strength. 🙂&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/chiefremote/part-3-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4pck"&gt;LINK TO PART 3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/chiefremote/using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4aek"&gt;Part 1&lt;/a&gt; | &lt;a href="https://dev.to/chiefremote/part-4-using-cursor-and-claude-to-create-automated-tests-with-playwright-2p7j"&gt;Part 4&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;ABOUT THE AUTHOR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Joe Giglio is a 25+ year veteran of the software industry. In his career, he has worked for a local dial-up ISP, startups of all sizes and a well established, slow moving enterprise. There were important lessons learned along every stop.&lt;/p&gt;

&lt;p&gt;His recent projects include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Remote work training and consulting: &lt;a href="//chiefremoteofficer.com"&gt;chiefremoteofficer.com&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://amzn.to/3YHp4AK" rel="noopener noreferrer"&gt;Kindle book "Making Remote Work, Work For You"&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remote company rankings.  Think "Glassdoor for remote companies": &lt;a href="https://www.remotescorecard.com/" rel="noopener noreferrer"&gt;remotescorecard.com&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Joe’s guiding principles are: Remote first, quality driven, customer champion and lifelong learning. He was an introvert and practiced social distancing long before it was cool!&lt;/p&gt;

&lt;p&gt;He currently resides in North Carolina and is always interested in new opportunities, meeting quality people and learning about exciting projects. &lt;/p&gt;

&lt;p&gt;Contact Joe Giglio: joe -AT- joegiglio.org | &lt;a href="https://x.com/ChiefRemote" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; | &lt;a href="https://www.linkedin.com/in/joegiglio/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Part 1 - Using Claude, Claude-Dev and Aider to Build a Ticketing System</title>
      <dc:creator>Joe Giglio, Chief Remote Officer</dc:creator>
      <pubDate>Tue, 13 Aug 2024 21:04:33 +0000</pubDate>
      <link>https://dev.to/chiefremote/using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4aek</link>
      <guid>https://dev.to/chiefremote/using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4aek</guid>
      <description>&lt;p&gt;&lt;strong&gt;MARCH 2025 UPDATE:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I tried a similar experiment using Windsurf with Claude 3.5.  How did it compare?&lt;/p&gt;

&lt;p&gt;The only way to know for sure is to watch my video series, &lt;a href="https://www.youtube.com/playlist?list=PLLRCLXxv4S0fYqYMJfawS8TyY_S78YEkg" rel="noopener noreferrer"&gt;"The Truth about Vibe Coding with Windsurf… Better than Cursor?”&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/chiefremote/part-2-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-5hnd"&gt;Part 2&lt;/a&gt; | &lt;a href="https://dev.to/chiefremote/part-3-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4pck"&gt;Part 3&lt;/a&gt; | &lt;a href="https://dev.to/chiefremote/part-4-using-cursor-and-claude-to-create-automated-tests-with-playwright-2p7j"&gt;Part 4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PART 1 -&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The project has been open sourced if you would like to play along at home: &lt;a href="https://github.com/joegiglio/helpdesk-claude-dev-ai" rel="noopener noreferrer"&gt;https://github.com/joegiglio/helpdesk-claude-dev-ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AI is probably coming for all of us eventually.  It promises to make companies “more efficient” but how far along is it right now?  Can it really be used to replace software developers?  Can you just pick a tech stack, tell AI what to write and put your feet up while the money rolls in?&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.amazonaws.com%2Fuploads%2Farticles%2Fmoze6dpnv5aaacyrpxw2.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fmoze6dpnv5aaacyrpxw2.jpg" alt="Money" width="640" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I had tinkered with the usual LLMs - Copilot, ChatGPT, Gemini, Gab and Claude.  I found them all to be capable of helping to create boilerplate code, adding basic unit tests and acting as a reliable pair programmer.  The answers are usually pretty good but not without error.  They give a solid starting point and prevent you from having to deal with all the geniuses on Stack Overflow.  &lt;/p&gt;

&lt;p&gt;I have seen demo videos of snake games and To-Do list web apps being created using only AI prompts without code and I wanted to take it further.  Having a background in help desk and ticketing software, I wanted to push AI to create a ticketing system and see how far I can take it with integrations into third party apps such as Slack and Salesforce.  &lt;/p&gt;

&lt;p&gt;So what would my AI stack be?  At the moment, the buzz seems to be around Claude, paired with VS Code extensions Claude-Dev and Aider so I figured I would start there.  I believe the best tool for the job is the one you are most familiar with, so I would ask AI to use a tech stack of Python, Flask, SQLite, Bootstrap and jQuery.  Keeping with languages I am familiar with will help me with the inevitable debugging and maintenance.&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.amazonaws.com%2Fuploads%2Farticles%2Fym3tfdo4dz2uxi9swokf.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.amazonaws.com%2Fuploads%2Farticles%2Fym3tfdo4dz2uxi9swokf.png" alt="Claude logo" width="800" height="449"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Using these plug-ins requires an API key but acquiring one is not as straightforward as you might expect.  You create your account and login at &lt;a href="https://claude.ai/" rel="noopener noreferrer"&gt;https://claude.ai/&lt;/a&gt; but need to obtain your API key from &lt;a href="https://console.anthropic.com/" rel="noopener noreferrer"&gt;https://console.anthropic.com/&lt;/a&gt; and there is no obvious link… or at least there was none during my initial draft but now there is. :)  &lt;/p&gt;

&lt;p&gt;Once I had my API key, I needed to add credits to my account or API requests would be rejected.  Luckily, Anthropic is running a $5 credit promotion which appears in your dashboard.  I accepted the offer, was texted a validation code which I entered and then…nothing.  I did not see any credits.  I was stuck in a loop of offer/validation/acceptance and could not get the credits to appear in my account.  I sent them an email and figured I would try again the next day.&lt;/p&gt;

&lt;p&gt;The next day came and there was no reply so I just decided to purchase $5 worth of credits and get on with the show.  First up, I would try Aider which runs in a VS Code terminal window.  I am not crazy about the UI but configuration was easy enough, it makes Github commits after each step and it gets great reviews on Youtube so it was worth a try.  &lt;/p&gt;

&lt;p&gt;Here is the initial prompt I used.  I chopped it into a couple of pieces so I could check the work as we went along.  Much like people, AI works best iteratively, giving you a chance to make sure things are working as intended at each milestone and giving you an opportunity to debug and clean up.&lt;/p&gt;

&lt;p&gt;[START FIRST PROMPT] &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I would like to create simple help desk software using AI to build the product.  Instructions will be given iteratively so it can be built piece by piece.&lt;br&gt;&lt;br&gt;
You are an expert web developer with expertise in Python and Flask.  All code must be secure to prevent SQL injection and other attacks.  All fields must have reasonable size limits and maxlengths.  Field lengths and data types are to be protected on the client and server side.&lt;br&gt;&lt;br&gt;
The technical requirements are:&lt;/p&gt;

&lt;p&gt;Python&lt;br&gt;
Flask&lt;br&gt;
Fast-API&lt;br&gt;
Bootstrap&lt;br&gt;
jQuery&lt;br&gt;
We will initially use SQLite for simplicity but will move to MySQL at some point so keep that in mind.&lt;br&gt;&lt;br&gt;
All pages must be responsive and work well on desktop, tablet and mobile screen resolutions. The product will be API-First with all CRUD operations working through the API layer using Fast-API.  This includes fields for support tickets as well as administration such as users, preferences and other settings. &lt;br&gt;
Integrations with other popular products such as Slack, JIRA and Salesforce and the ability to send data to a webhook URL will be important for adoption so keep that in mind while building the core of this platform.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[END FIRST PROMPT]  &lt;/p&gt;

&lt;p&gt;[START SECOND PROMPT] &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Product requirements for the first iteration:&lt;br&gt;
Build a lefthand bar with the following links:&lt;br&gt;
Tickets&lt;br&gt;
Integrations&lt;br&gt;
Workflows&lt;br&gt;
Team&lt;br&gt;
Settings&lt;br&gt;
Each of these links will be its own files in the templates directory.&lt;/p&gt;

&lt;p&gt;When clicking one of the entries on the left navigation bar, the right side will refresh with the necessary data.  Examples:&lt;br&gt;
When you click Tickets, show a list of existing cases and a link to create a new case. &lt;br&gt;
When creating a new case, display the following fields:&lt;br&gt;
Ticket ID (Numeric, auto generated, read only but visible)&lt;br&gt;
Customer First Name (field length 25, maxlength 50)&lt;br&gt;
Customer Last Name (field length 25, maxlength 50)&lt;br&gt;
Customer Email (field length 25, maxlength 50)&lt;br&gt;
Subject (field length 50, maxlength 100)&lt;br&gt;
Priority (Dropdown with values 1-Urgent, 2-Important, 3-Normal, 4-Low)&lt;br&gt;
Assignee (Dropdown with a list of dummy data for now)&lt;br&gt;
Details (Large textarea, maxlength 50,000)&lt;/p&gt;

&lt;p&gt;There should be a save button so you can save the case. &lt;br&gt;
When you click Integrations on the left navigation bar, show logos and placeholder data for Slack, JIRA and Salesforce. &lt;br&gt;
When you click Workflows on the left navigation bar, show a placeholder header graphic and placeholder data.&lt;br&gt;
When you click Team on the left navigation bar, show a placeholder header graphic and placeholder data.&lt;br&gt;&lt;br&gt;
When you click Settings on the left navigation bar, show a placeholder header graphic and placeholder data. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[END SECOND PROMPT] &lt;/p&gt;

&lt;p&gt;After running the first part of the prompt, I checked the project structure and files.  I was surprised and impressed to find that it generated a modular Flask file structure, with blueprints, separate routes files and Pydantic for strong typing which I believe is required for FastAPI.  &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.amazonaws.com%2Fuploads%2Farticles%2Fzlmytd7vzat4n2gy67d4.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.amazonaws.com%2Fuploads%2Farticles%2Fzlmytd7vzat4n2gy67d4.png" alt="a" width="189" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Out of the box, Flask allows you to quickly crank out code and it is not strict about file structure or naming conventions other than the ‘static’ folder.  This allows you to get up and running without a lot of ceremony which can be a benefit or drawback depending on the project.  Aider, with Claude, was taking my project right into the deep end into somewhat unfamiliar territory but I liked what I saw so far!     &lt;/p&gt;

&lt;p&gt;However, the server would not start and dependency version conflicts took about 10 attempts to fix.  Each request costs money and goes against your hourly and daily quota.  Yes, it gives you the wrong code and yes, you have to pay for it to clean up and may be “put on timeout” if you ask it too many times while it works through the problem. &lt;/p&gt;

&lt;p&gt;Although the server finally started and seemed to be working, it was using Uvicorn as its web server and it was not configured to detect changes to files other than Python.  This meant every time I made a change to the HTML or CSS, I had to remember to manually restart the server.  I found a few possible solutions from Claude and other websites but I could not get this to work.  I put that annoyance aside and would go another round the next day.&lt;/p&gt;

&lt;p&gt;Here is the initial UI Claude generated: &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.amazonaws.com%2Fuploads%2Farticles%2Fxzzdp0ld4u4d9ika2jk9.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.amazonaws.com%2Fuploads%2Farticles%2Fxzzdp0ld4u4d9ika2jk9.png" alt="b" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I spent some more time on the server restart problem the next day but still had no luck so I decided to add this requirement to the project requirement prompts along with some other tweaks to fix shortcomings from the first round.  I created a new folder and went another round with Aider:&lt;/p&gt;

&lt;p&gt;[START FIRST PROMPT] &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I would like to create simple help desk software using AI to build the product.  Instructions will be given iteratively so it can be built piece by piece.&lt;br&gt;&lt;br&gt;
You are an expert web developer with expertise in Python and Flask.  All code must be secure to prevent SQL injection and other attacks.  All fields must have reasonable size limits and maxlengths.  Field lengths and data types are to be protected on the client and server side.&lt;br&gt;&lt;br&gt;
The technical requirements are:&lt;/p&gt;

&lt;p&gt;Python&lt;br&gt;
Flask&lt;br&gt;
Fast-API&lt;br&gt;
Bootstrap&lt;br&gt;
jQuery&lt;br&gt;
We will initially use SQLite for simplicity but will move to MySQL at some point so keep that in mind. &lt;br&gt;
I am using VS Code as my IDE.  Please make sure that changes to all files such as HTML templates and CSS files trigger an automatic restart of the web server.  &lt;/p&gt;

&lt;p&gt;All pages must be responsive and work well on desktop, tablet and mobile screen resolutions. The product will be API-First with all CRUD operations working through the API layer using Fast-API.  This includes fields for support tickets as well as administration such as users, preferences and other settings. &lt;br&gt;
Integrations with other popular products such as Slack, JIRA and Salesforce and the ability to send data to a webhook URL will be important for adoption so keep that in mind while building the core of this platform. &lt;/p&gt;

&lt;p&gt;Let me know how to install all the necessary dependencies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[END FIRST PROMPT] &lt;/p&gt;

&lt;p&gt;[START SECOND PROMPT] &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Product requirements for the first iteration:&lt;br&gt;
Build a lefthand bar with the following links:&lt;br&gt;
Tickets&lt;br&gt;
Integrations&lt;br&gt;
Workflows&lt;br&gt;
Team&lt;br&gt;
Settings&lt;/p&gt;

&lt;p&gt;Each of these links will be its own files in the templates directory.&lt;br&gt;&lt;br&gt;
When clicking one of the entries on the left navigation bar, the right side will refresh with the necessary data and the left navigation bar will still appear.  Examples:&lt;br&gt;
When you click Tickets, show a list of existing cases and a link to create a new case. &lt;br&gt;
When creating a new case, display typical fields that are found in ticketing software.  Each should have a reasonable field length and maxlength. &lt;/p&gt;

&lt;p&gt;There should be a save button so you can save the case to the database. &lt;br&gt;
When you click Integrations on the left navigation bar, show logos and placeholder data for Slack, JIRA and Salesforce. &lt;br&gt;
When you click Workflows on the left navigation bar, show a placeholder header graphic and placeholder data.&lt;br&gt;
When you click Team on the left navigation bar, show a placeholder header graphic and placeholder data. &lt;br&gt;
When you click Settings on the left navigation bar, show a placeholder header graphic and placeholder data. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[END SECOND PROMPT] &lt;/p&gt;

&lt;p&gt;I ended up with a similar file structure as the first attempt but the server would not start due to circular import issues, a familiar pain point for Python developers when they try to modularize their code and break pieces into separate directories: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;ImportError: cannot import name 'routes' from partially initialized module 'helpdesk_app' (most likely due to a circular import) (/home/joe/Documents/programming/python/helpdesk2/helpdesk_app/__init__.py)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Aider was able to fix this and similar issues after several attempts.  Finally, I could get the server to start without issue but when I tried to hit the homepage, it generated a database exception which I fed back to Aider: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When I try to hit the homepage I am getting this error.  It looks like a problem with the database:  sqlite3.OperationalError: no such table: tickets&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aider itself immediately crashes with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Traceback (most recent call last):&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/bin/aider", line 8, in &amp;lt;module&amp;gt;&lt;br&gt;
    sys.exit(main())&lt;br&gt;
             ^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/main.py", line 620, in main&lt;br&gt;
    coder.run()&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/coders/base_coder.py", line 685, in run&lt;br&gt;
    self.run_one(user_message, preproc)&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/coders/base_coder.py", line 723, in run_one&lt;br&gt;
    list(self.send_message(message))&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/coders/base_coder.py", line 945, in send_message&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;messages = self.format_messages()&lt;br&gt;
               ^^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/coders/base_coder.py", line 904, in format_messages&lt;br&gt;
    messages_tokens = self.main_model.token_count(messages)&lt;br&gt;
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/models.py", line 532, in token_count&lt;br&gt;
    return litellm.token_counter(model=self.name, messages=messages)&lt;br&gt;
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/litellm/utils.py", line 1987, in token_counter&lt;br&gt;
    num_tokens += calculage_img_tokens(&lt;br&gt;
                  ^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/litellm/utils.py", line 1834, in calculage_img_tokens&lt;br&gt;
    resized_width, resized_height = resize_image_high_res(&lt;br&gt;
                                    ^^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/litellm/utils.py", line 1751, in resize_image_high_res&lt;br&gt;
    if width &amp;lt;= 768 and height &amp;lt;= 768:&lt;br&gt;
       ^^^^^^^^^^^^&lt;br&gt;
TypeError: '&amp;lt;=' not supported between instances of 'NoneType' and 'int'&lt;br&gt;
(.venv) joe@mint:~/Documents/programming/python/helpdesk1$ aider&lt;br&gt;
Aider v0.49.1&lt;br&gt;
Models: claude-3-5-sonnet-20240620 with diff edit format, weak model claude-3-haiku-20240307&lt;br&gt;
Git repo: .git with 21 files&lt;br&gt;
Repo-map: using 1024 tokens&lt;br&gt;
VSCode terminal detected, pretty output has been disabled.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Trying again:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It looks like the database tables were never created or initialized.  Can you create code to do so?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;Traceback (most recent call last):&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/bin/aider", line 8, in &amp;lt;module&amp;gt;&lt;br&gt;
    sys.exit(main())&lt;br&gt;
             ^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/main.py", line 620, in main&lt;br&gt;
    coder.run()&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/coders/base_coder.py", line 685, in run&lt;br&gt;
    self.run_one(user_message, preproc)&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/coders/base_coder.py", line 723, in run_one&lt;br&gt;
    list(self.send_message(message))&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/coders/base_coder.py", line 945, in send_message&lt;br&gt;
    messages = self.format_messages()&lt;br&gt;
               ^^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/coders/base_coder.py", line 892, in format_messages&lt;br&gt;
    messages += self.get_files_messages()&lt;br&gt;
                ^^^^^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/coders/base_coder.py", line 592, in get_files_messages&lt;br&gt;
    repo_content = self.get_repo_map()&lt;br&gt;
                   ^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/coders/base_coder.py", line 564, in get_repo_map&lt;br&gt;
    repo_content = self.repo_map.get_repo_map(&lt;br&gt;
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/repomap.py", line 105, in get_repo_map&lt;br&gt;
    files_listing = self.get_ranked_tags_map(&lt;br&gt;
                    ^^^^^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/repomap.py", line 448, in get_ranked_tags_map&lt;br&gt;
    num_tokens = self.token_count(tree)&lt;br&gt;
                 ^^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/repomap.py", line 69, in token_count&lt;br&gt;
    return self.main_model.token_count(text)&lt;br&gt;
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/models.py", line 542, in token_count&lt;br&gt;
    return len(self.tokenizer(msgs))&lt;br&gt;
               ^^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/models.py", line 528, in tokenizer&lt;br&gt;
    return litellm.encode(model=self.name, text=text)&lt;br&gt;
           ^^^^^^^^^^^^^^&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/llm.py", line 20, in __getattr__&lt;br&gt;
    self._load_litellm()&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/aider/llm.py", line 27, in _load_litellm&lt;br&gt;
    self._lazy_module = importlib.import_module("litellm")&lt;br&gt;
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "/usr/lib/python3.12/importlib/__init__.py", line 90, in import_module&lt;br&gt;
    return _bootstrap._gcd_import(name[level:], package, level)&lt;br&gt;
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;br&gt;
  File "&amp;lt;frozen importlib._bootstrap&amp;gt;", line 1387, in _gcd_import&lt;br&gt;
  File "&amp;lt;frozen importlib._bootstrap&amp;gt;", line 1360, in _find_and_load&lt;br&gt;
  File "&amp;lt;frozen importlib._bootstrap&amp;gt;", line 1331, in _find_and_load_unlocked&lt;br&gt;
  File "&amp;lt;frozen importlib._bootstrap&amp;gt;", line 935, in _load_unlocked&lt;br&gt;
  File "&amp;lt;frozen importlib._bootstrap_external&amp;gt;", line 995, in exec_module&lt;br&gt;
  File "&amp;lt;frozen importlib._bootstrap&amp;gt;", line 488, in _call_with_frames_removed&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/litellm/__init__.py", line 20, in &amp;lt;module&amp;gt;&lt;br&gt;
    from litellm.proxy._types import (&lt;br&gt;
  File "/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/litellm/proxy/_types.py", line 10, in &amp;lt;module&amp;gt;&lt;br&gt;
    from pydantic import BaseModel, ConfigDict, Extra, Field, Json, model_validator&lt;br&gt;
ImportError: cannot import name 'model_validator' from 'pydantic' (/home/joe/Documents/programming/python/helpdesk1/.venv/lib/python3.12/site-packages/pydantic/__init__.py). Did you mean: 'root_validator'?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Another exception - something Pydantic related?  Way out of my league...&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.amazonaws.com%2Fuploads%2Farticles%2F3xiu3h4czzv6iudcg0i9.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F3xiu3h4czzv6iudcg0i9.jpg" alt="c" width="640" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was stuck and STILL had the web server restart issue.  It was discouraging but I decided to simplify the initial application by removing the Fast-API requirements and sticking with a simpler Flask structure to see if I can get the basics to work and then push into the more advanced stuff iteratively.&lt;/p&gt;

&lt;p&gt;These are the prompts I used next.  There are some differences including instructions around the virtual directory, removal of FastAPI and the generating of a .gitignore file.&lt;/p&gt;

&lt;p&gt;[START FIRST PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I would like to create simple help desk software using AI to build the product.  Instructions will be given iteratively so it can be built piece by piece.&lt;br&gt;&lt;br&gt;
You are an expert web developer with expertise in Python and Flask.  All code must be secure to prevent SQL injection and other attacks.  All fields must have reasonable size limits and maxlengths.  Field lengths and data types are to be protected on the client and server side.&lt;br&gt;&lt;br&gt;
The technical requirements are:&lt;br&gt;
Python&lt;br&gt;
Flask&lt;br&gt;
Bootstrap&lt;br&gt;
jQuery&lt;/p&gt;

&lt;p&gt;We will initially use SQLite for simplicity but will move to MySQL at some point so keep that in mind. Be sure to initialize the database.&lt;br&gt;&lt;br&gt;
Let me know how to install all the necessary dependencies. The virtual environment has already been created and is active.  The directory name is “venv”.&lt;br&gt;&lt;br&gt;
Generate an appropriate .gitignore file for the project and include the venv directory in it. &lt;br&gt;
I am using VS Code as my IDE.  Please make sure that changes to all files such as HTML templates and CSS files trigger an automatic restart of the web server.&lt;br&gt;&lt;br&gt;
All pages must be responsive and work well on desktop, tablet and mobile screen resolutions. &lt;br&gt;
Integrations with other popular products such as Slack, JIRA and Salesforce and the ability to send data to a webhook URL will be important for adoption so keep that in mind while building the core of this platform.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[END FIRST PROMPT]&lt;/p&gt;

&lt;p&gt;[START SECOND PROMPT]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Product requirements for the first iteration:&lt;br&gt;
Build a lefthand bar with the following links:&lt;br&gt;
Tickets&lt;br&gt;
Integrations&lt;br&gt;
Workflows&lt;br&gt;
Team&lt;br&gt;
Settings&lt;br&gt;
Each of these links will be its own files in the templates directory.&lt;br&gt;&lt;br&gt;
When clicking one of the entries on the left navigation bar, the right side will refresh with the necessary data and the left navigation bar will still appear.  Examples:&lt;br&gt;
When you click Tickets, show a list of existing cases and a link to create a new case. &lt;/p&gt;

&lt;p&gt;When creating a new case, display typical fields that are found in ticketing software.  Each should have a reasonable field length and maxlength.&lt;br&gt;&lt;br&gt;
There should be a save button so you can save the case to the database. &lt;br&gt;
When you click Integrations on the left navigation bar, show logos and placeholder data for Slack, JIRA and Salesforce. &lt;br&gt;
When you click Workflows on the left navigation bar, show a placeholder header graphic and placeholder data.&lt;br&gt;
When you click Team on the left navigation bar, show a placeholder header graphic and placeholder data.  &lt;/p&gt;

&lt;p&gt;When you click Settings on the left navigation bar, show a placeholder header graphic and placeholder data.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;[END SECOND PROMPT]&lt;/p&gt;

&lt;p&gt;The server started right up and the file structure was much simpler:&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.amazonaws.com%2Fuploads%2Farticles%2Ftihvezwd4jycb4y1tfg4.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.amazonaws.com%2Fuploads%2Farticles%2Ftihvezwd4jycb4y1tfg4.png" alt="d" width="726" height="1082"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything seemed to work OK and I was also impressed with what Claude did with the skeleton of the Integrations page:&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.amazonaws.com%2Fuploads%2Farticles%2F1orkg2tzsbgdb9bca8ww.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.amazonaws.com%2Fuploads%2Farticles%2F1orkg2tzsbgdb9bca8ww.png" alt="e" width="800" height="154"&gt;&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2F381tuziwpy3gx5qcpr7h.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.amazonaws.com%2Fuploads%2Farticles%2F381tuziwpy3gx5qcpr7h.png" alt="Integrations Page" width="800" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I noticed that the .gitignore file was generated but it was not excluding the “.venv” directory which was my mistake.  I originally instructed it to look for a “venv” directory instead of a “.venv” directory.  AI is only as smart as what you feed it and it can’t read your mind.  Yet.  &lt;/p&gt;

&lt;p&gt;I then prompted:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The basic frameworks seems to be working OK but I would like to add more fields for each ticket.  Please add more field types that would be typical of a helpdesk ticketing application.  Each field must be an appropriate length with maxsize enforced on the client and server side. &lt;br&gt;
Also create the ability to edit each ticket from the tickets page.  Clicking the ticket ID field would be the logical place to add this functionality. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This worked great and I thanked Claude and prompted him to take a break but I got this error message:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your per-minute rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;OK then… I let it sit for a while and wanted to see if Claude could add “ticket delete” functionality.  I created a new branch and prompted: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please now add the ability to delete a ticket.  For now, let’s just mark a ticket as deleted and not physically delete it from the database.  Add a delete option to each ticket in the listing of all tickets.  Use an X icon.  Confirm deletion.  Hide deleted tickets from the list of all tickets.  We will soon build a view to show only deleted tickets.  Be sure to update the database schemas as appropriate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This returned another rate limit error:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;429 {"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your daily rate limit (https://docs.anthropic.com/en/api/rate-limits); see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase."}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Womp, womp… I guess Claude will get the rest of the day off and I will see how far I can push it tomorrow.&lt;/p&gt;

&lt;p&gt;The next day, I fed the same prompt and it returned a well thought out response to show that it understood the technical requirements:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;To accomplish this task, we'll need to make several changes to our existing codebase. Let's break it down into steps and use the available tools to implement these changes.&lt;br&gt;
We need to update the database schema to add a 'deleted' column to the tickets table.&lt;br&gt;
We need to modify the app.py file to add a new route for deleting tickets.&lt;br&gt;
We need to update the tickets.html template to add a delete button with an X icon for each ticket.&lt;br&gt;
We need to modify the existing route that lists all tickets to exclude deleted tickets.&lt;br&gt;
Let's start by examining the current state of our app.py file and the tickets.html template.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After showing me the proposed change step-by-step, Claude reported back that it was done!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Task Completed&lt;br&gt;
The ability to delete tickets has been successfully implemented. Here's a summary of the changes:&lt;br&gt;
Updated the Ticket model in app.py to include a 'deleted' column (Boolean, default False).&lt;br&gt;
Modified the tickets route to only show non-deleted tickets using Ticket.query.filter_by(deleted=False).all().&lt;br&gt;
Added a new route /tickets/&amp;lt;int:id&amp;gt;/delete for soft deleting tickets.&lt;br&gt;
Updated the tickets.html template to include a delete button with an X icon for each ticket.&lt;br&gt;
Added confirmation dialog before deleting a ticket.&lt;br&gt;
Ran database migrations to apply the schema changes.&lt;br&gt;
These changes allow users to mark tickets as deleted without physically removing them from the database. Deleted tickets are hidden from the main ticket list, and we can easily implement a view to show only deleted tickets in the future.&lt;br&gt;
To see the changes in action, you can run the Flask application and navigate to the tickets page. You should see the new delete buttons (X icons) next to each ticket. Clicking on a delete button will prompt for confirmation before marking the ticket as deleted.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I saw the new column in the database but now none of my tickets were appearing in the list:&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.amazonaws.com%2Fuploads%2Farticles%2F7h8n37lu43gpgu5a1sq0.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.amazonaws.com%2Fuploads%2Farticles%2F7h8n37lu43gpgu5a1sq0.png" alt="Ticket list" width="800" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Newly created tickets were appearing and this is the code generated to query for non deleted tickets:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;def tickets():&lt;br&gt;
    tickets = Ticket.query.filter_by(deleted=False).all()  # Only show non-deleted tickets&lt;br&gt;
    return render_template('tickets.html', tickets=tickets)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Based on my experience, this is probably a zero vs. null issue.  I asked Claude to fix it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;None of the existing tickets are appearing in the ticket list but newly created tickets do appear. The query for getting all tickets may be incorrect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The response:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;I apologize for the oversight. It seems there's an issue with the query for retrieving tickets. Let's fix this problem by adjusting the query in the app.py file. We'll modify the tickets route to correctly display existing tickets while still hiding the deleted ones.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Claude updated the code to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;def tickets():&lt;br&gt;
    tickets = Ticket.query.filter((Ticket.deleted == False) | (Ticket.deleted == None)).all()  # Show non-deleted tickets and tickets without the 'deleted' attribute&lt;br&gt;
    return render_template('tickets.html', tickets=tickets)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;…and now it works as intended with a new column and deletion confirmation:&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.amazonaws.com%2Fuploads%2Farticles%2F22uyatiea2o0dq32lu8a.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.amazonaws.com%2Fuploads%2Farticles%2F22uyatiea2o0dq32lu8a.png" alt="Delete column" width="800" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am not too crazy about the delete icon but I am just about out of Claude credits.  I will continue on this journey for the next part of this journal.&lt;/p&gt;

&lt;p&gt;SIDE NOTE - While iterating on this project, I somehow ended up with an instance that requires user login for all of the pages.  I did not explicitly ask for this and I am not sure how we ended up here.  I had to reboot my system and lost all my Aider / Claude history and I am not sure if it can be retrieved.  However, the first check in for the Master branch does show a “flask_login” import, followed by a bunch of fixes and refactors.  Those refactors added a &lt;code&gt;@login_required&lt;/code&gt; decorator to every page.&lt;/p&gt;

&lt;p&gt;After all those fixes and refactors, each page of the UI is asking for a login but there is no mechanism for creating an account.  I will need this feature at some point but not yet. Now it is just in the way.  This goes to show that you should not blindly accept the code without reviewing it and you really need to understand what you are looking at.  Claude took creative liberties and added a feature I did not ask for.&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.amazonaws.com%2Fuploads%2Farticles%2F3gw0q648loo5vefuoavo.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.amazonaws.com%2Fuploads%2Farticles%2F3gw0q648loo5vefuoavo.png" alt="Code" width="596" height="438"&gt;&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2Fpxsh3yw8ugyz1had20m7.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.amazonaws.com%2Fuploads%2Farticles%2Fpxsh3yw8ugyz1had20m7.png" alt="Login" width="800" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was an interesting exercise for me and hopefully you found it insightful.  I found that Claude has the same battles I would have once I push beyond a basic Flask setup - issues with circular imports, dependency version hell, etc.  New day, new tool, same old problems.&lt;/p&gt;

&lt;p&gt;Just like any of the “no code tools”, the audience that will benefit the most are the people who have had experience writing code from line one, understand programming concepts, are able to clearly explain requirements in the written form and have troubleshooting experience in the tech stack at hand.&lt;/p&gt;

&lt;p&gt;I will be pushing this project further iteratively to see how far I can take it.  &lt;/p&gt;

&lt;p&gt;Next up: &lt;strong&gt;Integrations!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/chiefremote/part-2-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-5hnd"&gt;Part 2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/chiefremote/part-3-using-claude-claude-dev-and-aider-to-build-a-ticketing-system-4pck"&gt;Part 3&lt;/a&gt; | &lt;a href="https://dev.to/chiefremote/part-4-using-cursor-and-claude-to-create-automated-tests-with-playwright-2p7j"&gt;Part 4&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;ABOUT THE AUTHOR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Joe Giglio is a 25+ year veteran of the software industry. In his career, he has worked for a local dial-up ISP, startups of all sizes and a well established, slow moving enterprise. There were important lessons learned along every stop.&lt;/p&gt;

&lt;p&gt;His recent projects include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Remote work training and consulting: &lt;a href="//chiefremoteofficer.com"&gt;chiefremoteofficer.com&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://amzn.to/3YHp4AK" rel="noopener noreferrer"&gt;Kindle book "Making Remote Work, Work For You"&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remote company rankings.  Think "Glassdoor for remote companies": &lt;a href="https://www.remotescorecard.com/" rel="noopener noreferrer"&gt;remotescorecard.com&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Joe’s guiding principles are: Remote first, quality driven, customer champion and lifelong learning. He was an introvert and practiced social distancing long before it was cool!&lt;/p&gt;

&lt;p&gt;He currently resides in North Carolina and is always interested in new opportunities, meeting quality people and learning about exciting projects. &lt;/p&gt;

&lt;p&gt;Contact Joe Giglio: joe -AT- joegiglio.org | &lt;a href="https://x.com/ChiefRemote" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; | &lt;a href="https://www.linkedin.com/in/joegiglio/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Some images from &lt;a href="//unsplash.com"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ai</category>
      <category>webdev</category>
      <category>python</category>
    </item>
    <item>
      <title>The Importance of "Whole Company Support"</title>
      <dc:creator>Joe Giglio, Chief Remote Officer</dc:creator>
      <pubDate>Wed, 29 Jan 2020 21:42:21 +0000</pubDate>
      <link>https://dev.to/chiefremote/the-importance-of-whole-company-support-18pf</link>
      <guid>https://dev.to/chiefremote/the-importance-of-whole-company-support-18pf</guid>
      <description>&lt;p&gt;&lt;strong&gt;Teams do their best, and most valuable, work when they have a deep understanding of their products, domain and customers.&lt;/strong&gt; If you are not working to better understand and serve your customers, what are you working on?   &lt;/p&gt;

&lt;p&gt;Many companies still consider "&lt;strong&gt;technical support&lt;/strong&gt;" and "&lt;strong&gt;customer service&lt;/strong&gt;" to be a burden, nuisance and cost center. I wholeheartedly disagree and take the opposite view. I believe the support team is one of the most important teams in a company. They understand the products at an intimate level and most importantly, understand your customer's use cases, demands, pain points and requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Whole Company Support&lt;/strong&gt;, also known as &lt;strong&gt;All Hands Support&lt;/strong&gt;, has been gaining traction with companies that want to build a more well-rounded organization with deep levels of customer empathy. &lt;/p&gt;

&lt;p&gt;Technical support, customer service, customer success - whatever you want to call it - these roles are vital to the health of your company. These are roles that require skill, tact, communication, constant learning and patience. Although not typically considered as "valuable" as "technical skills", these "soft skills" can often be the difference between a satisfied or disgruntled customer. Remember, the support team is often responsible for mending relationships and playing a liaison role between customers and the rest of the company.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customer Support is a craft and not everyone is good at it. If there are team members in the organization that do not have the confidence, patience or communication skills to directly handle support requests, all is not lost!&lt;/strong&gt; The goal of Whole Company Support is not necessarily to create more support agents, although that may be a positive side effect. &lt;strong&gt;Rather, the goal is to increase collaboration and build a company where everyone develops a deeper understanding of their products and empathy for their customers.&lt;/strong&gt; Everyone can help the company meet these goals by partnering with a member of the Support team, reviewing support cases for common themes and committing to use their skills to help solve problems and improve the customer experience.  &lt;/p&gt;

&lt;p&gt;My first software job was as a Technical Support engineer. It was with a new startup company that did not have many customers so I was asked to also perform QA duties during support downtime. This turned out to be ideal since the roles complement each other... As QA, you learn every inch of the products. As Tech Support, you learn how real customers are using the product. The combined knowledge is helpful in helping drive product direction and influencing the Engineering team to focus on the right things. &lt;/p&gt;

&lt;p&gt;On a personal note, this combined role kept me intimately involved with the Sales and Engineering teams and I won &lt;strong&gt;Employee of the Year&lt;/strong&gt; awards twice. Not just because of the great job I did but also because everyone at the company knew who I was since I found solutions for prospective and existing customers. I straddled the line between customer advocate and technical “Product Management”.   &lt;/p&gt;

&lt;p&gt;A friend of mine works customer support for a major retailer and most of his calls fall into one of a few common themes. The number of phone calls and level of customer frustration could be drastically reduced if the company practiced Whole Company Support and was closer to the customer experience. Some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mailed gift cards&lt;/strong&gt; - There is a bug with the gift card system that falsely reports the gift cards as delivered when they have been received by the post office. In addition, the tracking number in the email and the support system is often incorrect. This creates anxiety for customers who often believe the gift card is lost in the mail. The support agents are helpless in tracking the gift card and all the customers can do is “wait a few days” and hope the gift card shows up.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Third party vendor items&lt;/strong&gt; - This company employs “drop shipping” for many items which is invisible to their customers. Once the customer pays for the item, the system simply has a status of “Processing”. Tracking information is not available and it is not possible to get further information or cancel an item without an agent sending a request that is handled by another team. This can take several days and creates anxiety for customers. If an item is taking too long to be delivered, customers often want to immediately cancel the order and it is not possible due to the lack of integration between the in-house and partner systems.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lack of emailed updates&lt;/strong&gt; - If an agent cancels or discounts an ordered item, the customer is not sent a confirmation email. This leaves doubt in the customer’s mind as to whether their request has been fulfilled.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lack of “after call work” following phone calls&lt;/strong&gt; - On busier days, the incoming call volume can be very heavy. In order to reduce hold times, the telephone system does not support “after call work” which means that calls are often wrapped up without agents entering any notes. If the customer calls in again, there is no record in the system of what was done for them and who handled the call.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Old orders disappear from the system&lt;/strong&gt; - In order to relieve strain on the database, orders over a certain age are archived off the main system and are unavailable for agent querying. They are available on another system which can only be viewed by certain supervisors. Wait times for supervisor escalation can often exceed ½ hour so customers are frustrated having to wait so long.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Restrictive coupon codes&lt;/strong&gt; - Customers are often emailed coupons that give them “25% OFF EVERYTHING AND FREE SHIPPING (&lt;em&gt;)”. The asterisk (&lt;/em&gt;) is a long screen of fine print that customers don’t read. The fine print encompasses the brand and merchandise restrictions, so “EVERYTHING” is never really on sale.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Shopping cart view/edit&lt;/strong&gt; - Customers often call in about items that are still in their shopping cart. Because many items have the same description, agents often need a model number to assist the customers. If agents had the ability to view/edit the customer’s shopping cart, they would be able to provide a faster and personalized level of support. I have seen this strategy employed at Crutchfield and was always impressed with the technology. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No price protection&lt;/strong&gt; - Prices may change from day to day and the company does not have any type of price protection policy. If the price drops on an item that you ordered yesterday for a higher price, too bad. Perhaps if the company employed an “automatic [X] day price protection” policy, customers would believe they are getting the best possible deal and would happily continue shopping there in the future.     &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After reading this list of grievances, hopefully the wheels are spinning in your head as to how you may address each one. These are all items that can be addressed by various teams in the company - IT, website, marketing, partnerships, etc. Some of these items can be fixed with code updates, others with revisions to outdated policies that may have once made sense but should be reviewed due to the impact on customer satisfaction.  &lt;/p&gt;

&lt;p&gt;Regardless of one's role, there are always benefits to working with the support team and being closer to the needs of your customers. Spending time with the support team should be part of onboarding training. I also recommend rotating support assignments for each team member. The schedule should be published far in advance so teams can adjust for a member's absence and lessen the impact on scheduled deliverables.&lt;/p&gt;

&lt;p&gt;Give your support team the respect, tools, trust and empathy they need to keep your customers happy. It can be the difference between customer attrition and lifelong customers who happily recommend your company to their friends and social media followers.  &lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Joe Giglio is a 25 year veteran of the software industry. In his career, he has worked for a local dial-up ISP, startups of all sizes and a well established, slow moving enterprise. There were important lessons learned along every stop.&lt;/p&gt;

&lt;p&gt;His guiding principles are: Remote first, quality driven, customer champion and lifelong learning.  &lt;/p&gt;

&lt;p&gt;He currently resides in North Carolina and is always interested in new opportunities, meeting quality people and learning about exciting projects.  &lt;/p&gt;

</description>
      <category>support</category>
      <category>technicalsupport</category>
      <category>service</category>
      <category>management</category>
    </item>
  </channel>
</rss>
