用 AtomCode 从零开发并部署上线:一个 Flask 待办应用的完整实战
用 AtomCode 从零开发并部署上线:一个 Flask 待办应用的完整实战
本文是一篇全程真机实操的记录。所有命令、输出、HTTP 状态码、Git 提交与仓库地址均来自服务器
117.72.182.3(Ubuntu 22.04 / Python 3.10.12)上的真实执行,非示意。目标:只给 AtomCode 一句需求,让它从零写出一个可运行的 Flask 任务管理应用,然后在服务器上部署上线并推送到全新的 Gitee 仓库。
- 编程执行引擎:AtomCode 4.26.0(模型
deepseek-v4-flash)- 最终成果仓库:
https://gitee.com/LiaCin/atomcode-flask-todo
目录
- 一、这篇文章要证明什么
- 二、整体流程一图看懂
- 三、环境准备
- 四、第 1 步:写清楚需求(Prompt 即规格)
- 五、第 2 步:一条命令让 AtomCode 从零开发
- 六、第 3 步:AtomCode 交付了什么
- 七、第 4 步:跑测试(18 个用例)
- 八、第 5 步:部署上线 + curl 验收
- 九、第 6 步:推送到全新 Gitee 仓库
- 十、安全收尾
- 十一、关键命令速查表
- 十二、踩坑与经验
- 十三、附录:AtomCode 生成的核心代码
一、这篇文章要证明什么
一句话:从一句需求到线上可访问的服务 + 云端代码仓库,全程由 AtomCode 自动完成编码,人只负责"下需求、验收、上线"。
拆成 6 个可验证的步骤:
| 步骤 | 做什么 | 由谁完成 | 验收凭证 |
|---|---|---|---|
| 1 | 写需求(prompt.txt) | 人 | 见 §四 |
| 2 | 从零生成全部代码 | AtomCode | 见 §五、§六 |
| 3 | 自测 | AtomCode 自跑 + 人复跑 | 18 tests OK(§七) |
| 4 | 部署运行 | 人 | curl200/201(§八) |
| 5 | 新建远程仓库 | 人(Gitee API) | HTTP 201(§九) |
| 6 | 推送代码 | 人(git push) | new branch main(§九) |
二、整体流程一图看懂
核心分工:AtomCode 负责 ②③(写代码 + 自测),人负责 ①④⑤⑥⑦⑧(下需求、验收、部署、建仓、推送)。
三、环境准备
服务器实测环境:
OS : Ubuntu 22.04(内核容器/云主机) Python : Python 3.10.12 pip : pip 22.0.2 Flask : 3.1.3(已装) AtomCode: 4.26.0 (/usr/local/bin/atomcode,Rust 二进制) 模型 : deepseek-v4-flash(base_url = https://llm-api.atomgit.com/v1) 工作目录 : /root/projects/flask-todoAtomCode 是 Rust 单二进制,不依赖 Node 运行时;官方一键安装:
curl -fsSL https://raw.atomgit.com/.../install.sh | sh
四、第 1 步:写清楚需求(Prompt 即规格)
AtomCode 的产出质量,几乎完全取决于需求写得有多具体。这里把需求当"规格说明书"写进prompt.txt,明确到接口、字段、端口、文件清单:
You are an expert software engineer. Build a complete, runnable Flask task-management web application in /root/projects/flask-todo. 1. Backend (app.py): - Flask only, SQLite (tasks.db),tasks 表:id/title/description/done/created_at - REST API: GET /api/health -> {"status":"ok"} GET /api/tasks -> 全部任务(最新在前) POST /api/tasks -> 创建(JSON title/description),返回 201 GET /api/tasks/<id> -> 单条或 404 PUT /api/tasks/<id> -> 更新,返回更新后对象 DELETE /api/tasks/<id> -> 删除,返回 204 - static/ 目录托管前端;默认监听 127.0.0.1:5000(env PORT 可覆盖;后续为对外访问已改为 0.0.0.0,见 §8.1) - 启动时自建表;if __name__ == "__main__" 守卫 2. Frontend (static/index.html + app.js + style.css):原生 fetch,无框架 3. requirements.txt: 仅 flask 4. README.md:运行说明 + 接口表 5. test_app.py:用 Flask test client 建任务并断言其出现,可 python3 直接跑 Keep everything local; do NOT expose the server publicly.经验:接口用"方法 + 路径 + 期望状态码"三元组写死,AtomCode 就不会自由发挥出你不想要的路由。
五、第 2 步:一条命令让 AtomCode 从零开发
用 headless(非交互)模式,让 AtomCode 读需求文件、自动写代码、自动自测:
cd/root/projects/flask-todo atomcode-y\-C/root/projects/flask-todo\--max-turns30\--prompt-file /root/projects/flask-todo/prompt.txt\--disable-tools none\>build.log2>&1参数拆解:
| 参数 | 作用 |
|---|---|
-y/--dangerously-skip-permissions | 自动批准所有工具调用(无人值守必需) |
-C <dir> | 指定工作目录,代码就地生成 |
--max-turns 30 | 最多 30 个自主回合,防止跑飞 |
--prompt-file | 从文件读需求(比-p更适合长规格) |
--disable-tools none | 允许全部工具(读写文件、跑 bash、跑测试) |
build.log里 AtomCode 的自述(真实节选):
[engine v2] new stack active (model deepseek-v4-flash) [headless] --dangerously-skip-permissions: all tool calls are auto-approved ... All 18 tests pass. Let me clean up the temp database file ... and finalize. All tasks complete. Here's a summary of the project:也就是说,AtomCode自己写完代码后,自己跑了 18 个测试并全部通过,才宣布收工。
六、第 3 步:AtomCode 交付了什么
find实测生成的文件清单:
/root/projects/flask-todo/app.py # Flask 后端(REST + SQLite + 静态托管) /root/projects/flask-todo/static/index.html # 单页前端 /root/projects/flask-todo/static/app.js # 原生 fetch CRUD /root/projects/flask-todo/static/style.css # 响应式样式 /root/projects/flask-todo/test_app.py # 18 个 API 测试 /root/projects/flask-todo/requirements.txt # 仅 flask /root/projects/flask-todo/README.md # 运行说明 + 接口表 /root/projects/flask-todo/build.log # AtomCode 自述日志AtomCode 生成的接口一览(与需求完全对齐):
| Method | Path | 动作 | 状态码 |
|---|---|---|---|
| GET | /api/health | 健康检查 | 200 |
| GET | /api/tasks | 列出全部(最新在前) | 200 |
| POST | /api/tasks | 创建任务 | 201 |
| GET | /api/tasks/<id> | 查单条 | 200 / 404 |
| PUT | /api/tasks/<id> | 更新 | 200 |
| DELETE | /api/tasks/<id> | 删除 | 204 |
七、第 4 步:跑测试(18 个用例)
人工复跑一遍 AtomCode 写的测试,验证不是"自说自话":
cd/root/projects/flask-todo&&python3 test_app.py真实输出(尾部):
test_get_task ... ok test_get_task_not_found ... ok test_health ... ok test_list_tasks_empty ... ok test_list_tasks_order ... ok test_update_task_done ... ok test_update_task_invalid_done ... ok test_update_task_not_found ... ok test_update_task_title ... ok ---------------------------------------------------------------------- Ran 18 tests in 0.133s OK覆盖:健康检查、完整 CRUD、参数校验(缺 title / done 非法值)、404 分支、列表排序、静态文件托管。18/18 通过。
八、第 5 步:部署上线 + curl 验收
后台启动服务(干净库,重定向日志):
cd/root/projects/flask-todorm-ftasks.dbnohuppython3 app.py>/tmp/flask.out2>&1&启动日志(真实,绑定 0.0.0.0 后):
* Serving Flask app 'app' * Debug mode: on * Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:5000 * Running on http://172.16.0.3:5000 * Debugger is active!端口确认在听(已绑定到全部网卡0.0.0.0):
$ ss-ltnp|grep5000LISTEN01280.0.0.0:5000... users:(("python3",pid=27836,...))验收 1|健康检查:
$curl-s-w'\n[HTTP %{http_code}]\n'http://127.0.0.1:5000/api/health{"status":"ok"}[HTTP200]验收 2|创建任务(中文入参):
$curl-s-XPOST http://127.0.0.1:5000/api/tasks\-H'Content-Type: application/json'\-d'{"title":"部署验收任务","description":"AtomCode 从零开发并上线"}'{"created_at":"2026-07-10T09:38:46.063850+00:00","description":"AtomCode 从零开发并上线","done":0,"id":1,"title":"部署验收任务"}[HTTP201]验收 3|列表回读:
$curl-shttp://127.0.0.1:5000/api/tasks[{"id":1,"title":"部署验收任务","done":0,...}][HTTP200]验收 4|前端首页:
$curl-s-o/dev/null-w'index.html [HTTP %{http_code}] %{size_download} bytes\n'http://127.0.0.1:5000/ index.html[HTTP200]891bytes至此,服务已在服务器上真实运行并对外提供 REST + 前端页面。
8.1 改为对外监听0.0.0.0(公网可访问)
默认app.py写的是host="127.0.0.1",只能本机127.0.0.1访问。若要让服务对外部网络开放,只需把启动地址改成0.0.0.0:
# app.py 第 174-176 行host="0.0.0.0"# 原为 "127.0.0.1"port=int(os.environ.get("PORT",5000))app.run(host=host,port=port,debug=True)改完重启并复验(真实输出):
$ ss-ltnp|grep5000LISTEN01280.0.0.0:5000... users:(("python3",pid=27836,...))$curl-s-o/dev/null-w'%{http_code}\n'http://127.0.0.1:5000/api/health200$curl-s-o/dev/null-w'%{http_code}\n'http://0.0.0.0:5000/api/health200外部可达性还需两步(本次已确认服务器内部0.0.0.0绑定成功,但公网探测返回000):
| 检查项 | 状态 | 说明 |
|---|---|---|
服务绑定0.0.0.0:5000 | ✅ 已生效 | ss明确看到0.0.0.0:5000 |
| 云安全组 / 防火墙放通 5000 | ⚠️ 需手动 | 本机curl 117.72.182.3:5000仍000,需在云控制台入站规则放行 TCP 5000 |
| 本机公网 IP | 117.72.182.3 | 外部访问地址即http://117.72.182.3:5000 |
改完记得把代码推回仓库:
git commit -m 'chore: bind 0.0.0.0:5000 for external access' && git push(实际已推,commita84c9b4)。
⚠️安全红线:
debug=True的开发服务器一旦绑定0.0.0.0暴露到公网,Werkzeug 调试器存在**远程代码执行(RCE)**风险(知道 PIN 或绕过 PIN 即可执行任意命令)。公网开放务必关 debug,见下方生产建议。
生产建议:
app.run(debug=True)仅用于本次验收;正式上线应换gunicorn -w 4 -b 127.0.0.1:5000 app:app+ Nginx 反代(Nginx 监听0.0.0.0:80/443对外,Flask 仍只绑内网),并关闭 debug。若确实要 Flask 直连公网,至少debug=False且加反向代理与访问控制。
九、第 6 步:推送到全新 Gitee 仓库
9.1 用 Gitee API 新建仓库
curl-s-XPOST'https://gitee.com/api/v5/user/repos'\-H'Content-Type: application/json'\-d'{"access_token":"<TOKEN>","name":"atomcode-flask-todo", "description":"由 AtomCode 从零自动开发的 Flask 任务管理应用", "private":false,"has_issues":true}'返回(真实,节选):
{"full_name":"LiaCin/atomcode-flask-todo","html_url":"https://gitee.com/LiaCin/atomcode-flask-todo.git","private":true}[HTTP201]⚠️ 注意:即使传
private:false,Gitee 新建仓库默认仍为私有,需要公开可到仓库设置里手动改。
9.2 加 .gitignore(别把库/日志/凭据提交上去)
__pycache__/ *.pyc tasks.db build.log prompt.txt *.out .venv/9.3 配置 Git 身份并提交
该服务器原本没有全局 Git 身份(
/root/.gitconfig不存在),首次提交前必须配置:
gitconfig--globaluser.name"LiaCin"gitconfig--globaluser.email"liacin@gitee.com"gitconfig--globalinit.defaultBranch maincd/root/projects/flask-todogitinitgitadd-Agitcommit-m"feat: AtomCode 从零生成的 Flask 待办应用(REST API + SQLite + 原生JS前端 + 18测试)"提交结果(真实):
2deaf20 feat: AtomCode 从零生成的 Flask 待办应用... ---tracked files--- .gitignore README.md app.py requirements.txt static/app.js static/index.html static/style.css test_app.py9.4 推送
# 用 token 临时鉴权:https://<用户名>:<TOKEN>@gitee.com/<owner>/<repo>.gitgitremoteaddorigin"https://LiaCin:<TOKEN>@gitee.com/LiaCin/atomcode-flask-todo.git"gitbranch-Mmaingitpush-uorigin main推送结果(真实):
To https://gitee.com/LiaCin/atomcode-flask-todo.git * [new branch] main -> main Branch 'main' set up to track remote branch 'main' from 'origin'.API 二次核验default_branch已变为main:
$curl-s'https://gitee.com/api/v5/repos/LiaCin/atomcode-flask-todo?access_token=<TOKEN>'..."default_branch":"main"...[HTTP200]🎉代码已上云:https://gitee.com/LiaCin/atomcode-flask-todo
十、安全收尾
真机操作后必须做的收尾(本次已全部执行):
- 清除 remote 里的明文 token——push 完把带 token 的 URL 换掉:
核验:gitremote set-url origin https://gitee.com/LiaCin/atomcode-flask-todo.gitgit remote -v已不含 token。 - 停掉验收用的 debug 服务:
pkill -f 'python3 app.py'。 - 删除本地含明文凭据的临时脚本(root 密码 / Gitee token 均不落盘)。
- 敏感文件进 .gitignore:
tasks.db、build.log、prompt.txt、*.out不入库。
十一、关键命令速查表
| 阶段 | 命令 |
|---|---|
| 让 AtomCode 开发 | atomcode -y -C <dir> --max-turns 30 --prompt-file prompt.txt --disable-tools none |
| 复跑测试 | python3 test_app.py |
| 后台起服务 | nohup python3 app.py > /tmp/flask.out 2>&1 & |
| 查端口 | ss -ltnp | grep 5000 |
| 健康检查 | curl -s http://0.0.0.0:5000/api/health(或127.0.0.1) |
| 开放公网 | 改app.run(host="0.0.0.0")+ 云安全组放行 5000 |
| 建 Gitee 仓库 | curl -X POST gitee.com/api/v5/user/repos -d '{"access_token":"..","name":".."}' |
| Git 身份 | git config --global user.name/user.email |
| 首推 | git init && git add -A && git commit -m .. && git push -u origin main |
| 清 token | git remote set-url origin https://gitee.com/<owner>/<repo>.git |
十二、踩坑与经验
| 坑 | 现象 | 解决 |
|---|---|---|
| Gitee token 校验用错方式 | 用Bearer头 → 401 | Gitee 用?access_token=查询参数或Authorization: token |
| owner 用了显示名 | Lincoln/xxx→ 404 | 用pathLiaCin(显示名 name ≠ 仓库 owner path) |
| 新仓库默认私有 | 传private:false仍是私有 | 到仓库设置手动改公开 |
| 服务器无 Git 身份 | commit 报 author unknown | 先git config --global user.name/email |
| token 写进 remote | 明文残留在.git/config | push 后立即git remote set-url去掉 token |
| headless 权限 | 交互确认卡住 | 无人值守用-y,并配--max-turns兜底 |
| 需求太笼统 | 生成的路由/字段跑偏 | prompt 里把"方法+路径+状态码+字段"写死 |
最大的一条经验:把prompt.txt当成给资深工程师的验收标准来写——你写得越像规格说明书,AtomCode 一次成型的概率越高。这次 18 个测试全过、6 个接口零返工,靠的就是需求写得够死。
十三、附录:AtomCode 生成的核心代码
app.py(AtomCode 自动生成,未经人工改动,节选主体):
#!/usr/bin/env python3"""Flask task-management API with SQLite backend."""importos,sqlite3fromdatetimeimportdatetime,timezonefromflaskimportFlask,g,jsonify,request,send_from_directory app=Flask(__name__,static_folder="static")DATABASE=os.path.join(os.path.dirname(os.path.abspath(__file__)),"tasks.db")defget_db():if"db"noting:g.db=sqlite3.connect(DATABASE)g.db.row_factory=sqlite3.Rowreturng.dbdefinit_db():withapp.app_context():db=get_db()db.execute(""" CREATE TABLE IF NOT EXISTS tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, description TEXT, done INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL)""")db.commit()@app.route("/api/health")defapi_health():returnjsonify({"status":"ok"})@app.route("/api/tasks",methods=["POST"])defapi_create_task():data=request.get_json(silent=True)ifnotdataornotdata.get("title","").strip():returnjsonify({"error":"title is required"}),400title=data["title"].strip()description=data.get("description","").strip()orNonenow=datetime.now(timezone.utc).isoformat()db=get_db()cur=db.execute("INSERT INTO tasks (title, description, done, created_at) VALUES (?,?,0,?)",(title,description,now))db.commit()task=db.execute("SELECT * FROM tasks WHERE id=?",(cur.lastrowid,)).fetchone()returnjsonify(dict(task)),201# ... GET/PUT/DELETE /api/tasks/<id>、静态托管路由略(结构同上)...if__name__=="__main__":init_db()port=int(os.environ.get("PORT",5000))app.run(host="0.0.0.0",port=port,debug=True)# 已改为对外监听;生产环境应 debug=False亮点(全部由 AtomCode 自主决定):
- 用
g+teardown_appcontext管理 SQLite 连接,请求级复用、自动关闭; - PUT 更新做了类型与取值校验(
done只允许 0/1,title 必须字符串); created_at用带时区的 ISO8601;列表按created_at DESC排序;- 入口
init_db()幂等建表,端口支持PORT环境变量覆盖。
一句话总结:需求写进一个文件 →
atomcode -y --prompt-file一条命令 → 8 个文件 + 18 个通过的测试自动生成 →curl验收 200/201 → Gitee 建仓 +git push上云。人只做了"下需求、验收、上线",写代码这件事,AtomCode 全包了。成果仓库:
https://gitee.com/LiaCin/atomcode-flask-todo
