Push it to the Limit EP. 2—GPT Engineer
Integrating a large database with 40+ tables in GPT Engineer & Claude Sonnet 3.5
I did it. Using GPT Engineer + Claude Sonnet 3.5 I am on my way to build a freelance market website connected to my Supabase database with around 40+ tables, triggers, functions which all handle backend logic.
Essentially the workflow I came up with was:
Generated a large 40+ table database on Supabase with Claude
Generated relevant triggers and functions for backend logic
Generated Row Level Security script with Claude
Ran the generated SQL scripts on Supabase which auto-generates REST API
Uploaded auto-generated API docs on Claude Projects to generate boilerplate
Prompted Claude to generate React components with Supabase client code
Upload each React components into GPT Engineer to “stitch” em up
Prompt GPT Engineer to make incremental UI adjustments
I came up with this workflow after I experienced that GPT Engineer could not just digest the Supabase docs to generate consistent forms. Note GPT Engineer is a competitor to v0.dev (I hope to cover this in the future) focusing on frontend.
While GPT Engineer’s Supabase integration works out of the box for smaller number of tables, for a large database like mine, where I had to manually copy paste the table structure and REST API endpoints, it react inconsistently to my prompts.
Main challenge with GPT Engineer was having it call my API properly and render them consistently. I ended up getting stuck for days because I could barely implement a module. For example, I wanted to load projects from my REST API on Supabase but it would get stuck in infinite API calls or would not render it properly.
It didn’t matter how clever my prompts were it simply felt like moving through molasses. In my desperation, an idea came to me to use Claude Project with a larger context window size and intelligence to bypass what GPT Engineer struggled with.
So for now based on my experiment, the alpha is to generate the boilerplate code that already talks to Supabase as a starting point for GPT Engineer to update UI and behavior incrementally with prompts
I know the title is GPT Engineer but I could not have pulled this off without Claude 3.5 Sonnet and how heavy its used here. It truly is a marvel. I just fed it my automatically generated API docs from Supabase after generating all the 32 system modules. This is a big topic which we will discuss database generation prompt techniques in another post.
From those giant database/api documents I uploaded to Claude Projects ( Table dump, API endpoints) it generated each piece of React component code for all 32 modules.
Lets start with the top level App.js code and paste it into GPT Engineer:
// src/App.js
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { createClient } from '@supabase/supabase-js';
// Import components for each module
import UserManagement from './components/UserManagement';
import ProjectManagement from './components/ProjectManagement';
import BiddingSystem from './components/BiddingSystem';
import MilestonePayment from './components/MilestonePayment';
import TimeTracking from './components/TimeTracking';
import ReviewFeedback from './components/ReviewFeedback';
import Communication from './components/Communication';
import DisputeResolution from './components/DisputeResolution';
import SkillManagement from './components/SkillManagement';
import FinancialManagement from './components/FinancialManagement';
import TeamManagement from './components/TeamManagement';
import ContentManagement from './components/ContentManagement';
import AnalyticsReporting from './components/AnalyticsReporting';
import ModerationSecurity from './components/ModerationSecurity';
import APIRateLimiting from './components/APIRateLimiting';
import NotificationSystem from './components/NotificationSystem';
import UserPreferences from './components/UserPreferences';
import SystemConfiguration from './components/SystemConfiguration';
import ErrorLogging from './components/ErrorLogging';
import AuditTrail from './components/AuditTrail';
import Portfolio from './components/Portfolio';
import UserVerification from './components/UserVerification';
import ReferralSystem from './components/ReferralSystem';
import SubscriptionSystem from './components/SubscriptionSystem';
import AuthSessions from './components/AuthSessions';
import CurrencyRates from './components/CurrencyRates';
import RefreshLog from './components/RefreshLog';
import ProjectTags from './components/ProjectTags';
import StripeAccounts from './components/StripeAccounts';
import UserTestResults from './components/UserTestResults';
import UserReports from './components/UserReports';
const supabaseUrl = 'https://myapi.com';
const supabaseKey = 'mykey';
const supabase = createClient(supabaseUrl, supabaseKey);
function App() {
return (
<Router>
<div className="App">
<Switch>
<Route path="/user-management" component={UserManagement} />
<Route path="/project-management" component={ProjectManagement} />
<Route path="/bidding" component={BiddingSystem} />
<Route path="/milestone-payment" component={MilestonePayment} />
<Route path="/time-tracking" component={TimeTracking} />
<Route path="/review-feedback" component={ReviewFeedback} />
<Route path="/communication" component={Communication} />
<Route path="/dispute-resolution" component={DisputeResolution} />
<Route path="/skill-management" component={SkillManagement} />
<Route path="/financial-management" component={FinancialManagement} />
<Route path="/team-management" component={TeamManagement} />
<Route path="/content-management" component={ContentManagement} />
<Route path="/analytics-reporting" component={AnalyticsReporting} />
<Route path="/moderation-security" component={ModerationSecurity} />
<Route path="/api-rate-limiting" component={APIRateLimiting} />
<Route path="/notifications" component={NotificationSystem} />
<Route path="/user-preferences" component={UserPreferences} />
<Route path="/system-configuration" component={SystemConfiguration} />
<Route path="/error-logging" component={ErrorLogging} />
<Route path="/audit-trail" component={AuditTrail} />
<Route path="/portfolio" component={Portfolio} />
<Route path="/user-verification" component={UserVerification} />
<Route path="/referral" component={ReferralSystem} />
<Route path="/subscription" component={SubscriptionSystem} />
<Route path="/auth-sessions" component={AuthSessions} />
<Route path="/currency-rates" component={CurrencyRates} />
<Route path="/refresh-log" component={RefreshLog} />
<Route path="/project-tags" component={ProjectTags} />
<Route path="/stripe-accounts" component={StripeAccounts} />
<Route path="/user-test-results" component={UserTestResults} />
<Route path="/user-reports" component={UserReports} />
</Switch>
</div>
</Router>
);
}
export default App;
Very cool! It produced a nice main page linking to all the module components (which are currently empty). The Profile button doesn’t make sense there as it points to User profile after they login. I’ll prompt GPT Engineer to move it out of there later.
Now we just need to repeat this for all 32 modules. But we also need to implement Supabase Auth for user signups and signins out of the gate. We need to then use Supabase Auth UUID to associate any projects, milestones, preferences created to the authenticated user.
Telling GPT Engineer to add authentication….
Noting the whitespace there that needs to be removed later.
Now we continue looping through all 32 modules (React forms) by repeating the steps. Starting with the Project Management module. I paste the Claude generated React code into GPT Engineer.
// src/components/ProjectManagement.js
import React, { useState, useEffect } from 'react';
import { supabase } from '../supabaseClient';
const ProjectManagement = () => {
const [projects, setProjects] = useState([]);
const [newProject, setNewProject] = useState({ title: '', description: '', creator_id: '', budget: 0 });
useEffect(() => {
fetchProjects();
}, []);
const fetchProjects = async () => {
let { data: projects, error } = await supabase
.from('projects')
.select('id, title, description, status')
.range(0, 9);
if (error) console.error('Error fetching projects:', error);
else setProjects(projects);
};
const createProject = async (e) => {
e.preventDefault();
const { data, error } = await supabase
.from('projects')
.insert([newProject]);
if (error) console.error('Error creating project:', error);
else {
fetchProjects();
setNewProject({ title: '', description: '', creator_id: '', budget: 0 });
}
};
return (
<div>
<h1>Project Management</h1>
<form onSubmit={createProject}>
<input
type="text"
placeholder="Title"
value={newProject.title}
onChange={(e) => setNewProject({ ...newProject, title: e.target.value })}
required
/>
<textarea
placeholder="Description"
value={newProject.description}
onChange={(e) => setNewProject({ ...newProject, description: e.target.value })}
required
/>
<input
type="text"
placeholder="Creator ID"
value={newProject.creator_id}
onChange={(e) => setNewProject({ ...newProject, creator_id: e.target.value })}
required
/>
<input
type="number"
placeholder="Budget"
value={newProject.budget}
onChange={(e) => setNewProject({ ...newProject, budget: parseFloat(e.target.value) })}
required
/>
<button type="submit">Create Project</button>
</form>
<ul>
{projects.map((project) => (
<li key={project.id}>{project.title} - {project.status}</li>
))}
</ul>
</div>
);
};
export default ProjectManagement;
Noting that this code above already integrates Supabase and Claude also did a good job of adding a way to view the projects a user creates! Very smart!
Pasting ProjectManagement.js into GPT Engineer generates a styled form like this.
The big question is does this form work out of the box? Can it save a project?
Holy **** it works out of the box with toast notification added by GPT Engineer! Note I’m logged in and noticing error handling messages too. I’m getting super excited but we will celebrate once we’ve generated ALL 32 modules.
I prompt GPT Engineer some UI changes like fixing the whitespace in signup modal.
GPT Engineer correctly removes the whitespace issue in modal.
and remember that Profile button on main page we dont need?
Important to be explicit about what outcome you dont want as I noted in brackets.
Success! It removed the profile button from main and kept the Profile link at the top right. Also it fixed the weird alignment issue in the modal
So far I am having way more progress with GPT Engineer by giving it the React form that talks to Supabase as a starting point. Next, we want some universal variable currentUserUUID
for when we submit a form to a table requiring author’s user id.
For example the Your Profile component that reads and writes to the Users table.
I copy paste the auto-generated Supabase API docs.
Wouldn’t it be wild if it updates the Your Profile page I generated earlier with the Users table?
Absolutely amazing! It pulled values like User ID from the users table. I am providing the baseline React form that already integrates my REST API on Supabase into GPT Engineer to “stich it all up”.
As noted in the beginning, I struggled to generate these backend talking forms from scratch on GPT Engineer using the same table documents I fed to Claude. I think one possible theory is that I do not see what components are being created behind the scenes and so im unable to form a mental model which will allow for more precise prompts about which components I need to change.
Claude gave me the React code, Supabase integration, triggers & functions, RLS before I even got to GPT Engineer. This means I am building a good mental model of the basic React components and database table relations before I get to prompting in GPT Engineer. This is both a limitation and a feature of GPT Engineer. For those that can’t read code this is not an issue. Those that do need to read the code, the current UI makes it difficult. I suggest some file explorer.
One type of problem happens once in a while especially after your chats get long. For example, in that Your Profile page screenshot, I asked GPT Engineer to pull the Reputation score and first name from Users table but the preview did not reflect it but it confirmed the edit. Refreshing the browser made no difference. It was after some time had passed I noticed the issue was fixed so this could be another sandbox cache issue or something. I am not sure why this keeps happening. It could be that the Preview is not updating consistently and might have been addressed by the time I am writing this post (2 weeks have gone by)
By using Claude Sonnet 3.5 as a sort of boiler plate generator I’ve been having a lot easier time integrating them into GPT Engineer due to a “solid foundation”
Above, I am pulling all the projects from Projects table. Create Bid button also works by writing to Bids table! Claude has done a great job here considering all this code was generated from prompt ONCE.
I’m not confident that I wouldn’t have struggled to get it working consistently with GPT Engineer and probably would take many prompts and revisions to add this backend functionality manually but seemingly works better when using Supabase Integration mode (limited to smaller tables as mine failed).
I tirelessly work to implement each component by repeating the mantra: copy paste Claude generated code into GPT Engineer, making UI adjustments there.
Above, I’ve asked GPT Engineer to turn the Project text field into a drop down by pulling the projects I created.
What’s wild is that Claude generated react code (which already integrates Supabase) also takes account into one to many and many to many relationships. The toast notifcation is a nice automatic touch by GPT Engineer.
So after another hour and half of copy pasting Claude’s react code and table columns ive got a basic CRUD functionality for all of the modules. Lets visit some of these modules to see if they work properly:
note it rejects my bid since I already bid on that project! nice edge case consideration.
easily pulls project tags and allows CRUD
haven’t tested this one since projects dont show up. So again this is the challenge, I need to revisit and test every aspect of the generated components. But to think 8 years ago I’d be able to generate this amount of React code over a weekend (starting with Claude) with minimal React knowledge and experience should scare any software devs
so this is another problematic component. What was working initially, GPT Engineer ended up breaking responding to my simple UI update ask. This seems to happen once in a while where a seemingly simple and innocent UI change will drastically change the whole layout. What would be wise is some way to target prompts to a specific UI region (like how v0.dev does it) with a highlight tool. Having to constantly remind GPT Engineer to never change existing function and layout is tiring.
I was most impressed with this component because multiple table relations involved.
buttons working properly and pulling the right data
As I wrap up this post I realize just how much I had to leave out with what I did on Claude as I wanted to focus on GPT Engineer with this post. The database table, trigger and function generation needs to be studied further distill an optimal prompt in another post. Lot of lessons learned there that I need to share in another post.
I also need to cover RLS generation for user authorization and role based access control on a path to complete our ProfilePond freelancer website. Without this our API would be wide open. RLS prompting was the toughest part of this whole workflow and it deserves a separate post.
My ultimate goal is to figure out a workflow to generate a full stack web app with as minimal involvement as possible without sacrificing complexity, edge case coverage, security.
So far, I am learning to prompt (each will be a post):
generate complex databases and tables
generate complex backend logic using triggers and functions on Postgres
generate security and role based authorization with Row Level Security
generate a consistent and smart React code that talks to any backend
maintain this full stack React app without coding going forward (https://github.com/PromptCoding/ProfilePond)
In Episode 3, I will be completing the ProfilePond freelancer website and documenting the remaining steps.
Please Like, Subscribe & Leave a Comment!