从零搭建BrewUI:前后端分离的智能酿造管理平台实战
2026/9/20 23:50:46 网站建设 项目流程

1. 项目背景:为什么需要BrewUI

我最初接触到BrewUI,是在帮朋友搭一套家庭智能酿造系统的时候。他在家里做精酿啤酒已经有两年多,配方、温控、发酵记录全散落在不同的App和Excel表格里,每次酿酒都要手动翻记录。当时市面上不是没有酿造管理软件,但要么只支持单一设备,要么界面停留在上个时代,数据导出和配方管理做得一塌糊涂。找了一圈之后,我决定自己动手,把"酿造管理"这件事做成一个真正好用的Web应用,这就是BrewUI的起点。

BrewUI本质上是一个面向自酿爱好者和小型酿造工作室的酿造流程管理工具。它解决的核心问题很直接:把配方设计、酿造过程记录、设备温度监控、发酵进度追踪、批次管理和数据统计全部收敛到一个界面里,不再需要你在不同工具之间来回切换。对于刚入门的玩家,它比Paper和Excel直观得多;对于已经跑了不少批次的进阶玩家,它能帮你积累数据、复盘配方、沉淀自己的酿造经验。

这个项目的目标用户非常明确:一是自酿爱好者,二是在小规模测试配方的工作室,三是偶尔接单做定制酿造的兼职酿友。这三个群体的共同点是——他们不需要工业化酿造管理软件里那些复杂到吓人的功能,但需要一套足够灵活、足够清晰的工具,把酿造这件充满变量的手艺活变得可追踪、可复制、可优化。

我选择做Web应用而不是原生App,原因也很实际:第一,酿造过程跨端使用频率极高,配方设计可能在电脑上完成,发酵监控需要在手机上看;第二,Web应用的部署和维护成本远低于同时维护iOS和Android两套客户端;第三,容器化部署之后,整个工具可以轻松跑在家里NAS或者一台小型服务器上,数据完全自持,不依赖第三方云服务。对于一个长期使用率很高的工具来说,数据在自己的掌控之中,是底线.

2. 整体架构与核心功能拆解

2.1 前后端分离的模块化设计

BrewUI采用前后端分离架构,这算是当前Web应用的主流选择,但具体到酿造管理场景,这个选择有它特别的理由。酿造数据的特点是:写入频率低但单次数据量大,查询模式复杂,而且涉及大量状态变化。比如一次酿造过程包含投料、糖化、煮沸、加酒花、冷却、接种、发酵、装瓶等环节,每个环节都有一批参数需要记录。如果采用传统的服务端渲染,每次页面跳转都要重新加载大量表单和数据,体验会非常割裂。

后端我用了Go语言,主要看重它的并发性能和部署便利性。酿造工作室有时会同时跑多个批次,每个批次挂多个温度探头,后端需要同时处理这些数据流。Go的goroutine模型在这种场景下比Python的GIL更省心,而且编译出来的单二进制文件部署非常简单。前端选择Vue 3,因为它的响应式数据流非常适合做实时刷新场景——温度曲线、pH变化、比重趋势这些图表数据需要实时更新,Vue的响应式机制让这个实现变得非常直接。

数据存储层用了PostgreSQL和Redis组合。PostgreSQL负责所有结构化数据,包括配方、批次、设备配置、用户信息;Redis承担缓存和临时数据存储,比如当前活动的温度监控数据,以及频繁读取的设备状态缓存。这套组合的好处是清晰、可控、容易打理,对于自酿规模的数据量来说绰绰有余,即使数据增长到几十万条记录,PostgreSQL也完全扛得住。

提示:如果你的数据量很小,比如只有几十个批次记录,完全没必要上Redis。直接全部走PostgreSQL反而更简单。我一开始就上了Redis,后来发现初期大部分接口根本不需要缓存,白白增加了一层复杂度。

2.2 配方管理模块

配方管理是BrewUI的核心模块,也是整个应用里最有价值的部分。设计一个可靠的酿造配方,需要考虑麦芽配比、酒花添加计划、酵母选择、糖化温度、发酵温度等多个维度,而且这些维度之间互相影响。传统做法是拿纸笔或者Excel记录,问题在于:配方之间的横向对比非常困难,想从历史配方中迭代优化出更好的版本,更是要翻遍所有记录。

BrewUI的配方模块采用版本化配方设计。每个配方可以创建多个版本,每次调整都自动生成新版本并保留历史版本。这个设计来自代码版本管理的灵感——你改配方参数的时候,系统会记录下这次改动,之后随时可以回溯、对比、甚至恢复旧版本。对于酿酒来说,这一点极其重要:配方调整的变量太多,如果改坏了没有回溯能力,整个批次就废了;有版本化之后,你可以放心大胆地试验新方案。

配方创建页面里集成了一个简易的配方计算器,它可以基于麦芽出糖率和糖化效率预估原麦汁浓度,基于酒花α酸含量和添加时间计算IBU苦度值。底层的计算逻辑参考了多本酿酒经典教材的公式,虽然做不到商业软件那样精确,但对于自酿场景已经足够可靠。对于批次量一致的配方,计算误差能控制在3%以内,这个精度足够支撑日常决策了。

2.3 酿造记录与过程追踪

酿造过程中的记录模块,是我个人在实际使用中最常用也最受益的部分。自酿最怕的不是配方不好,而是不知道自己在哪一步做得好、哪一步做得差。BrewUI把酿造过程拆成标准化阶段:设备准备、投料、糖化、过滤洗糟、煮沸、冷却、发酵、成熟、装瓶,每个阶段都有对应的参数录入模板。

记录的方式我做成了两步:实时记录和分批补录。实时记录适合在酿造现场用手机操作,每个阶段有独立的表单,提交后自动带时间戳;分批补录适合结束后统一整理,系统会按时间顺序排列各个数据点。这两种模式覆盖了绝大多数酿造场景——有时间专注记录的时候用实时模式,手忙脚乱顾不上记录的时候用补录模式,保证数据不会因为现场太乱而缺失。

发酵追踪是这个模块里我投入精力最多的部分。自酿的发酵阶段通常持续一到三周,期间需要记录比重的变化趋势、温度波动、以及观察到的发酵现象。BrewUI允许用户为每个批次设置自定义的测量时间点和提醒,到时间自动生成待办事项。同时支持接入蓝牙比重计和温度探头,自动采集数据生成曲线图。实测下来,自动采集和手动记录相比,不仅仅省去了每天抄录的烦恼,更重要的是数据密度高了之后,能明显看出发酵停滞或者异常波动的时间点.

3. 核心功能实现与关键参数计算

3.1 配方计算引擎的实现

配方计算引擎是BrewUI的技术核心,这个模块的计算准确性直接决定了用户对工具的信任度。我之前做第一版的时候,只是简单地把麦芽重量乘以平均出糖率,结果算出来的浓度和实际测量值差了接近20%,后来仔细研究才发现问题出在单位换算和效率系数的处理上。

最终的计算引擎分三层。第一层是把用户输入的原料按类别归类,麦芽需要处理其潜在出糖量(以每公斤麦芽可产生的糖度·升数表示)、色度、出糖效率;酒花需要处理α酸含量、添加时间、煮沸利用率;辅料需要处理可发酵性比例和添加方式。第二层是基础计算,核心公式如下:

预估原麦汁浓度(单位Plato)= (总可提取糖量(克) ÷ 最终麦汁体积(升) ÷ 1000) × 100 × 效率系数

总可提取糖量 = Σ(每种麦芽重量(kg) × 该麦芽潜在出糖量(克/公斤))

效率系数是这套计算里最需要经验的参数。麦芽的潜在出糖量标注值是在实验室条件下获得的极限值,实际酿造中不可能达到100%。家用设备的效率通常在65%到75%之间,商用设备可以做到80%到85%。BrewUI默认给出70%的经验值,用户可以在批次结束后根据实测数据修正效率系数,系统会自动把这个修正值应用到后续同设备的配方估算中。这个"学习式修正"机制是实测后最有效的优化——设备不同、操作习惯不同,恒定参数永远不可能精确,但动态修正可以越用越准。

IBU苦度值的计算也有几个版本,勃灵公式、火花公式等都有各自的适用场景。BrewUI默认采用Rager公式,它在煮沸时间处于30到90分钟范围内时精度表现最好,而这个范围恰好覆盖了大多数自酿配方的酒花添加策略。Rager公式:

IBU = (酒花重量(克) × α酸含量(%) × 利用率(%) × 1000) ÷ (麦汁体积(升) × 1.34)

其中利用率基于煮沸时间查表获得:煮沸5分钟约5%,15分钟约12%,30分钟约18%,60分钟约27%,90分钟约30%。

建议:新用户第一次使用配方计算器时,可以先用一个以前做过的配方做验证,对比计算结果和实测数据,修正效率系数后再开始设计新配方。这样能最快建立对工具的信任感。

3.2 温度监控与数据采集链路

温度监控功能需要端到端的数据链路设计,从传感器到展示界面的每一步都会影响数据的可靠性和实时性。目前BrewUI支持两类温度数据来源:一类是支持HTTP API的智能温度计,比如iSpindel通过WiFi上报数据;另一类是通过MQTT协议接入的树莓派加DS18B20传感器方案。MQTT方案更灵活,成本也更低,适合DIY玩家。

数据采集流程是这样的:温度传感器每30秒采样一次,通过MQTT推送到BrewUI后端的MQTT broker,后端服务订阅主题后把数据写入Redis缓存,同时异步写入PostgreSQL做持久化。前端通过WebSocket订阅实时数据流,温度变化可以在1秒内反映在页面上。数据写入Redis是为了处理高频查询和短期曲线展示,存PostgreSQL是为了长期存档和批次复盘。

DS18B20传感器的接线虽然不算复杂,但我在实测中踩过一个坑:传感器线缆过长时会出现信号衰减和读数漂移。后来在传感器两端并联了一个4.7kΩ的上拉电阻到VCC,问题才彻底解决。另外,DS18B20的防水探头必须做好密封,如果探头长时间浸泡在液体中,密封不好会导致读数永久性偏移,而且不会自行恢复。

MQTT消息体我设计得尽量精简,只包含传感器ID、时间戳和温度值三个字段,避免网络传输带来的时序抖动:

{ "sensor_id": "ferm1", "timestamp": 1736150400, "temperature": 20.5 }

3.3 批次状态机与阶段流转

酿造批次的状态流转是整个业务逻辑里最容易被忽略、但最容易出bug的部分。不同阶段之间的转换关系如果不明确,就会出现"发酵还没开始就能直接进入装瓶"这种逻辑错误,或者"冷却完成后发酵阶段居然还能修改糖化温度"这类数据矛盾。

BrewUI用状态机来约束批次的生命周期。每个批次实例的状态只有七个:准备、糖化中、煮沸中、冷却中、发酵中、熟化中、已完成。状态之间的跳转只有固定的邻接关系:准备可以进入糖化中,糖化中可以进入煮沸中,以此类推,不允许跳级,更不允许回退到先前已完成的状态。这个设计看起来约束很多,但实际上恰好符合酿造流程本身的线性特征,也减少了用户误操作的概率。

状态流转的同时会触发对应的数据校验规则。比如从糖化中进入煮沸中之前,系统会校验糖化记录是否完整——麦芽投料时间、糖化温度、糖化持续时间、洗糟水量这几项是必填项,缺一不可。同理,从冷却中进入发酵中之前,必须记录冷却后的麦汁温度和比重值。这套校验规则是从几十个真实批次的数据完整性分析中总结出来的,缺失率最高的字段恰恰就是这些影响后续判断的关键参数。

4. 实操过程:从零搭起一套可用的BrewUI

4.1 开发环境与部署方案

整个BrewUI项目我用了Docker Compose做本地开发和部署编排,这也是我最推荐的方案。开发环境和生产环境保持一致的容器编排,可以省掉大量环境不一致带来的麻烦。建议的目录结构如下:

brewui/ ├── backend/ │ ├── cmd/ │ ├── internal/ │ ├── go.mod │ └── Dockerfile ├── frontend/ │ ├── src/ │ ├── package.json │ └── Dockerfile ├── deploy/ │ ├── docker-compose.yml │ ├── nginx.conf │ └── .env └── data/ └── postgres/

Docker Compose编排里包含四个服务:前端Nginx容器、后端Go容器、PostgreSQL容器、Redis容器。后端容器里同时开启MQTT broker子进程,用systemd管理生命周期,确保温度采集链路和Web服务同时可用。生产环境部署在NAS或者小型Linux服务器上,总内存要求不超过4GB,对于大多数家庭设备来说完全没有压力。

编排文件的关键部分:

version: '3.8' services: backend: build: ../backend ports: - "8080:8080" environment: - DB_HOST=postgres - REDIS_HOST=redis - MQTT_BROKER_PORT=1883 depends_on: - postgres - redis postgres: image: postgres:16-alpine volumes: - ../data/postgres:/var/lib/postgresql/data environment: - POSTGRES_DB=brewui - POSTGRES_USER=brewui - POSTGRES_PASSWORD=change_me redis: image: redis:7-alpine

4.2 数据库表设计与关键SQL

数据库设计这块,我花了不少时间建模,核心表包括用户表、设备表、配方表、配方版本表、批次表、批次阶段记录表、传感器数据表。这里我只挑最关键的三张表展开。

配方表和配方版本表采用一对多的关系,一个配方可以对应多个版本。版本表里包含了配方的完整快照,包括麦芽列表、酒花列表、酵母信息、糖化参数、发酵参数和计算得到的预估浓度与苦度值。快照式存储是我刻意选择的方案——如果只存修改差异,回溯老版本时需要反向计算,既费时又容易出错;快照方式虽然占用空间多一点,但换来的是百分之百可靠的版本回溯。

批次表关联配方版本,同时记录设备ID、酿造日期、实际的初始比重、最终比重、发酵温度区间、装瓶数量等字段。酿造过程中产生的大量阶段测量数据单独存放在批次测量记录表里,每一条记录都包含时间戳、阶段标识、测量类型和数值。

传感器数据表采用按时间分区的策略,每天一个分区,查询某段时期的曲线时只扫描对应分区,性能好得多。实测下来,即使积累了超过一百万条温度记录,按分区查询的响应时间依然能保持在100毫秒以内。

4.3 前端核心页面与交互逻辑

前端页面我重点打磨了三个视图:配方编辑器、批次工作台、数据统计面板。

配方编辑器的交互设计目标是"所见即所得"。左侧是原料清单,右侧是实时计算面板,每次增删原料或修改参数,右侧的预估浓度、苦度值、色度立即刷新。这个实时反馈机制极大降低了配方设计的试错成本,传统做法是改完所有参数再统一计算,看到结果后如果不符合预期又得从头调整;实时计算把整个设计过程变成了即时调参。

批次工作台是酿造现场的主界面,按阶段展示当前批次的进度和参数。顶部是阶段进度条,中间是当前阶段的参数表单和实时测量数据,底部是历史测量记录的时间线。发酵阶段时,工作台会展示温度曲线和比重曲线,两条曲线放在同一张图上,可以直观看出温度变化对照比重变化的影响关系。这个联动视图对诊断发酵异常非常有帮助,比如温度骤降导致发酵迟滞,在图上会表现为温度曲线下跌的同时比重曲线趋于平缓。

数据统计面板聚合了所有批次的历史数据,支持按配方、酵母、麦芽品牌等维度筛选对比。最实用的是"批次对比"功能,可以把三到五个批次放在同一张图上对比温度曲线、比重曲线和最终评价,方便复盘哪些调整带来了实际改善。

5. 我踩过的坑:BrewUI实战问题排查

5.1 温度传感器数据漂移问题

第一次接入DS18B20传感器时,我遇到了非常头疼的数据漂移问题。温度显示少量波动时还正常,但连续运行两天后,读数会逐渐偏离实际温度,最大偏差达到了3摄氏度。排查过程花了两天,最后定位到两个根因。

第一个根因是传感器供电不稳定。单片机通过USB口供电时,电流波动会导致DS18B20内部电压基准漂移,进而影响温度转换精度。解决方法是给传感器单独使用稳压模块供电,隔离数字电路和模拟电路的供电回路。

第二个根因是数据线受到的电磁干扰。传感器线缆和220V电源线捆在一起走线时,50Hz的工频干扰会叠加到信号线上,导致偶尔出现跳变和读数偏移。把传感器线缆和电源线分开走线,并在信号线外包了一层屏蔽层做好接地之后,读数稳定在正负0.3摄氏度以内。

5.2 前端实时数据卡顿

温度监控页面上线初期,WebSocket推送频率一旦超过每秒一次,页面的温度曲线就会出现明显卡顿,尤其当历史数据加载完成后,交互响应变得迟钝。排查后发现主要瓶颈在浏览器DOM更新频率上:每次收到传感器数据就重新绘制整条温度曲线,而曲线包含了一千多个点,重绘开销太大。

解决办法是把曲线重绘改成节流模式,每3秒最多重绘一次,数据点先缓存在内存数组中,重绘时一次性追加。同时开启了Canvas accelerator加速,曲线绘制性能提升了约五倍。另外对历史数据做了降采样处理,展示一分钟内的曲线时用全量数据,展示一天内的曲线时每隔30个点取一个代表点,这样既保证了细节精度,又不会让浏览器崩溃。

5.3 MQTT消息重放导致的数据重复

MQTT broker在断线重连后偶尔会重发旧消息,导致温度数据出现重复记录。这个问题在传感器端和broker端都有可能发生:传感器断网后本地积累的数据重新发送,broker在恢复会话后从最后确认的消息位置继续投递。最终我在消息消费端做了幂等处理,判断依据是传感器ID加时间戳,如果同一传感器在同一时间戳已有记录,直接丢弃新到达的重复消息。

5.4 数据库连接被耗尽

酿酒旺季时,多个批次同时运行,温度采集和设备状态检查导致数据库连接数峰值飙升,出现过几次"too many connections"错误。排查后发现连接池配置默认的最大连接数是100,应用本身并不需要这么高的并发。把连接池最大值调低到30,同时开启了连接复用和空闲连接回收,问题彻底解决。这件事给我的经验是:连接池配置不是越大越好,设置合理的上限反而能避免雪崩,关键是让监控数据告诉你合理的阈值在哪里。

6. 常见问题速查表

问题现象可能原因排查思路与解决方案
温度读数整体偏高传感器探头未完全浸没确认探头位置处于液体中心,避免接触容器壁
温度曲线出现尖刺电磁干扰或供电不稳分离信号线与电源线布线,检查稳压模块
浓度计算值与实测偏差大出糖效率系数设置不当用实测数据反推效率系数,更新至配方配置
批次无法进入下一阶段必填参数缺失查看阶段校验提示,补全记录后再试
WebSocket频繁断开网络不稳定或Nginx超时调整Nginx的proxy_read_timeout和心跳间隔
发酵曲线长时间无更新传感器离线或消息堆积检查传感器网络连接,查看broker消息队列长度
前端页面加载缓慢历史数据量过大开启列表分页和图表降采样,数据按批次隔离

7. 后续扩展方向与真实体会

BrewUI目前的版本已经在我自己的酿造工作室跑了二十多个批次,稳定性达到预期,但这只是起点。后续计划加入移动端深度适配的PWA功能,让手机在锁屏状态下也能接收发酵报警通知;另外考虑实现配方分享社区,让用户之间可以交换和评估配方,把个人的配方库变成群体的知识库。

还有几个待优化的方向:自动生成批次报告,用PDF或HTML格式输出一份完整的酿酒记录,可以直接分享给朋友或者存档;增加AI辅助的配方推荐,基于已有的批次数据和用户评分,推荐口感风格相似的配方配方变体;接入更多主流传感器设备,降低硬件门槛。

最后分享几个我个人的使用习惯,希望能帮你更快上手BrewUI。第一,每次批次结束后,务必花两分钟填写最终评价和口感描述,这是后续配方迭代最宝贵的参考数据。第二,不要同时运行太多批次,BrewUI虽然后台并发能力足够强,但批次太多反而会让你的注意力分散,降低每次酿造的质量控制水平。第三,定期备份PostgreSQL数据库,虽然服务器一般不会出事,但数据是无价的——我自己的备份策略是每天凌晨自动导出一次,同步到另一个存储设备,同时保留最近三十天的备份文件。

BrewUI这个项目的价值,不只是把酿造记录搬到了电脑上。它真正改变了我的酿酒习惯——从凭感觉调整方案变成看数据做决策,从碎片化记录变成完整可追溯的知识体系。如果你也在认真对待每一次酿造,不妨试着用类似工具把自己的工艺沉淀下来。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询