栖居在城市的大地上,分享城市中的感想予你,在留言板留下你的足迹,希望你在这里有所收获,祝幸运

开源

今年 8 月,我做了一个决定:把「失业互助平台」从一个想法变成一个开源项目。花了几天时间,从需求设计、前端页面、后端 API 到数据库表结构,完整地做了一版,命名为 ShiYeLeHuZhu(失业乐互助),采用 MIT 协议开源在 GitHub 上。

项目地址:

写这篇文章,一是做个项目记录,二是把开发过程中踩过的坑和设计取舍讲清楚,给同样想做「一个人全栈开源项目」的朋友一些参考。

为什么做这个项目

起因很直接:经济下行周期里,失业的人比想象中多,而他们需要的信息和工具是分散的——失业保险金怎么申领、社保断缴怎么补、财务跑道还有多长、心理撑不住的时候打哪个电话。这些内容每一条单独看都不难找,但没有一个地方把它们组织好。

市面上的求职产品都在解决「怎么找到工作」,几乎没有产品在认真解决「失业期间怎么把日子过好」。我想做的就是这个:一个给失业人群的信息门户 + 个人管理工具台,不贩卖焦虑,只提供可操作的信息和工具。

项目是做什么的

整个项目分两层:上层是面向公众的信息门户,下层是登录后可用的个人管理工具台。

信息门户部分包含:失业后的六座大困境分析、就业市场数据透视(所有数据标注来源与截止时间)、行业趋势、八类资源工具箱(经济保障/社保/技能/心理/求职/创业/法律/转型)、可迁移技能测评(5 题问卷 + SVG 雷达图)、心理热线与自救指南、真实转型故事、30 天行动清单、财务跑道计算器和常见问题。

工具台部分是登录后的四个核心模块:求职追踪(投递记录、状态流转、面试反馈、统计面板)、失业日记(每日心情打卡 + 失业天数计数 + 小成就记录)、收支记账(收支分类、月度汇总、存款支撑月数预估)、技能充电(学习计划、每日打卡、连续天数、14 天热力图)。此外还有邮箱订阅和匿名反馈,反馈直接写入后端数据库。

技术架构:刻意做的减法

这个项目的技术选型没什么新潮的东西,反而在几个地方刻意做了减法。

前端是一个 180KB 的单文件 HTML。所有 CSS、JS、SVG 图标全部内联,零外部依赖——没有 React、没有 CDN 字体、没有图标库。所有图标是 34 个手写的 SVG symbol,全站零 emoji(emoji 在不同系统渲染差异太大,部分 Android 机型直接显示为方块)。图表全部用内联 SVG 手写:技能测评的雷达图、收支饼图、打卡热力图、财务计算器的进度环。这个决定让部署变成「把一个文件放上去」,也让整个页面在断网时依然可用。

后端是 FastAPI + PostgreSQL,约 1000 行 Python,18 个 API 路由。认证用 JWT + bcrypt,密码哈希、token 验证、SQL 全部参数化查询。数据库 9 张表:users、job_applications、diary_entries、transactions、skill_plans、skill_checkins、user_settings、subscribers、feedback,配了 11 个索引和 4 个自动更新时间戳的触发器。

部署提供了三套方案:Docker Compose 一键起三个容器(Nginx + FastAPI + PostgreSQL)、裸机 systemd + Nginx、以及宝塔面板的图形化部署文档。考虑到目标用户是中文环境,宝塔文档写得最细。

数据严谨性:每个数字都有出处

做信息类产品最怕的是编数据。这个项目里所有统计数字都做了来源标注:城镇登记失业人数标国家统计局、青年失业率标注明统计口径、高校毕业生存量标教育部、行业增长趋势明确写了「综合招聘平台估算值,非官方统计数据」。开发过程中我专门做了一轮数据核对,修正了四个事实错误——包括「创业担保贷款最高 30 万」实际国标是 20 万、第三产业就业占比引用口径偏差等。法律条款部分全部标注了《社会保险法》和《劳动合同法》的具体条目。

这个习惯来自一个朴素的判断:失业状态下的人本来就焦虑,一个数字错误可能造成真实的决策失误。

开发中踩的坑

记录几个印象深的:

passlib 与 Python 3.13 的兼容性。最初用 passlib 做 bcrypt 哈希,在 Python 3.13 上直接报错,查了半天发现是 passlib 底层与新版 Python 的 crypt 模块变更冲突。解法是绕开 passlib,直接用 bcrypt 库的原生 API,三行代码解决。

PostgreSQL 14 的两个小坑。一是表达式索引里用 to_char() 会报「函数非 IMMUTABLE」,只能换成普通字段索引;二是 CREATE TRIGGER IF NOT EXISTS 在 PG 14 不支持,去掉了才跑通。

一个典型的前端逻辑 bug:登录门控。工具台区域默认 display:none,页面加载时 checkAuth() 检查 token——但我最初只在「有 token」的分支里写了显示逻辑,「无 token」分支直接 return 了。结果是未登录用户看到的工具台区域是纯空白,没有任何「请先登录」的提示。这个 bug 的教训是:每个分支都要对 UI 状态负责,尤其是「什么都不做」的那个分支。

锚点跳转与 JS 滚动的冲突。资源卡片的链接是 href="#xxx" 加 onclick 做 tab 切换,结果浏览器原生锚点跳转抢在 JS 的 scrollIntoView 之前执行,页面跳到错误位置。改成 href="javascript:void(0)" 彻底规避。这是一次「HTML 默认行为 vs JS 控制」的经典冲突。

项目现状与后续计划

项目 8 月 10 日创建,目前 25 个文件、约 3000 行代码(前端 1963 行 + 后端 1012 行)。没有任何宣传的情况下,GitHub 上有了一些自然流量:几个独立用户克隆了代码,收获了第一个 Star。对公益项目来说,这是需求真实存在的信号。

接下来的计划按优先级:第一,把网站真正部署上线——代码完成不等于产品可用,这是从 0 到 1 的门槛;第二,完善 README 的可视化展示;第三,持续迭代工具台的功能。

如果你也在经历职业空窗期,或者单纯想看看一个「信息门户 + 工具台」的完整实现,欢迎访问项目仓库:

Loading...

也欢迎提 Issue 和 PR——这本来就是一个靠社区生长的项目。

项目采用 MIT 协议开源。文中所有平台数据的来源与截止时间均已在项目页面内标注。