Published: Mar 11, 2025 by Isaac Johnson
Claude Code has gotten a lot of buzz since Anthropic quietly announced it via a blog post Feb 24th along with Claude Sonnet 3.7 (skipping 3.6 altogether).
I wanted to play with both and I will call out the “Research Preview” of Claude Code does require ‘approval’, so you’ll want to request access via the Anthropic Console (for reference, took me a bit over a day).
I’ll cover all that and more as we build out a full Python app and release it using both Claude Code, Claude Sonnet 3.5 and 3.7 via VS Code, and other AI tools.
The goal is to end-to-end build an app from scratch (and I’m going to focus on building a Meeting app that I could use to help manage a weekly morning men’s group of which I take part and we get by with Google calendar)
Claude Code
We need to have at least NodeJS 18.x or higher
builder@LuiGi:~/Workspaces/flaskAppBase$ nvm list
v16.20.2
v18.20.2
-> v21.7.3
system
default -> stable (-> v21.7.3)
iojs -> N/A (default)
unstable -> N/A (default)
node -> stable (-> v21.7.3) (default)
stable -> 21.7 (-> v21.7.3) (default)
lts/* -> lts/iron (-> N/A)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.17.0 (-> N/A)
lts/dubnium -> v10.24.1 (-> N/A)
lts/erbium -> v12.22.12 (-> N/A)
lts/fermium -> v14.21.3 (-> N/A)
lts/gallium -> v16.20.2
lts/hydrogen -> v18.20.4 (-> N/A)
lts/iron -> v20.15.1 (-> N/A)
If we want enhanced search, we need rg
builder@LuiGi:~/Workspaces/flaskAppBase$ which rg
/home/linuxbrew/.linuxbrew/bin/rg
We can install with npm
builder@LuiGi:~/Workspaces/flaskAppBase$ npm install -g @anthropic-ai/claude-code
added 3 packages in 8s
2 packages are looking for funding
run `npm fund` for details
I then just launched claude
in my checked out Forgejo repo
Next, I need to log into my Anthropic account
Launching with WSL pops up these Firefox
I authed, but was told at this time they were at capacity
That night I saw the email that “my spot was confirmed”
Claude via VS Code
I can try using Claude via VS Code using the Sonnet 3.5 preview model. It’s not the new 3.7, but it is quite excellent
I’ll see if it can add a team page
@workspace Can you add a picker for teams after the user logs in? They can pick from existing teams or create a new team. Store team membership in the database and show Team membership when the user logs in (if they are in a team).
It came back with some updates
I can now see a new “manage teams” after I create an account
Clicking that lets me join or add a team
I can create a new team
I’m redirected back to the page that now shows my team membership
I can use another browser to test joining the team
I pushed that commit and asked Claude 3.5 via Copilot to now add an admin user
can you add a default admin user with password password123. This admin user, when logging in, should see a table of all users with their team membership as well as all teams. the user and teams table should be sortable.
And I can see the new generated code
It did create an admin user which showed teams
I realized I have a left a gap in that users cannot change passwords. Having an admin user with a fixed password that cannot be changed would be a rather big miss.
The next updates worked quite well, even if I’m not keen on the UI sizing of the password change
While I didn’t ask for it, the admin dashboard lets me reset other user’s passwords which is a handy feature
Picking back up with Claude Code
Within a day or so I saw I was granted a spot
A bit of cleverness here is that yes, I have access, and 7 days to use it. However, to use it I have to move to the paid tier of Claude.
Let’s see how far US$10 takes me
Looks like I’m in
Now I can login with Claude Code
I get some security notes then tips for usage
I confirm I trust files in the folder
Asking for some UI changes
First, I’ll setup an Init file
It then basically read and reviewed my code to build a logical markdown of style guidelines and usage. Pretty clever
Saving it, as I would expect, I saw CLAUDE.md get created in my workspace
Let’s ask it to improve the Password block
Let’s see how it does
Since I have this in GIT, I can see the changes reflected
I fired a build and tested - looks good
I’m pretty good with this base. I think I’ll make a branch and start to build an App with it and see how far it goes.
Calendar and Assignments
I’m going to push it to make a calendar and assignment section. It’s a pretty big ask, let’s see how it does:
On first look, seems nice
I can pick specific days, but it does not re-occur
The other issue is that when I join a team, it does not share the schedule with team members, so it must be stored on the user, not team
I can then ask Claude via Cursor AI to create an ICS calendar
I can let it setup local python and test it without Docker which is nice
Not only did Claude Code fix the Team scheduling aspect of the calendar, it did a fantastic job create a working ICS
I can see we need to likely to add iCalendar to our requirements as Claude Code did it on the fly
...
> That worked great, thanks. Can you create a per-team ICS format calendar that I could use in google calender.
● I'll create a per-team ICS calendar format for Google Calendar integration. Let me implement this feature.
● Read(file_path: "app.py", limit: 50, offset: 0)…
⎿ from flask import Flask, session, request, jsonify, redirect, url_for, render_template, send_from_directory
from flask_sqlalchemy import SQLAlchemy
import os
... (+47 lines)
● Bash(pip3 install icalendar --break-system-packages)…
⎿ Collecting icalendar
Downloading icalendar-6.1.1-py3-none-any.whl.metadata (10 kB)
Collecting python-dateutil (from icalendar)
Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl.metadata (8.4 kB)
Collecting tzdata (from icalendar)
Downloading tzdata-2025.1-py2.py3-none-any.whl.metadata (1.4 kB)
Collecting six>=1.5 (from python-dateutil->icalendar)
Downloading six-1.17.0-py2.py3-none-any.whl.metadata (1.7 kB)
Downloading icalendar-6.1.1-py3-none-any.whl (200 kB)
Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB)
Downloading tzdata-2025.1-py2.py3-none-any.whl (346 kB)
Downloading six-1.17.0-py2.py3-none-any.whl (11 kB)
Installing collected packages: tzdata, six, python-dateutil, icalendar
Successfully installed icalendar-6.1.1 python-dateutil-2.9.0.post0 six-1.17.0 tzdata-2025.1
● Now I'll implement the calendar export functionality by adding a new route to generate ICS files for teams. Let's add this to our app.py file:
● Update(file_path: app.py)…
⎿ Updated app.py with 4 additions and 1 removal
1 from flask import Flask, session, request, jsonify, redirect, url_for, render_template, send_from_directory
1 from flask import Flask, session, request, jsonify, redirect, url_for, render_template, send_from_directory, Response
2 from flask_sqlalchemy import SQLAlchemy
3 import os
4 import datetime
5 import calendar
...
I can use Copilot to quickly get the requirements.txt file Updated
Out of habit I started to use Copilot to add a mount point to the Dockerfile and a local DB spot as I wanted to use a PVC when the time came for Kubernetes.
But I stopped myself and went back to Claude to add the next part - some kind of password for the Team.
What dawned on me is that if I expose this, anyone could join any team and that would not be desired.
Here we can see how Claude Code handles this ask and a quick test showing we need to deal with our existing database
That worked great
Now I want the ability to leave teams and add notes. As this took a bit more thinking, I paused the recording at times
I can now see edit notes available
And again, the test worked great
Now if I really want to test this, I need to create a build and release file I can use with Kubernetes.
If this works, I’ll set up a CICD pipeline, but to stat with, I just want to push it up to Dockerhub so i can test it
builder@LuiGi:~/Workspaces/flaskAppBase$ docker tag mytest123:1.5 idjohnson/devotionapp:1.5
builder@LuiGi:~/Workspaces/flaskAppBase$ docker push idjohnson/devotionapp:1.5
The push refers to repository [docker.io/idjohnson/devotionapp]
1361a1f741f3: Pushed
f22b09a73a21: Pushed
4bf371b00791: Pushed
522dac915f0a: Pushed
597792c21051: Pushed
cb8559ac3925: Pushed
5da80621c140: Pushed
ee6e0d2a97f1: Pushed
6022e9b5727d: Mounted from idjohnson/k8sresourceviewer
e0dfbff797f9: Mounted from idjohnson/k8sresourceviewer
0eaf13317391: Mounted from idjohnson/k8sresourceviewer
7914c8f600f5: Mounted from idjohnson/k8sresourceviewer
1.5: digest: sha256:34d4bd4f4600e5185de682412db786078bd3d1c26d7f317e5d0018c2208c99e5 size: 2823
I could have fired up Claude Code to create the Dockerfile. But why pay for that? I know Copilot can kick that out in a heartbeat
I can now test
$ kubectl apply -f k8s-deployment.yaml
persistentvolumeclaim/devotion-db-pvc created
service/devotion-app-service created
deployment.apps/devotion-app created
The Deployment was right, but I missed the type on the service so it’s trying to make a LoadBalancer instead of a ClusterIp
builder@LuiGi:~/Workspaces/flaskAppBase$ kubectl get po -l app=devotion-app
NAME READY STATUS RESTARTS AGE
devotion-app-67c9b94f46-w7qns 1/1 Running 0 72s
builder@LuiGi:~/Workspaces/flaskAppBase$ kubectl get svc devotion-app-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
devotion-app-service LoadBalancer 10.43.203.159 <pending> 80:30268/TCP 74s
That was just a quick fix to type
apiVersion: v1
kind: Service
metadata:
name: devotion-app-service
spec:
selector:
app: devotion-app
ports:
- protocol: TCP
port: 80
targetPort: 5000
type: ClusterIP
I might have the idea this would help my Men’s Group meetings, but it really could be used for any kind of recurring meetup.
I’ll create a quick DNS record for “meet” in my Azure DNS
$ az account set --subscription "Pay-As-You-Go" && az network dns record-set a add-record -g idjdnsrg -z tpk.pw -a 75.73.224.240 -n meet
{
"ARecords": [
{
"ipv4Address": "75.73.224.240"
}
],
"TTL": 3600,
"etag": "5c3eca87-ba80-4ac3-b729-2e6dff4e8960",
"fqdn": "meet.tpk.pw.",
"id": "/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idjdnsrg/providers/Microsoft.Network/dnszones/tpk.pw/A/meet",
"name": "meet",
"provisioningState": "Succeeded",
"resourceGroup": "idjdnsrg",
"targetResource": {},
"trafficManagementProfile": {},
"type": "Microsoft.Network/dnszones/A"
}
Then I just need to create an Ingress and launch it
builder@LuiGi:~/Workspaces/flaskAppBase$ cat ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: azuredns-tpkpw
generation: 1
name: meet
spec:
ingressClassName: nginx
rules:
- host: meet.tpk.pw
http:
paths:
- backend:
service:
name: devotion-app-service
port:
number: 80
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- meet.tpk.pw
secretName: meet.tpk.pw-tls
builder@LuiGi:~/Workspaces/flaskAppBase$ kubectl apply -f ./ingress.yaml
ingress.networking.k8s.io/meet created
That didnt work, let me rework it
builder@LuiGi:~/Workspaces/flaskAppBase$ cat ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: azuredns-tpkpw
ingress.kubernetes.io/ssl-redirect: "true"
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
name: meetingress
spec:
rules:
- host: meet.tpk.pw
http:
paths:
- backend:
service:
name: devotion-app-service
port:
number: 80
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- meet.tpk.pw
secretName: meet-tls
builder@LuiGi:~/Workspaces/flaskAppBase$ kubectl apply -f ./ingress.yaml
ingress.networking.k8s.io/meetingress created
I realized the issue is this ClusterIssuer was 361d old and that prompted me to check to see if the SP had an expired credential.
Indeed, I had set this Service Principals secret to expire in a year and that just happened
That time it worked
$ kubectl get cert meet-tls
NAME READY SECRET AGE
meet-tls True meet-tls 92s
Testing
We can test the login and see our iCal link is now showing
One issue (and it took testing on my phone to figure out), is that the ICS file is a static grouping of specific date entries that can import as events in an existing calendar, but doesn’t really work as a “remote” calendar that would sync.
Adaptive UI
Another issue I have from using a very basic flask App UI is a lack of adaptive UI. That is, it doesn’t optimize for mobile when that is available.
The login works, but it’s awfully small
though the main app is okay
Let’s try and fix both
The calendar ics file does not have a proper end tag (END:VCALENDAR). please fix the ics link so i can use it with google calendar. Also, the login page does not have responsive design so it does not format properly for mobile. Can you update the design to work better for mobile devices.
I wanted to set up a basic CICD pipeline. I decided to try building a pipeline in AzDO that can pull from Forgejo and push to my Harbor
and I can verify it pushed to Harbor
The login works fine for the web
But now the phone’s size is proper
I tested the calender and it works great!
I asked to break out notes and make the landing page have responsive design as well.
It is now much more full screen on the computer
and it looks great on mobile as well
API
I had spent some considerable time letting Claude work on creating an API I could use with REST.
It did not work at first, but with some work, I managed to figure it out.
At this point, for all the work I had Claude Code do to build this app, I was curious what kind of costs I might have incurred
It does seem an okay price but I might avoid using Claude for as much in the future as I think some of my work could have been done just as well with Copilot feature
Summary
So I finished to the point I was happy enough to share with my men’s group. I asked my wife to look at my app, and she was nice enough, but then just said “yeah, i mean, moms just use signup genius”. I had no idea what that app was. Perhaps that is a my fault for spending too much doing AI work and only really looking at social networks like LinkedIn and Meetup.
That said, I am pretty happy with this app and the value Claude Code provided. I feel it was effective, but I’m not sure about the pricing. It’s not so amazing I’m willing to go to Claude Code first each time. I might save it for when all the rest fail me.
Even as I was writing the summary I was stewing on using the rest of my credits to build out the Android and iOS accompanying apps if I wanted to go mobile native and even started the work locally.
However, I also realized I missed a favicon, so i used favicon.io to create a quick copy of my logo as a fav icon then asked Copilot (Free) to solve it - it was an “easy” ask (and my lazy butt could have just done it as well - i didn’t need AI for that).
As it stands, this app cost me about US$5.50 to build in Anthropic money (A few cents of that Claude Code bill was likely spent demoing to colleagues). The question is was it worth it?
I might think differently - if some tech buddy helped code as much as Claude did this time, would I buy my buddy Claude a fancy Starbucks drink for about the same amount? Damn straight I would. So yeah - I guess I think it’s priced fair.