Foundit架构解析

TL;DR

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

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

Foundit架构解析

本文基于项目源码撰写。该项目已从 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 的态度是:前端隐藏只是体验,真正的安全必须发生在服务端。

它的防线是这样的:

  1. 统一身份(OIDC + PKCE):登录走标准的授权码 + PKCE 流程,不存客户端密钥。
  2. 密码学令牌(RS256 JWT):服务端用 jose 库 + 远程 JWKS 公钥,逐条校验签名算法、签发者(issuer)、接收方(audience)、过期时间,并确认角色含 admin
  3. 服务端兜底:每个 /api/admin/* 都调用同一个 requireAdmin,前端无论怎么改都绕不过去。
  4. 服务端数据访问层强制过滤:公开读取只返回 status='published' 的内容,草稿、待审、归档天然不可见;数据库凭据(NUXT_DATABASE_URL)只在服务端环境变量中,不存在可被公开访问的数据库角色——没有任何一个公网入口能直接触达数据库。
  5. 密钥隔离:高权限的数据库连接串与 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(用户映射)等"未来扩展位"。媒体表 mediabucket 字段现在固定为 'local',表示文件落在服务器本地磁盘(区别于旧 Supabase 的 public-media / private-files)。

把这些表之间的关系画出来,就能看到这套"地基"的全貌——内容表居于核心,分类/标签/专题围绕它展开,而修订、审计、用户映射则像预埋的钢筋,静静等待未来的功能生长上去:

这意味着:今天它是个博客,明天它想加评论、加多作者、加付费墙,地基已经留好了。

四、Foundit和传统方案对比

维度 传统 WordPress / 自建后台 普通 SPA(如纯前端框架) Foundit
搜索引擎可见性 依赖插件,易出坑 差(JS 渲染) 原生 SSR + 结构化数据
安全模型 插件质量参差 前端路由即"伪权限" 服务端 JWT 校验 + 数据层状态过滤双层
运维成本 需常驻服务器 + 数据库 静态托管但功能受限 单台云服务器自托管,运维可控且合规
内容形态 单一"文章" 自己造轮子 文章/产品/想法/专题原生支持
设计一致性 主题市场鱼龙混杂 看团队水平 统一设计系统约束
AI 可发现性 基本没考虑 基本没考虑 内建 GEO 优化
数据驻留与合规 取决于主机商,常在海外 取决于托管地 数据库与媒体均在国内腾讯云,合规可控

用一个比喻:传统方案像"自己盖房子,水电自己接,锁自己装";Foundit 像"采用现代装配式建筑——结构、安防、节能标准都是出厂即合规的",只不过现在这栋房子稳稳地落在了自家(腾讯云)的地基上。

最后

Foundit 给我们的最大启发是:好的工程不是堆功能,而是把"正确的事"变成默认。 内容该被看见,所以默认 SSR;权限该被守住,所以默认服务端校验;数据该留在国内、成本该被压低,所以默认托管在自有云服务器。

它像一台调校得当的相机——没有花哨的灯,但每一次按下快门,都能稳定地、清晰地把"内容"拍下来,递到读者和机器面前。

“页面不主动争夺注意力,而是让内容自然地被看见。” —— 这正是 Foundit 设计系统里最动人的一句话,也是它整个架构的底层逻辑。

KEEP READING