Maybe 开源个人理财应用:本地开发环境与 Docker 自托管全解析
Maybe 是一款可直接运行的开源自托管个人理财应用,基于 Rails 7.2 + Hotwire 构建。本文围绕仓库根目录的 README 展开,覆盖其全部核心实操内容——Docker 自托管部署、本地开发环境搭建、演示数据加载与登录方式,并结合 compose.example.yml、Dockerfile、.env.example 与源码配置深入解析每个环境变量与部署细节的来龙去脉。读完本文,你可以独立完成 Maybe 的本地开发启动,也可以在服务器上部署一套可用的自托管实例并知道如何更新与排错。
需要说明的一点:README 中明确标注该仓库已不再积极维护(官方最终版本为 v0.6.0),因此本文所有操作均以当前仓库的实际文件内容为准确认,读者在引用时应留意这一点。
项目定位:一个可直接运行的理财应用
README 对 Maybe 的定位非常直接:它是一个 fully working 的个人理财应用,既支持 Docker 自托管,也面向贡献者提供完整的本地开发流程。从 Gemfile 可以看到它的技术栈:Rails ~> 7.2.2、PostgreSQL(pg 驱动)、Redis、Sidekiq 后台任务、Puma 服务器、Importmap + Turbo + Stimulus 的前端组合、ViewComponent 与 Lookbook 组件库,以及 Doorkeeper OAuth 与 Rack::Attack 用于外部 API 的安全控制。
应用通过一个 app_mode 配置区分两种运行形态,其定义在 config/application.rb 中:
config.app_mode = (ENV["SELF_HOSTED"] == "true" || ENV["SELF_HOSTING_ENABLED"] == "true" ? "self_hosted" : "managed").inquiry
即当环境变量 SELF_HOSTED=true 时,应用以 self_hosted 模式运行(开启自托管特有功能,如设置页内配置 Synth API Key);否则为 managed 模式(官方托管形态)。这是理解后续所有环境变量的关键开关。
Docker 自托管部署(推荐方式)
自托管用户应直接参考 docs/hosting/docker.md 这份官方指南,其完整流程如下。
前置:安装 Docker
- 按官方文档安装 Docker Engine 并启动 Docker 服务;
- 用以下命令验证安装:
# 若 Docker 配置正确,此命令将成功
docker run hello-world
创建应用目录并获取示例 Compose 文件
# 创建存放 Docker 文件的目录(名称可自定义)
mkdir -p ~/docker-apps/maybe
# 切换到该目录
cd ~/docker-apps/maybe
# 从 Maybe 仓库下载示例 compose 文件
curl -o compose.yml https://raw.githubusercontent.com/maybe-finance/maybe/main/compose.example.yml
执行后当前目录中应只有一个 compose.yml。该文件即本仓库中的 compose.example.yml,下文会逐段解读其结构。
(可选)配置安全环境变量
默认情况下示例 Compose 文件可以零配置运行;但如果实例运行在局域网之外,官方强烈建议创建 .env 文件以覆盖默认值:
touch .env
应用要求 SECRET_KEY_BASE 这一环境变量(Rails 用于加密 session 等凭据),可用以下任一方式生成:
openssl rand -hex 64
# 或不依赖 openssl 的替代方案:
head -c 64 /dev/urandom | od -An -tx1 | tr -d ' \n' && echo
随后在 .env 中填入:
SECRET_KEY_BASE="上一步生成的字符串"
POSTGRES_PASSWORD="你期望的数据库密码"
启动与后台运行
docker compose up # 拉取官方镜像并启动,可在终端看到日志
docker compose up -d # 用 Ctrl+C 停止前台进程后,以 detached 模式后台运行
docker compose ls # 验证 compose 项目正在运行
一切正常时,访问 http://localhost:3000 即可看到 Maybe 登录页。首次使用需在登录页点击 "create your account",输入邮箱与密码完成注册——自托管模式下没有预置账号,与本地开发模式的种子账号(见下文)不同。
更新与版本钉住
自托管实例的更新机制完全依赖 Compose 文件中的 GHCR 镜像标签。官方推荐两个标签:
ghcr.io/maybe-finance/maybe:latest(最新提交)ghcr.io/maybe-finance/maybe:stable(最新 release)
实例默认不会自动更新。更新命令序列为:
cd ~/docker-apps/maybe
docker compose pull # 从 GHCR 拉取新镜像
docker compose build # 使用更新重建应用
docker compose up --no-deps -d web worker # 以最新版本重启应用
若希望钉住特定版本,只需编辑 compose.yml 中的 image: 字段(例如改为 ...:stable),然后重新执行 pull/build/up 序列即可。
排错:ActiveRecord::DatabaseConnectionError
官方指南给出了一个典型场景:首次启动时若 Postgres 卷被之前失败/不同配置的尝试初始化过(即卷内已存在不同的默认角色),会出现数据库连接错误。解决办法是重置数据库——注意这会删除 Maybe 库中的全部数据:
docker compose down
docker volume rm maybe_postgres-data # 数据库挂载卷的名称
docker compose up
docker exec -it maybe-postgres-1 psql -U maybe -d maybe_production -c "SELECT 1;" # 验证修复
解读示例 Compose 文件:四个服务如何协作
compose.example.yml 定义了完整的生产形态拓扑,值得逐段理解:
- web:应用镜像(
ghcr.io/maybe-finance/maybe:latest),映射3000:3000端口,将app-storage卷挂载到/rails/storage(Active Storage 文件),restart: unless-stopped,并依赖 db 与 redis 健康后才启动; - worker:同一镜像以
command: bundle exec sidekiq覆盖默认命令,专职处理后台任务(同步、导入、AI 聊天等异步作业); - db:
postgres:16,数据持久化在postgres-data卷,带pg_isready健康检查; - redis:
redis:latest,持久化在redis-data卷,带redis-cli ping健康检查。
所有服务共享一个 maybe_net bridge 网络,并通过 YAML 锚点 x-db-env / x-rails-env 复用数据库与应用环境变量。关键连接参数为 DB_HOST: db、DB_PORT: 5432、REDIS_URL: redis://redis:6379/1(注意 Sidekiq 使用 Redis 1 号库)。
环境变量层面有几个值得注意的点:
SECRET_KEY_BASE在示例中有一个内置默认值,仅适合本地网络;对外暴露时必须按上文生成自己的密钥;SELF_HOSTED: "true"硬编码为 true,即该文件天生面向自托管场景(与 config/application.rb 中的app_mode判断呼应);RAILS_FORCE_SSL/RAILS_ASSUME_SSL默认为"false",自建反向代理 + TLS 时需自行调整;OPENAI_ACCESS_TOKEN为可选透传变量,文件内注释明确提醒:启用 OpenAI 后,应用内 AI 功能(聊天、规则)会产生费用,务必先在账户中设置消费上限。
镜像内部:多阶段 Dockerfile 与安全运行
Dockerfile 采用标准的多阶段构建,可作为理解生产镜像的参考:
- build 阶段:基于
ruby:3.4.4-slim,安装构建依赖后bundle install(BUNDLE_DEPLOYMENT=1),用SECRET_KEY_BASE_DUMMY=1预编译资产(./bin/rails assets:precompile),避免构建时要求真实的密钥; - 运行阶段:仅拷贝构建产物与应用代码,创建 uid/gid 均为 1000 的非 root
rails用户并切换运行; - 入口:
ENTRYPOINT ["/rails/bin/docker-entrypoint"]负责准备数据库(首次启动执行迁移等),默认命令为./bin/rails server,这也是 Compose 中 worker 服务能通过command覆盖来运行 Sidekiq 的原因; - 镜像暴露 3000 端口,Ruby 版本由
ARG RUBY_VERSION=3.4.4锁定,要求与.ruby-version及 Gemfile 保持一致。
本地开发环境搭建(面向贡献者)
README 特别强调:如果你的目标是自托管,请停止阅读本节、转去 Docker 指南;以下内容是贡献者开发流程。
环境要求
- Ruby 版本以
.ruby-version文件为准,当前仓库锁定为 3.4.4(与 Dockerfile 中的RUBY_VERSION一致); - PostgreSQL 9.3 以上,官方建议使用最新稳定版。
基本启动命令
cd maybe
cp .env.local.example .env.local
bin/setup
bin/dev
# 可选:加载演示数据
rake demo_data:default
bin/setup完成依赖安装与数据库准备(对应 CLAUDE.md 中记录的bin/setup说明:安装依赖、准备数据库);bin/dev依据 Procfile.dev 同时拉起三个进程,这是开发期命令组合的关键:
web: bundle exec ${DEBUG:+rdbg -O -n -c --} bin/rails server -b 0.0.0.0
css: bundle exec bin/rails tailwindcss:watch 2>/dev/null
worker: bundle exec sidekiq
即 Rails 服务器(绑定 0.0.0.0,且 DEBUG 时自动挂上 debug.rb 断点器)、Tailwind CSS 监听、以及一个本地 Sidekiq worker——本地开发与生产镜像在「web + worker 分离」这一点上是同构的。
启动后访问 http://localhost:3000,可用以下凭据登录(README 注明由 DB seed 生成):
- 邮箱:
user@maybe.local - 密码:
password
环境变量模板
开发环境模板 .env.local.example 只有两项,语义都很直接:
# 启用 / 禁用自托管功能
SELF_HOSTED=false
# 启用 Synth 市场数据(注意会消耗你的 API 额度)
SYNTH_API_KEY=yourapikeyhere
SELF_HOSTED=false 意味着本地开发默认走 managed 模式;若要在本地模拟自托管形态,将其改为 true 即可触发 config/application.rb 中的 app_mode 切换。完整的自托管变量清单在 .env.example 中,包含 SECRET_KEY_BASE(必需)、SYNTH_API_KEY(汇率与股票价格数据)、PORT(默认 3000,端口冲突时可改)、SMTP 系列变量(SMTP_ADDRESS / SMTP_PORT / SMTP_USERNAME / SMTP_PASSWORD / SMTP_TLS_ENABLED / EMAIL_SENDER,密码重置等邮件场景需要)、DB_HOST / DB_PORT / POSTGRES_USER / POSTGRES_PASSWORD、APP_DOMAIN(邮件链接生成的实例域名)、DISABLE_SSL,以及可选的 Active Record Encryption 密钥(rails db:encryption:init 可生成)。文件还列出了 Active Storage 的对象存储选项:默认磁盘存储,可选 Amazon S3(ACTIVE_STORAGE_SERVICE=amazon)或 Cloudflare R2(ACTIVE_STORAGE_SERVICE=cloudflare)。
演示数据生成器
rake demo_data:default 背后的实现在 lib/tasks/demo_data.rake,它其实提供了三档数据集:
| 任务 | 说明 |
|---|---|
rake demo_data:empty |
空的演示家庭(无任何财务数据,但已完成 onboarding) |
rake demo_data:new_user |
新用户演示家庭(未 onboarding、未订阅,用于调试新手引导流程) |
rake demo_data:default |
完整且拟真的数据集(默认任务) |
default 任务通过 Demo::Generator 生成数据,支持 SEED 环境变量传入随机种子以实现可复现的数据集;生成后还会自动执行一次校验,输出总条目数(期望区间 8k–12k)、交易类条目数(期望 500–1000)以及分类覆盖率(期望不低于 75%)。生成器实现见 app/models/demo/generator.rb,其中明确演示账号 user@maybe.local 即为该家庭创建的用户(create_family_and_users!("Demo Family", "user@maybe.local", onboarded: true, subscribed: true)),这与 README 给出的登录凭据互相印证。[db/seeds.rb](https://gitcode.com/GitHub_Trending/ma/maybe/blob/a90899668ff25bf24d5feb8100809642ce6192ee/db/seeds.rb?utm_source=gitcode_repo_files) 则负责加载 db/seeds/ 下的公共种子文件(如 OAuth 应用),并在开发环境提示运行 demo 数据命令。
日常开发命令速查
除 README 的命令外,仓库的 CLAUDE.md 还系统记录了贡献者的开发约定,与本地环境直接相关:
- 测试:
bin/rails test(全量)、bin/rails test:db(重置数据库)、bin/rails test:system(系统测试,耗时较长,谨慎使用)、bin/rails test test/models/account_test.rb:42(定位单条用例); - Lint 与安全:
bin/rubocop、npm run lint/npm run lint:fix/npm run format(Biome 配置见 biome.json)、bin/brakeman; - 数据库:
bin/rails db:prepare/db:migrate/db:rollback/db:seed; - 测试哲学:始终使用 Minitest + fixtures(禁止 RSpec/factories),fixtures 保持最小化,外部 API 用 VCR 录制回放(见
test/vcr_cassettes/)。
许可证与商标
README 末尾说明:Maybe 以 AGPLv3 协议分发(完整协议见 LICENSE),"Maybe" 是 Maybe Finance, Inc. 的商标。自托管、二次开发或对外提供服务时,请以该协议条款为准。
参考资料索引
| 文件 | 用途 |
|---|---|
| README | 项目入口:自托管指引与本地开发命令 |
| docs/hosting/docker.md | Docker 自托管完整指南(安装、配置、更新、排错) |
| compose.example.yml | 自托管示例编排文件(web/worker/db/redis 四服务) |
| Dockerfile | 生产镜像构建(多阶段、非 root、资产预编译) |
| .env.example | 自托管环境变量全量清单与说明 |
| .env.local.example | 本地开发环境变量模板 |
| Procfile.dev | 本地开发三进程启动定义 |
| CLAUDE.md | 开发命令、CI 流程与架构约定速查 |
| lib/tasks/demo_data.rake | 演示数据三档任务与自动校验 |
| app/models/demo/generator.rb | 演示数据生成器(可复现种子、账号创建) |
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00