# cube Fam 的小 app 平台。 ## 是什么 `cube` 是一个跑在 **`famzheng.me` 节点**(hostname `famzheng.com`,单节点 k3s + traefik + gitea,公网 IP `178.104.186.206`)上的小 app 平台,专门收纳 Fam 自己写的一堆小工具/玩具 web app。底层硬件、k3s、Gitea、act_runner 等基础设施详见 `~/.claude/memory/infra.md`。 主要任务:把目前散落在 `oci.euphon.net`(Oracle Cloud ARM VM)上**值得留下**的 Fam 个人小 app 迁过来。oci 主机本身不退役,留给 Hera 同学继续用。 设计目标:反 Karpathy "web app 像拼宜家家具" 的困境 —— 全部自有基础设施,**零跨 dashboard 配置**,新 app 上线压缩到 5 分钟内。 --- ## 平台约定 > 这是 cube 上所有 app 的"宪法",所有 app 必须遵守,破例必须改这份文档并经 Fam 拍板。 ### 仓库结构:monorepo + cargo workspace 整个 cube 是**一个 git 仓库** `fam/cube`,cargo workspace 模式。 ``` cube/ ├── Cargo.toml # workspace manifest ├── crates/ │ └── cube-core/ # 共享样板:base router / healthz / tracing / shutdown / config ├── apps/ │ ├── cube/ # app #0 = cube.famzheng.me 入口门户 │ │ ├── Cargo.toml # path 依赖 cube-core │ │ ├── src/main.rs │ │ ├── frontend/ # vite + vue 3 + ts │ │ ├── Dockerfile │ │ └── k8s/ # deployment / service / ingress │ ├── portfolio/ │ ├── repo-vis/ │ └── ... ├── doc/ └── .gitea/workflows/ # CI;按 path 触发,per-app build/deploy ``` `cube-core` 是 **path 依赖**(`cube-core = { path = "../../crates/cube-core" }`),不发布、不打 tag、不走 git 依赖。改 `cube-core` 时所有 app 一起 rebuild,monorepo 的整个意义就在于"一次重构,全员同步"。 ### 部署目标 单一目标:famzheng.me 节点的 k3s(`kubectl context default`),不双轨。 - 每 app 一个 k8s namespace,ns 名 = `cube-`(如 `cube-cube` / `cube-portfolio`),便于跟其他 ns 隔离 + 一眼可见归属 - traefik ingress + 通配符 LE 证书自动签 ### 域名 - `.famzheng.me`,wildcard A 记录已配,**零 DNS 操作** - 不嵌 `cube` 子域(冲突检查 = 起新 ingress 时 traefik 自然报错,不需要额外心智) - 旧域名(如 `portfolio.oci.euphon.net`)让 oci ingress 兜底 308 redirect 到新地址,过渡期后下掉 ### 后端:Rust + Axum 每个 app 是 workspace 里的一个 bin crate,单 axum 服务。 `cube-core` 提供: - `/healthz` router(200 = ok) - `ServeDir` 静态前端 fallback 到 `index.html`(SPA 路由兼容) - `tracing` 配 JSON stdout - SIGTERM graceful shutdown - env → struct 配置加载 业务 app 只写 `/api/*` 路由 + handler: ```rust let app = cube_core::base("dist") .nest("/api", api_routes()); cube_core::serve(app).await ``` ### 前端:Vite + Vue 3 - 默认栈:**Vite + Vue 3 + TypeScript + Pinia + Vue Router** - 选 Vue 而不是 Svelte 的原因:AI(Claude / GPT)写 Vue 3 `