I recently set out to build a simple yet functional Admin Panel for my Hugo blog—one that would allow me to create and edit posts directly from a web interface. Instead of building it from scratch, I decided to leverage AI to accelerate the process.
🚀 The Power of AI in Rapid Prototyping
To be clear, I wasn’t expecting AI to write perfect code or architect the ideal solution. Instead, I treated this as an experiment:
- Could AI help me move faster?
- Would it help me navigate edge cases more effectively?
- Would I need to spend more time fixing AI’s mistakes than it actually saved me?
The experience was illuminating. I was able to build a fully functional markdown editor with an integrated API backend in just an hour—a task that would have taken significantly longer had I started from scratch. The AI provided speed, enabling rapid iteration, but it also introduced obvious mistakes and lacked the architectural foresight that an experienced engineer would bring to the table.
🏗️ AI’s Strength: Speed and Rapid Execution
One of the most impressive aspects of using AI for this project was the sheer speed at which it generated working code. Within minutes, I had:
- A Go backend serving API endpoints for reading and writing Markdown posts
- A front-end admin panel with a markdown editor and live preview
- A working mechanism for storing posts inside Hugo’s
content/
directory
It was functional, but not well-structured. The AI jumped into solutions without first discussing architecture, folder structure, or API design considerations. It was eager to produce results—like a junior developer who wants to ship code as fast as possible. This wasn’t necessarily a bad thing, but it meant that I had to guide the process more than I expected.
For example, AI quickly provided this function to fetch a post’s content:
func getPostContent(w http.ResponseWriter, r *http.Request) {
slug := r.URL.Query().Get("slug")
if slug == "" {
http.Error(w, `{"error": "Slug is required"}`, http.StatusBadRequest)
return
}
filename := filepath.Join(contentDir, slug+".md")
content, err := ioutil.ReadFile(filename)
if err != nil {
http.Error(w, `{"error": "Failed to read file"}`, http.StatusInternalServerError)
return
}
post := Post{
Title: slug,
Slug: slug,
Content: string(content),
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(post)
}
It worked—but it didn’t validate the slug, didn’t check for .md
consistency, and didn’t extract metadata like title from the front matter. AI optimized for speed, not robustness.
🛑 The Obvious Mistakes AI Made
While the AI moved fast, it also made mistakes that a junior developer would have caught.
🔹 1. Duplicate CORS Headers
The AI initially added CORS headers in multiple places, instead of centralizing them:
func getPostContent(w http.ResponseWriter, r *http.Request) {
enableCors(w) // Redundant
...
}
func savePost(w http.ResponseWriter, r *http.Request) {
enableCors(w) // Redundant
...
}
I had to refactor this into a single place inside apiHandler()
, where it applies to all requests:
func apiHandler(w http.ResponseWriter, r *http.Request) {
enableCors(w) // ✅ Centralized CORS handling
switch r.URL.Path {
case "/admin/api/posts":
listPosts(w, r)
case "/admin/api/get":
getPostContent(w, r)
case "/admin/api/save":
savePost(w, r)
case "/admin/api/delete":
deletePost(w, r)
default:
http.NotFound(w, r)
}
}
🔹 2. .md.md Extension Issue
AI suggested multiple fixes for handling file extensions instead of investigating why .md.md
was being added in the first place.
It suggested this frontend fix, ensuring .md
was stripped before sending API requests:
async function editPost(slug) {
slug = slug.replace(/\.md$/, ""); // ✅ Remove .md before sending
const res = await fetch(`${API_URL}/admin/api/get?slug=${slug}`);
}
But it also suggested backend fixes, where .md
was appended only if missing:
if !strings.HasSuffix(slug, ".md") {
slug += ".md"; // ✅ Append only if missing
}
Both fixes worked, but the real issue was that this issue could have been eliminated at the data model level rather than patching it in two places.
🏛️ What AI Lacked: Architecture, Scalability, and a Systematic Approach
Beyond the tactical errors, the AI’s biggest weakness was its lack of architectural foresight. It took a scripty approach, rather than considering:
- How should posts be structured? Should there be a JSON schema for post metadata?
- How should the API evolve? What happens if we later need categories, tags, or draft statuses?
- How do we eliminate an entire class of errors? Instead of fixing one-off issues, how do we architect the system to prevent them from happening?
Had I been working with a seasoned human developer, they would have asked these questions before writing any code. AI, on the other hand, needs to be explicitly directed to consider architecture before implementation.
🎯 The Final Outcome: A Functional Admin Panel, Built Fast
Despite these shortcomings, the project was a success. Within an hour, I had a working, iteratively improved admin panel—something that would have taken me much longer to build alone. The speed of iteration was invaluable.
- I didn’t have to search for syntax or API documentation.
- I could delegate repetitive problem-solving to AI while focusing on higher-level decisions.
- I ended up with a fully functional prototype that I could refine further.
🤖 AI as a Coding Assistant: What Needs to Improve
Reflecting on this experience, I see huge potential for AI-assisted software development, but also significant areas for improvement:
- Context Retention: AI loses track of previous conversations quickly. If it were integrated into my IDE (VSCode), it could persist context better—but on my Chromebook, I couldn’t use such integrations natively.
- Follow-Up Questions: AI should ask clarifying questions before implementation. A simple “What folder structure do you prefer?” would have saved multiple iterations.
- Proactive Architecture Thinking: Instead of immediately generating code, AI should suggest structured approaches before writing anything.
- Root Cause Analysis: AI should detect patterns in mistakes instead of just fixing individual errors. Had it taken a step back, it could have eliminated the
.md
issue at its root.
🔮 Looking Ahead: AI as a Partner in Development
Would I use AI again for a project like this? Absolutely. But I would treat it more like a junior developer—guiding it, challenging its assumptions, and demanding architectural thinking before implementation.
🚀 What do you think? Have you built anything using AI that moved fast but lacked structure? Let’s discuss in the comments!