This guide is a schaffolding walkthrough. It uses the existing React + Vite + Express scaffold and the papers table from schema.sql.
The goal is not just to end with a working app. The deeper goal is to model a disciplined way to use AI to extend a codebase step by step without losing control of the design.
It is based on this project: https://github.com/jimskon/Demo-Scadfold-project
1. What we already have
The scaffold currently contains:
- a React frontend in
client/ - an Express backend in
server/ - a
paperstable inschema.sql .envalready populated with database credentials- a simple API with:
GET /api/helloGET /api/status
The papers table looks like this:
idtitleauthorsyearurlstatus(to_read,reading,read)tagssummarynotesdate_addeddate_read
This is enough to build a complete CRUD example.
2. The goal
- inspect the starting system
- make design decisions before coding
- ask AI for one bounded change at a time
- test after each change
- refine behavior and validation deliberately
- keep the code understandable
This is much better than saying: “Build me a full CRUD app.”
3. Scope
Core work
- connect Express to MySQL
- add backend CRUD routes for
papers - add Bootstrap to the React app
- replace the starter page with a papers UI
- support:
- list all papers
- add a paper
- edit a paper
- delete a paper
Important design topics
- required vs optional fields
- frontend vs backend validation
- how to report errors to the user
- how to keep data contracts simple and predictable
Login
Lets keep it intentionally simple.
Very light:
- no password hashing
- no database-backed auth yet
- one demo login screen
- hardcoded users or credentials in
.env - role is either
adminorstudent - student can view only
- admin can create, edit, delete
That gives us role-based UI without letting login swallow the process.
4. Architectural decisions to make before asking AI for code
Decision 1: Validation rules
Suggested rules for this demo:
title: required, non-emptyyear: optional, but if present must be an integer in a reasonable rangeurl: optional, but if present should look like a URLstatus: required, must be one ofto_read,reading,read- everything else: optional
- if
status = read, thendate_readmay be set; otherwise it can be null
Decision 2: Where validation happens
Use both layers, but for different reasons:
- frontend validation for quick user feedback
- backend validation as the source of truth
The frontend helps the user. The backend protects the system.
Decision 3: Error response format
Lets pick one format and keep it consistent.
{
"ok": false,
"error": "Validation failed",
"details": {
"title": "Title is required",
"year": "Year must be between 1900 and 2100"
}
}
Success format:
{
"ok": true,
"data": { ... }
}
Decision 4: Single source of truth
Lets eep the database and backend contract authoritative.
We should not not scatter business logic across many React components.
Decision 5: UI structure
Suggested UI:
- top title bar
- table of papers
- button to add a paper
- modal or inline form for add/edit
- alerts for success and error messages
5. Steps to creation
Step 0. Inspect the scaffold before changing anything
Goal
Understand the existing structure and confirm what is already working.
Lets reveiw
- show
server/index.js - show
client/src/App.jsx - show
schema.sql - run the app
- demonstrate
/api/status
Important point
Never ask AI to modify a codebase you have not first inspected.
Suggested AI prompt
I have a small full-stack scaffold with a React client and an Express server. Here are the current files. Explain the current architecture, identify what is already working, and tell me the minimum set of changes needed to turn this into a CRUD app for the papers table.
Step 1. Connect the Express server to MySQL
Goal
Move from a static scaffold to a database-backed server.
What to add
server/db.js- a MySQL connection pool using
mysql2/promise - environment variables for DB host, port, user, password, and database name
Suggested AI prompt
Add database connectivity to this Express server using mysql2/promise and a connection pool. Create a clean db.js file and update the server only as needed. Assume the .env file already contains DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, and DB_NAME. Show the exact code for db.js and any needed edits.
What to test
- restart server
- add a temporary route like
/api/db-test - run a simple
SELECT NOW()
Step 2. Add a backend route to list all papers
Goal
Build the first real feature in the smallest possible slice.
Route
GET /api/papers
Suggested behavior
- return papers ordered by
date_added DESC - wrap response in
{ ok: true, data: rows }
Suggested AI prompt
Using this Express + mysql2 scaffold, add a GET /api/papers route that fetches all rows from the papers table ordered by date_added descending. Use the existing connection pool. Return JSON in the form { ok: true, data: rows } and return a 500 error in the form { ok: false, error: '...' } if something fails. Show the full updated server/index.js.
What to test
- call route in browser or with curl
- confirm records come back
- test failure case if DB name is wrong
Important
Start with read-only features. CRUD should begin with the easiest successful path.
Step 3. Add Bootstrap to the frontend
Goal
Improve the UI quickly without writing custom CSS.
What to add
- install
bootstrap - import Bootstrap CSS in
main.jsx
Suggested AI prompt
Show me the exact steps to add Bootstrap to a Vite React frontend. Then update my main entry file so Bootstrap CSS is loaded correctly. Keep the existing app structure intact.
What to test
- verify styling changes
- use a simple Bootstrap container, table, and button
Step 4. Replace the starter React page with a papers list page
Goal
Have React call GET /api/papers and render the data.
Suggested UI first pass
- page title
- “Add Paper” button
- Bootstrap table with columns:
- title
- authors
- year
- status
- actions
- loading indicator
- error alert
Suggested AI prompt
Replace this starter React App with a Bootstrap-based papers list page. Fetch data from /api/papers, show a loading message, show an error alert if the request fails, and render the papers in a Bootstrap table with columns for title, authors, year, status, and actions. Keep it in a single App.jsx for now unless there is a strong reason to split components.
What to test
- empty table state
- table with data
- backend down
Important
AI should be asked for a bounded UI milestone, not the final polished system all at once.
Step 5. Add the Create form
Goal
Support adding a new paper.
Route
POST /api/papers
Backend validation to implement
- title required
- status must be valid
- year must be integer if present
Frontend behavior
- Bootstrap form or modal
- submit button
- show field-level or form-level errors
- refresh list after success
Suggested AI prompt for backend
Add a POST /api/papers route to my Express server. Validate title, status, and year. Return 400 with { ok: false, error: 'Validation failed', details: { ... } } for invalid input. Insert the row into the papers table and return the created record or insert id in { ok: true, data: ... }.
Suggested AI prompt for frontend
Extend my Bootstrap React papers page to include a form for creating a paper. The form should include title, authors, year, url, status, tags, summary, notes, and date_read. Add basic client-side validation for title and year, submit to POST /api/papers, show validation errors clearly, and refresh the table after a successful create.
Lets consider
- Should tags be a comma-separated string or something more structured?
- Should summary and notes both be multiline fields?
- Should date_read appear only when status is
read?
Consider
Validation is not a detail to add later. It is part of the design.
Step 6. Add Edit
Goal
Support updating existing papers.
Route
PUT /api/papers/:id
Suggested UI
- “Edit” button in each row
- open form prefilled with row values
- reuse the same form component for add and edit if possible
Suggested AI prompt
Refactor my React papers CRUD UI so the add form can also be used for editing. Add an Edit button for each paper, prefill the form with the selected row, submit updates to PUT /api/papers/:id, and keep the UI simple and readable for students.
Step 7. Add Delete
Goal
Complete CRUD.
Route
DELETE /api/papers/:id
Suggested UI behavior
- delete button in each row
- confirmation prompt before deleting
- refresh list afterward
Suggested AI prompt
Add delete support to this papers CRUD app. On the backend, add DELETE /api/papers/:id. On the frontend, add a Delete button in each row with a confirmation step. After deletion, refresh the list and show a Bootstrap success or error alert.
Delete is easy to code and easy to misuse. Good software makes destructive actions explicit.
Step 8. Improve validation and error reporting
Goal
Make the app feel trustworthy.
- What should happen if the server is down?
- What should happen if the database rejects a value?
- Should the frontend show one general message or per-field messages?
- What counts as a user error versus a system error?
Good practice for this project
- field-level validation on forms
- general alert for server/network errors
- backend always returns structured JSON errors
- React should not assume every error response has the same shape unless you designed it that way
Suggested AI prompt
Review this Express + React CRUD app and improve the validation and error-reporting flow. I want a clear distinction between field validation errors, server errors, and network errors. Keep the code beginner-friendly and use a consistent JSON response structure from the backend.
A working CRUD demo is not enough. A good CRUD demo handles mistakes cleanly.
Step 9. Add a very small login with roles (optional 10-minute extension)
If you include login, keep it deliberately tiny.
Recommended tiny version
- React login form with username and password
- backend route
POST /api/login - credentials checked against values in
.envor a tiny in-memory array - response includes role:
adminorstudent - store current user in React state only
- hide create/edit/delete for
student
This is not production authentication. That is fine. It is a demo for role-based UI and route design.
Suggested AI prompt
Add a very small demo login system to this scaffold. Keep it intentionally simple for classroom use: no database users, no hashing, no sessions yet. Use a POST /api/login route that checks credentials against a small hardcoded list or environment variables and returns { ok: true, data: { username, role } }. In the React frontend, show a login form first, store the logged-in user in state, and allow only admin users to create, edit, or delete papers. Students should have read-only access.
6. How to keep AI use disciplined
This part matters as much as the code.
Rule 1
Do not ask for everything at once.
Bad:
Build me a full papers app with login and bootstrap.
Better:
Add only GET /api/papers using the existing scaffold and show the exact code changes.
Rule 2
Paste in the real current code.
Do not let AI guess your existing files.
Rule 3
State constraints clearly.
Example:
- keep Express in one file for now
- do not add TypeScript
- use Bootstrap only
- keep the JSON response format consistent
- do not add authentication libraries yet
Rule 4
Test after every AI-generated change.
Rule 5
Refactor only after the feature works.
First make it work. Then make it cleaner.
7. Project Shape
Backend
Possible files:
server/index.jsserver/db.js- optionally later:
server/routes/papers.jsserver/utils/validatePaper.js
Frontend
Possible files:
client/src/App.jsx- optionally later:
client/src/components/PaperForm.jsxclient/src/components/PapersTable.jsxclient/src/components/LoginForm.jsx
For the first classroom pass, keeping things in fewer files is often better.
8. Concrete validation policy for the papers table
A reasonable classroom policy would be:
title- required
- trim whitespace
- minimum 1 character after trim
authors- optional string
year- optional
- integer between 1900 and 2100
url- optional
- must begin with
http://orhttps://if provided
status- required
- one of
to_read,reading,read
tags- optional comma-separated string
summary- optional multiline string
notes- optional multiline string
date_read- optional
- if status is not
read, allow null - if status is
read, may be provided
You can keep this simple without pretending it is perfect.
9. Concrete error policy for the program
Use these three categories:
Validation error
User entered bad data.
Example:
- missing title
- bad year
- invalid status
Return 400.
Not found error
User tried to edit or delete a record that does not exist.
Return 404.
Server error
Something broke in the backend or database.
Return 500.
This makes the system behavior easier to reason about.
11. Best prompts for the whole workflow
Here is a compact sequence you can reuse.
Prompt A — inspect first
I am going to extend an existing React + Vite + Express scaffold. Here are the current files: [paste files]. Explain the current architecture and propose the smallest sequence of changes needed to build a CRUD app for the papers table in schema.sql.
Prompt B — add DB connection
Using this existing Express scaffold, add a mysql2/promise connection pool in db.js and show the minimal edits needed to use environment variables DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, and DB_NAME.
Prompt C — add first read route
Add only GET /api/papers to this server. Use the connection pool, order by date_added desc, and return { ok: true, data: rows } or a structured error object.
Prompt D — add Bootstrap UI
Replace the starter React page with a Bootstrap-based page that fetches /api/papers and shows them in a clean table with loading and error states.
Prompt E — add create
Add POST /api/papers with backend validation for title, year, and status. Then add a Bootstrap form in React that submits to it and displays validation errors clearly.
Prompt F — add edit
Refactor the papers form so it supports both create and edit. Add PUT /api/papers/:id and keep the code beginner-friendly.
Prompt G — add delete
Add DELETE /api/papers/:id and a Delete button with confirmation in the React table. Refresh the list after deletion.
Prompt H — improve validation and error flow
Review this CRUD app and improve validation, error handling, and user feedback while keeping the code simple enough for an introductory software development course.
Prompt I — tiny role-based login
Add a tiny classroom demo login with admin and student roles. Keep it intentionally simple and do not use sessions or a database users table yet. Students should be read-only; admins can perform CRUD.
