This blog records the complete development process of the first web development assignment — a web calculator built from scratch. It includes requirement analysis, architecture design, API development, front‑end and back‑end joint debugging, and troubleshooting. All calculation logic runs on the backend. The frontend is only responsible for UI display and sending requests. SQLite is used for persistent data storage.Table of Contents​​​​​​1. Course Information2. GitHub Repository Links and Code Standards3. PSP Table4. Presentation of the Finished Product4.1 Main Interface4.2 Basic Calculation (128 20)4.3 Compound Expression4.4 Division by zero(5/0)4.5 Calculation History4.6 Delete a History Record4.7 History Persistence After Refresh4.8 Frontend Error When Backend Is Stopped5. Design and Implementation Process5.1 Requirement Analysis5.2 System Architecture5.3 Frontend Design5.4 Backend Design5.5 API Design5.6 Database Design5.7 Calculation Module5.8 History Module5.9 Error Handling5.10 Frontend/Backend Interaction6. Code Explanation7. Personal Journey and Learnings1. Course InformationItemContentCourseWeb DevelopmentAssignmentAssignment 1 — Front‑End and Back‑End Separation Calculator SystemFZ ID8324013142. GitHub Repository Links and Code StandardsFrontend Repository:Msq-168/web-calculator-frontend: frontendhttps://github.com/Msq-168/web-calculator-frontendBackend Repository:Msq-168/web-calculator-backend: Backendhttps://github.com/Msq-168/web-calculator-backendFrontend Code Standard:web-calculator-frontend/frontend codestyle.md at main · Msq-168/web-calculator-frontendhttps://github.com/Msq-168/web-calculator-frontend/blob/main/frontend%20codestyle.mdBackend Code Standard:web-calculator-backend/backend codestyle.md at main · Msq-168/web-calculator-backendhttps://github.com/Msq-168/web-calculator-backend/blob/main/backend%20codestyle.md3. PSP TablePhaseEstimated (min)Actual (min)Requirement Analysis1520System Design3040Backend Development100130Expression Calculation Module4050Database Design2025History Module3040Frontend Development80100Frontend/Backend Integration5070Testing3040Deployment Repository2030Blog Writing3060Others1515Total4305204. Presentation of the Finished Product4.1 Main InterfaceThe main page of the calculator includes an input display screen, number and operator buttons, and a history table. Each history record has a Delete button. When the page loads, it automatically fetches all history records from the backend.4.2 Basic Calculation (128 20)4.3 Compound Expression12*3712*3910/2712.08-3*22-5833*-2-64.4 Division by zero(5/0)4.5 Calculation HistoryCalculation history list. CallGET /api/historyto read SQLite database. The table shows id, expression, result and creation time. Newest records are displayed on top.4.6 Delete a History RecordDelete single history item. Frontend sendsDELETE /api/history/{id}request. Backend deletes the corresponding database record, then frontend refreshes the history table. It also supports clearing all history records viaDELETE /api/history.4.7 History Persistence After RefreshHistory data still exists after page refresh. This proves data is saved in backend SQLite database instead of browser memory.4.8 Frontend Error When Backend Is StoppedAfter shutting down the FastAPI backend service, the frontend cannot receive API responses and shows Network Error. This verifies that the frontend cannot calculate independently.5. Design and Implementation Process5.1 Requirement AnalysisSystem requirements:Build a web calculator supporting four arithmetic operations, parentheses and decimals.All calculation logic runs on backend.Support saving calculation history records.Support deleting single record and clearing all history.Strict separation of front and backend: two independent repositories.Each repository containsREADME.mdandcodestyle.md.5.2 System ArchitectureFrontend (HTML CSS Vanilla JavaScript) ↓ HTTP / JSON Fetch Backend (FastAPI Python) ↓ Database (SQLite)The frontend only handles UI interaction. The backend provides REST API interfaces. SQLite realizes data persistence. CORS is enabled to allow cross-origin access from frontend web pages.5.3 Frontend DesignSingle page:index.html, written in native JavaScript without any framework.Calculator buttons and display box; history table.Use fetch to send HTTP requests and communicate with backend.Catch network exceptions and show Network Error if backend is offline.Load history automatically on page load. Refresh history table after calculation or deletion.5.4 Backend DesignUse FastAPI as web service framework.Four APIs:POST /api/calculateGET /api/historyDELETE /api/history/{record_id}DELETE /api/historyLocal SQLite database. The table will be automatically created when the program starts, no manual SQL script needed.Add CORS middleware for cross-origin requests.5.5 API DesignMethodPathDescriptionPOST/api/calculateReceive math expression, compute and save history recordGET/api/historyQuery all calculation history recordsDELETE/api/history/{record_id}Delete one single history record by idDELETE/api/historyClear all calculation history records5.6 Database DesignFieldTypeDescriptionidINTEGER PRIMARY KEY AUTOINCREMENTrecord unique idexpressionTEXTmath input expressionresultTEXTcalculation resultcreate_timeTEXTrecord create time5.7 Calculation ModuleReceive expression string sent from frontend and compute on backend. Catch calculation exceptions. Insert record into database if success. Return error directly and skip database writing if failed.5.8 History ModuleInsert a new record into history table after successful calculation.Query all records, sorted in reverse order by id.Delete single record by id or clear the whole table.Close SQLite connection after every database operation. Add.gitignoreto ignorecalc_history.dband prevent committing database file to repository.5.9 Error HandlingIllegal math expression → returncode:500, msg:calculate errorDivision by zero → returncode:500, msg:calculate errorFrontend network request failure → frontend showsNetwork Error5.10 Frontend/Backend InteractionUser clicks calculator buttons to build expression string.User presses equal button. Frontend sends POST request to/api/calculate.Backend receives expression, performs calculation and saves record into database if success.Backend returns JSON result to frontend.Frontend displays result and callsloadHistory()to refresh history table.6. Code Explanationbackend core(app.py)from fastapi import FastAPIfrom fastapi.middleware.cors import CORSMiddlewareimport sqlite3import timefrom typing import Optionalapp FastAPI()# CORS settingsapp.add_middleware(CORSMiddleware,allow_origins[*],allow_credentialsTrue,allow_methods[*],allow_headers[*],)# Initialize database and create history tabledef init_database():conn sqlite3.connect(calc_history.db)cursor conn.cursor()cursor.execute(CREATE TABLE IF NOT EXISTS history(id INTEGER PRIMARY KEY AUTOINCREMENT,expression TEXT,result TEXT,create_time TEXT))conn.commit()conn.close()init_database()# 1. POST /api/calculate: receive expression and computeapp.post(/api/calculate)def calculate(data: dict):expression data.get(expression)if not expression:return {code: 500, msg: empty expression}try:# Calculate on backendresult str(eval(expression))current_time time.strftime(%Y-%m-%d %H:%M:%S)# Insert record into databaseconn sqlite3.connect(calc_history.db)cursor conn.cursor()cursor.execute(INSERT INTO history(expression, result, create_time) VALUES (?, ?, ?),(expression, result, current_time))conn.commit()conn.close()return {code: 200, data: {result: result}}except Exception:return {code: 500, msg: calculate error}# 2. GET /api/history: fetch all history recordsapp.get(/api/history)def get_history():conn sqlite3.connect(calc_history.db)cursor conn.cursor()cursor.execute(SELECT id, expression, result, create_time FROM history ORDER BY id DESC)rows cursor.fetchall()conn.close()record_list []for row in rows:record_list.append({id: row[0],expression: row[1],result: row[2],time: row[3]})return {code: 200, data: record_list}# 3. DELETE /api/history/{record_id}: delete single recordapp.delete(/api/history/{record_id})def delete_single_record(record_id: int):conn sqlite3.connect(calc_history.db)cursor conn.cursor()cursor.execute(DELETE FROM history WHERE id ?, (record_id,))conn.commit()conn.close()return {code: 200, msg: delete success}# 4. DELETE /api/history: clear all recordsapp.delete(/api/history)def delete_all_records():conn sqlite3.connect(calc_history.db)cursor conn.cursor()cursor.execute(DELETE FROM history)conn.commit()conn.close()return {code: 200, msg: clear all success}if __name__ __main__:import uvicornuvicorn.run(app:app, host127.0.0.1, port5000, reloadTrue)frontend core(index.html)!DOCTYPE htmlhtml langenheadmeta charsetUTF-8titleWeb Calculator Frontend/titlestyle.calculator{width:320px;margin:20px auto;padding:15px;border:1px solid #888;border-radius:8px;}#display{width:95%;height:40px;font-size:22px;text-align:right;margin-bottom:10px;}button{width:70px;height:70px;font-size:20px;margin:3px;cursor:pointer;}table{margin:30px auto;border-collapse: collapse;}th,td{border:1px solid #aaa;padding:8px;min-width:80px;text-align:center;}/style/headbodydiv classcalculatorinput typetext iddisplay readonlybrbutton οnclickappendChar(7)7/buttonbutton οnclickappendChar(8)8/buttonbutton οnclickappendChar(9)9/buttonbutton οnclickappendChar(/)//buttonbrbutton οnclickappendChar(4)4/buttonbutton οnclickappendChar(5)5/buttonbutton οnclickappendChar(6)6/buttonbutton οnclickappendChar(×)×/buttonbrbutton οnclickappendChar(1)1/buttonbutton οnclickappendChar(2)2/buttonbutton οnclickappendChar(3)3/buttonbutton οnclickappendChar(-)-/buttonbrbutton οnclickappendChar(()(/buttonbutton οnclickappendChar(0)0/buttonbutton οnclickappendChar()))/buttonbutton οnclickappendChar()/buttonbrbutton οnclickappendChar(.)./buttonbutton οnclickclearDisplay()C/buttonbutton οnclickcalcEqual() stylewidth:150px/button/divtable idhistory-tabletheadtrthID/ththExpression/ththResult/ththTime/ththOperation/th/tr/theadtbody/tbody/tablediv styletext-align:center;button οnclickclearAllHistory()Clear All History/button/divscriptconst BASE_URL http://127.0.0.1:5000;// append character to input boxfunction appendChar(char) {const inputBox document.getElementById(display);inputBox.value char;}// clear calculator inputfunction clearDisplay() {document.getElementById(display).value ;}// send expression to backend api /api/calculateasync function calcEqual() {let expression document.getElementById(display).value;if (!expression) return;expression expression.replaceAll(×, *);try {const response await fetch(${BASE_URL}/api/calculate, {method: POST,headers: {Content-Type: application/json},body: JSON.stringify({expression: expression})});const resData await response.json();if (resData.code 200) {document.getElementById(display).value resData.data.result;loadHistory();} else {document.getElementById(display).value Error;}} catch (err) {document.getElementById(display).value Network Error;}}// load all history records from /api/historyasync function loadHistory() {const response await fetch(${BASE_URL}/api/history);const resData await response.json();let html ;for (const item of resData.data) {html trtd${item.id}/tdtd${item.expression}/tdtd${item.result}/tdtd${item.time}/tdtdbutton οnclickdeleteSingleRecord(${item.id})Delete/button/td/tr;}document.querySelector(#history-table tbody).innerHTML html;}// delete single record by idasync function deleteSingleRecord(recordId) {await fetch(${BASE_URL}/api/history/${recordId}, {method: DELETE});loadHistory();}// delete all historyasync function clearAllHistory() {await fetch(${BASE_URL}/api/history, {method: DELETE});loadHistory();}// load history after page loadedwindow.onload loadHistory;/script/body/html7. Personal Journey and LearningsProblems encountered during development:Cross-origin error between frontend and backend. CORS middleware was not configured for FastAPI, so browsers blocked requests. Adding CORSMiddleware solved the cross-origin issue.Database connection was not closed properly. Multiple requests triggered warnings about occupied database. We close SQLite connection after each read and write operation.Wrong API path. Frontend called/calculateinstead of the required/api/calculate, resulting in 404 not found error.Git commit issue. I nearly uploaded the auto-generatedcalc_history.dbdatabase file..gitignoreis configured to ignore runtime generated files.Unstable GitHub network. Retry after switching network to finish repository upload.Knowledge learned:Understand the real separation of frontend and backend: UI and calculation logic are separated and communicate through JSON APIs.FastAPI API development and CORS configuration.Basic CRUD operations of SQLite in Python.Git/GitHub version control and standard software engineering documents including.gitignore,codestyle.mdandREADME.md.Joint debugging workflow: test backend API alone first, write frontend, then integrate and debug the whole system.Future improvements:Replace unsafeeval()with AST module to parse expressions securely.Add user management, so each user has independent calculation history.Deploy the project to public server for internet access.