Front‑End and Back‑End Separation Calculator System
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.

相关新闻

点一下地图上的村点位,大屏右侧三张图表怎么同时换数据?

点一下地图上的村点位,大屏右侧三张图表怎么同时换数据?

一、一次点击换来三张图的不同反应镇里那面大屏有三米宽,左边一张地图铺满,上面标着辖区内十四个村的点位,右边竖着三张图,产量趋势、人口结构、积分排行。需求很朴素,鼠标点某个村的点位,右边三张图同时换…

2026/10/7 8:09:02 阅读更多 →
生成文本一眼就是机器写的,三个可量化特征该怎么拆解?

生成文本一眼就是机器写的,三个可量化特征该怎么拆解?

一、一分钟挑出十篇的那次复盘最早发现这个问题是在一次稿子复盘上。运营同事把十篇机器生成的稿子混在三篇人工稿里让我们挑,我们不到一分钟就把那十篇全挑出来了,理由说不上来,就是读起来一个味儿。为了把这种感觉变成能动手改的东西&#…

2026/10/7 8:09:02 阅读更多 →
ai写论文哪个软件最好?答案藏在“骨架”与“贴皮”的区别里——云智变AI 云智变AI官网www.yunzhibian.cn 微信公众号搜一搜 云智变ai学术

ai写论文哪个软件最好?答案藏在“骨架”与“贴皮”的区别里——云智变AI 云智变AI官网www.yunzhibian.cn 微信公众号搜一搜 云智变ai学术

先戳破一个错觉:你搜到的“最好”,回答的根本不是你的问题 每年毕业季,“ai写论文哪个软件最好”都会成为搜索高频词。你点开那些推荐帖,看到的答案高度统一:ChatGPT、DeepSeek、Kimi、豆包。这些推荐错了吗&#xff…

2026/10/7 8:08:02 阅读更多 →

最新新闻

MOS管五维测试法:告别万用表误判

MOS管五维测试法:告别万用表误判

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 9:04:50 阅读更多 →
SATA高速接口PCB设计实战:从协议到信号完整性

SATA高速接口PCB设计实战:从协议到信号完整性

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 9:04:50 阅读更多 →
Spyglass CDC/RDC验证目录深度解析与工程实践指南

Spyglass CDC/RDC验证目录深度解析与工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 9:04:50 阅读更多 →
STM32F103T8C6最小系统板设计:嘉立创EDA从原理图到打样全流程

STM32F103T8C6最小系统板设计:嘉立创EDA从原理图到打样全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 9:04:50 阅读更多 →
ROS2核心通信机制与实战:从安装到导航多机通信全解析

ROS2核心通信机制与实战:从安装到导航多机通信全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 9:04:50 阅读更多 →
ESP32隐藏射频通路:蓝牙Wi-Fi共存下的底层调试与感知

ESP32隐藏射频通路:蓝牙Wi-Fi共存下的底层调试与感知

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 9:03:49 阅读更多 →

日新闻

ROS2机械臂仿真与运动控制:从URDF建模到Gazebo实战全解析

ROS2机械臂仿真与运动控制:从URDF建模到Gazebo实战全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:01:58 阅读更多 →
用浏览器直接改ESP32的WiFi密码:NVS键值配置工具设计与实现

用浏览器直接改ESP32的WiFi密码:NVS键值配置工具设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:02:00 阅读更多 →
芯片封装缺陷检测:扫描声学显微镜(SAT)原理与实操指南

芯片封装缺陷检测:扫描声学显微镜(SAT)原理与实操指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:02:00 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 7:15:40 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 5:29:09 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 6:26:51 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 8:21:32 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 4:21:51 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 1:18:13 阅读更多 →