Foundit架构解析
TL;DR
基于项目源代码的架构拆解——Foundit 为什么比传统博客/CMS 更聪明、更安全、更"被看见"
基于项目源代码的架构拆解——Foundit 为什么比传统博客/CMS 更聪明、更安全、更"被看见"

本文基于项目源码撰写。该项目已从 Cloudflare Workers + Supabase 迁移至国内腾讯云服务器自托管:Nginx 反向代理 + Nuxt SSR(Node)+ 本地 PostgreSQL + 本地文件存储,身份服务由 Srces Auth 提供。
如果你曾经搭过个人网站、技术博客,或者公司内容站,大概率踩过这些坑:文章发出去搜索引擎半年没收录;后台登录形同虚设,改个 URL 就能绕过;服务器月月烧钱;换台手机排版就崩了。
Foundit 这个项目,正是针对这些"老毛病"给出的一个近乎教科书式的答案。它不是一个臃肿的系统,而是一套用现代工具链拼起来的、克制而精密的内容站。下面我们用拆解一台精密仪器的眼光,看看它的内部构造。
一、它到底是什么?
用一句话概括:
Foundit 是一个部署在腾讯云服务器上、基于 Nuxt(SSR)、本地 PostgreSQL(数据库)+ 本地文件存储(媒体)以及 Srces Auth(统一登录)的科技内容知识站。
它把内容分成四种形态——文章、产品、想法、专题,对外提供公开阅读(首页、列表、详情、搜索、RSS、Sitemap),对内提供一个由管理员权限保护的内容后台。
它的技术栈可以用"五个方面军"来理解:
这张图里藏着 Foundit 的第一个聪明之处:浏览器永远不直接碰数据库钥匙。所有写入都要经过 Nuxt 服务端这一道"门房",而"门房"只认经过密码学签名的令牌。整条链路(Nginx、Node、PostgreSQL、磁盘)都跑在同一台腾讯云 CVM 的内网回环上,只有 Nginx 监听公网 443,数据库与 Node 进程绝不暴露在公网。
如果把镜头再拉近一点,按"分层"的视角看,各个组件的上下游关系会更清晰——公开读取和管理员写入走的是两条泾渭分明的通道,最终都汇聚到 PostgreSQL,但沿途经过的"安检"完全不同:
注意左右两侧的对称:左边"公开访问者"只能通过服务端过滤后的只读通道拿到已发布内容;右边"管理员"必须先过 Srces Auth 的 JWT 验签、再由服务端持数据库连接串才能写入,并且每一次写入都会留下审计记录。
二、目录结构:像图书馆一样井井有条
一个项目好不好维护,先看它的"房间怎么分"。Foundit 的目录非常符合直觉:
| 目录 / 文件 | 职责 | 科普类比 |
|---|---|---|
pages/ |
19 个页面(前台 + 后台) | 对外开放的"展厅"和内部的"办公室" |
components/ |
7 个可复用组件 | 标准化的"家具":列表、轮播、编辑器 |
composables/ |
3 个组合式逻辑(认证、图片压缩、主题) | 可插拔的"功能模块" |
server/api/ |
公共接口 + 后台接口 | 对外的"服务窗口" |
server/utils/ |
数据访问层 + 鉴权 + 审计 + 媒体存储 | 后厨:备菜、安检、记账、储物 |
server/routes/ |
robots.txt / sitemap.xml / rss.xml / llms.txt |
给搜索引擎的"地图和告示" |
database/ |
schema.sql + migrations/*.sql |
仓库的"建筑图纸"与"加建记录" |
layouts/ |
前台布局 + 后台布局 | 两套"装修风格"但同源 |
config/、types/、utils/ |
配置、类型、纯函数工具 | 字典和工具箱 |
scripts/ |
一键部署 / 升级 / 数据迁移脚本 | 标准化的"施工手册" |
最值得称道的一点:公共接口(/api/content)与后台接口(/api/admin/*)严格分离。前者的数据访问层叫 content-repository,后者叫 admin-repository。
三、六大优点与特性
1. 生来就被搜索引擎"看得懂"——SSR + SEO + GEO
很多现代网站为了酷炫,正文靠 JavaScript 在浏览器里现拉现渲染。结果就是:关掉 JS,页面一片空白;搜索引擎爬虫看不懂;AI 问答工具也抓不到。
Foundit 反其道而行。它用 SSR(服务端渲染),用户或爬虫拿到的就是一份完整的 HTML 正文。项目里还专门做了三件事:
- 结构化数据(JSON-LD):每篇文章/产品页都输出机器可读的
Article/SoftwareApplication标签,相当于给内容贴了"身份证",方便 Google、Bing 以及各类 AI 准确理解。 - Sitemap + RSS + robots.txt + llms.txt:全部由服务端动态生成,内容一发布就自动更新"目录"。
- GEO(生成式引擎优化):专门为"被 AI 引用"做了设计——首屏直出核心结论、事实与观点分开、标注作者与来源时间、提供参考资料链接。
那么一次"打开文章"的请求,在幕后到底经历了什么?下面这张时序图,把从浏览器发起请求,到 Nginx 反向代理、服务端拉数据、Markdown 渲染、注入 JSON-LD,最后吐出完整 HTML 的全过程摊开看:
关键在于:真正决定"正文长什么样"的那一步(渲染 + 注入结构化数据)发生在服务端,而不是浏览器。所以无论是搜索引擎爬虫、AI 抓取器,还是关掉了 JS 的读者,拿到的都是同一份完整、可读、带"身份证"的 HTML。
2. 多层安全防线——"隐藏菜单"骗不了人
很多 CMS 的"权限"只是前端把按钮藏起来。Foundit 的态度是:前端隐藏只是体验,真正的安全必须发生在服务端。
它的防线是这样的:
- 统一身份(OIDC + PKCE):登录走标准的授权码 + PKCE 流程,不存客户端密钥。
- 密码学令牌(RS256 JWT):服务端用
jose库 + 远程 JWKS 公钥,逐条校验签名算法、签发者(issuer)、接收方(audience)、过期时间,并确认角色含admin。 - 服务端兜底:每个
/api/admin/*都调用同一个requireAdmin,前端无论怎么改都绕不过去。 - 服务端数据访问层强制过滤:公开读取只返回
status='published'的内容,草稿、待审、归档天然不可见;数据库凭据(NUXT_DATABASE_URL)只在服务端环境变量中,不存在可被公开访问的数据库角色——没有任何一个公网入口能直接触达数据库。 - 密钥隔离:高权限的数据库连接串与
adminSessionSecret只存在于服务器环境变量,绝不进前端产物。
具体到"登录"这件事,Foundit 用了一套巧妙的双令牌机制:管理员先从 Srces Auth 拿到一枚有效期仅 10 分钟的 RS256 令牌(用于向服务端证明身份),服务端验签通过后,再签发一枚 8 小时的 HttpOnly 会话 Cookie(免去每次都携带外部令牌)。整个握手过程如下:
这里有两个容易被忽略的细节:其一,本地会话 Cookie 的 path 被限定为 /api/admin,意味着它只在后台请求时才会被发送,不会泄漏到普通页面;其二,无论前端如何伪造,服务端 requireAdmin 都会重新验签并检查 admin 角色——前端隐藏菜单,永远绕不过这道服务端的门。
一句话总结它的安全哲学:“永远不要相信浏览器送来的任何东西。”
3. 一套设计语言,前后台"长得很像"
Foundit 附带了一份极其详尽的 UI 设计规范(40 多节)。它的核心只有几个字:克制、安静、留白、内容优先。
- 色彩只有黑、白、浅灰三色体系;
- 视觉层级靠字体和间距建立,而不是靠色块和阴影;
- 前后台共用同一套字体、按钮、表单风格,后台不再是"花花绿绿的 SaaS 仪表盘";
- 连动效都限制时长(150–220ms),禁止"为了高级感而高级感"。
这种设计的好处是长期可读、跨设备一致、维护成本低。它像一本排版考究的书,而不是一面喧闹的广告墙。
4. 智能缓存:既快又不会"显示旧文章"
Foundit 的缓存是两层协作的:
- Nuxt Nitro
routeRules:在应用层把页面缓存策略写得很细(见下表),基于 SWR(Stale-While-Revalidate)。 - Nginx 静态缓存:构建产物
_nuxt/静态资源设expires 1y, immutable并关闭访问日志;上传的媒体文件/uploads/设expires 30d, public并开启 gzip——这些静态内容由 Nginx 直接吐出,根本不进 Node 进程。
| 页面 | 缓存策略(Nitro routeRules) | Nginx 静态层 |
|---|---|---|
| 首页 | SWR 5 分钟 | — |
| 文章 / 产品 / 专题详情 | SWR 1 小时 | — |
/_nuxt/ 静态资源 |
— | 1y immutable(直出,不落 Node) |
上传媒体 /uploads/ |
— | 30d public + gzip(直出) |
| 登录回调 / 后台 / 后台接口 | no-store(绝不缓存) |
反代透传,带 noindex 头 |
SWR(Stale-While-Revalidate)是个聪明机制:先立刻把缓存的老页面给用户(快),同时后台悄悄刷新(新)。而涉及认证和敏感数据的页面,则坚决不缓存,避免把别人的后台响应留在节点上;/auth/**、/admin/**、/api/admin/** 还会被打上 x-robots-tag: noindex, nofollow 防止被搜索引擎收录。
5. 云服务器部署:数据主权与成本可控
Foundit 自2026年8月1日起整体迁移至一台腾讯云 CVM(云服务器),:
互联网 ── HTTPS :443 ── Nginx ── Nuxt SSR(Node)── PostgreSQL
└── /uploads/ → 服务器本地磁盘
这带来几个实打实的好处:
- 数据留在国内:数据库与媒体文件都在腾讯云,访问国内访客延迟低,也更符合数据驻留与合规要求;不再依赖海外第三方 SaaS。
- 没有供应商锁定:PostgreSQL 是标准关系型数据库,本地磁盘就是文件,哪天要迁走,导出 SQL + 打包
/uploads/即可,不绑定 Supabase 专有能力。 - 成本可预期:一台按量或包年 CVM 的账单清清楚楚,不存在"请求数暴涨导致边缘函数账单失控"的风险。
- 证书与域名可控:TLS 证书直接由腾讯云 SSL 证书控制台下载 Nginx 格式部署,域名走自有 DNS。
这对个人创作者尤其友好:运维负担被一键脚本压到了最低——
scripts/setup-foundit-windows.ps1/setup-nginx.ps1把装环境、建库、构建、注册开机自启服务、配置 Nginx 与防火墙全部标准化、可重复执行;代码升级只需重新跑一遍脚本。
代价也要说清楚:它不再是"无限扩展的边缘网络"——单台服务器是单点(SPOF),需要自行负责系统更新、监控与扩容(垂直升配,或在前面加负载均衡 + 多台)。但内容站本就是"读多写少",单台 2–4 核 CVM + Nginx 足以支撑相当大的流量。
6. 数据模型:为"生长"而设计
数据库 schema 不是拍脑袋写的。它用枚举约束内容类型与状态(draft/pending_review/published/archived),用 jsonb 存产品截图与链接,用 GIN 索引支持全文搜索,还预留了 revisions(修订记录)、audit_logs(审计日志)、auth_users(用户映射)等"未来扩展位"。媒体表 media 的 bucket 字段现在固定为 'local',表示文件落在服务器本地磁盘(区别于旧 Supabase 的 public-media / private-files)。
把这些表之间的关系画出来,就能看到这套"地基"的全貌——内容表居于核心,分类/标签/专题围绕它展开,而修订、审计、用户映射则像预埋的钢筋,静静等待未来的功能生长上去:
这意味着:今天它是个博客,明天它想加评论、加多作者、加付费墙,地基已经留好了。
四、Foundit和传统方案对比
| 维度 | 传统 WordPress / 自建后台 | 普通 SPA(如纯前端框架) | Foundit |
|---|---|---|---|
| 搜索引擎可见性 | 依赖插件,易出坑 | 差(JS 渲染) | 原生 SSR + 结构化数据 |
| 安全模型 | 插件质量参差 | 前端路由即"伪权限" | 服务端 JWT 校验 + 数据层状态过滤双层 |
| 运维成本 | 需常驻服务器 + 数据库 | 静态托管但功能受限 | 单台云服务器自托管,运维可控且合规 |
| 内容形态 | 单一"文章" | 自己造轮子 | 文章/产品/想法/专题原生支持 |
| 设计一致性 | 主题市场鱼龙混杂 | 看团队水平 | 统一设计系统约束 |
| AI 可发现性 | 基本没考虑 | 基本没考虑 | 内建 GEO 优化 |
| 数据驻留与合规 | 取决于主机商,常在海外 | 取决于托管地 | 数据库与媒体均在国内腾讯云,合规可控 |
用一个比喻:传统方案像"自己盖房子,水电自己接,锁自己装";Foundit 像"采用现代装配式建筑——结构、安防、节能标准都是出厂即合规的",只不过现在这栋房子稳稳地落在了自家(腾讯云)的地基上。
最后
Foundit 给我们的最大启发是:好的工程不是堆功能,而是把"正确的事"变成默认。 内容该被看见,所以默认 SSR;权限该被守住,所以默认服务端校验;数据该留在国内、成本该被压低,所以默认托管在自有云服务器。
它像一台调校得当的相机——没有花哨的灯,但每一次按下快门,都能稳定地、清晰地把"内容"拍下来,递到读者和机器面前。
“页面不主动争夺注意力,而是让内容自然地被看见。” —— 这正是 Foundit 设计系统里最动人的一句话,也是它整个架构的底层逻辑。



