从零构建现代化个人知识库:全栈TypeScript、Next.js与双链笔记实践
1. 项目概述从零到一构建一个现代化的个人知识管理工具最近在整理自己的笔记和项目资料时总是感觉现有的工具要么太重、要么太散要么就是数据被锁在某个平台里迁移起来特别麻烦。相信很多开发者、内容创作者或者终身学习者都有类似的痛点我们每天接触大量信息需要一个地方来系统性地沉淀、连接和复用这些知识。于是我决定自己动手打造一个符合我个人工作流的知识管理工具这就是EESIZ/woongaksi项目的由来。简单来说woongaksi是一个开源的、自托管的个人知识库与第二大脑系统。它的核心目标不是替代 Notion、Obsidian 这类成熟产品而是提供一个高度可定制、数据完全自主、且能与开发者现有技术栈无缝集成的解决方案。它特别适合那些对数据隐私有要求、喜欢折腾技术、或者希望将知识库深度集成到自己其他应用比如博客、项目文档、自动化工作流中的朋友。通过这个项目你不仅能获得一个得心应手的知识管理工具更能深入理解一个现代化 Web 应用从前端到后端再到数据存储与检索的完整构建过程。2. 核心架构设计与技术选型思路2.1 为什么选择全栈 JavaScript/TypeScript 技术栈在启动项目时技术栈的选择是首要决策。我最终确定了以TypeScript为核心的全栈 JavaScript 方案这背后有几点核心考量。首先是开发效率与一致性。对于一个由个人或小团队主导的项目使用同一种语言TypeScript来编写前端、后端甚至数据库操作逻辑能极大降低上下文切换的成本。团队成员或者未来的自己无需在 Python、Java、Go 和 JavaScript 之间反复横跳工具链如 ESLint、Prettier和包管理器pnpm可以统一配置代码风格和类型定义也能保持高度一致。TypeScript 提供的静态类型检查对于构建一个结构复杂、数据模型多样的知识库应用来说是预防低级错误、提升代码可维护性的利器。其次是生态系统的丰富性。Node.js 后端框架如 Fastify、NestJS、前端框架Next.js、Vue 3以及各种数据库驱动、工具库都拥有极其活跃的社区和成熟的解决方案。这意味着项目中遇到的绝大多数问题都能在社区找到经过验证的答案或现成的轮子。例如处理 Markdown 解析、实现实时搜索、构建 GraphQL API 等需求都有非常优秀的开源库可供选择。最后是部署与扩展的灵活性。基于 Node.js 的应用可以轻松部署在任何支持 Node 的环境从传统的 VPS 到云函数Serverless再到 Docker 容器都有成熟的方案。这对于希望将知识库私有化部署的用户来说门槛大大降低。注意技术选型没有绝对的“最佳”只有“最适合”。如果你的团队更熟悉 PythonDjango/Flask或 Go完全可以用它们来构建后端。woongaksi 项目的价值在于其设计理念和功能模块技术栈是实现它的手段可以根据实际情况替换。2.2 前端Next.js 与 React 生态的深度结合前端我选择了Next.js作为核心框架。这是一个基于 React 的元框架它为我们解决了几大痛点。第一服务端渲染SSR与静态生成SSG。知识库的很多页面比如一篇已经沉淀下来的技术笔记其内容在短时间内是不会变化的。使用 Next.js 的 SSG 功能可以在构建时就将这些页面预渲染为静态 HTML从而获得极快的首屏加载速度和更好的搜索引擎优化SEO效果。这对于希望将部分公开笔记作为技术博客分享的用户来说是一个巨大的优势。同时Next.js 也支持 SSR 和客户端渲染CSR我们可以根据页面的特性灵活选择渲染策略例如知识库的列表页用 SSR 保证内容可抓取而富文本编辑器页面则用 CSR 获得更流畅的交互体验。第二全栈能力与 API Routes。Next.js 内置了 API Routes 功能允许我们在同一个项目中编写后端 API 接口。这意味着对于 woongaksi 这样前后端紧密耦合的应用我们可以将一些简单的、仅服务于前端的业务逻辑如处理表单提交、调用第三方服务直接写在 API Routes 里无需维护一个完全独立的后端服务简化了项目结构。当然复杂的核心业务逻辑和数据库操作我仍然建议放在一个独立的后端服务中以实现更好的关注点分离。第三对现代开发体验的极致优化。Next.js 开箱即用地支持 TypeScript、ESLint、Fast Refresh热更新、文件系统路由等特性极大地提升了开发体验。其Image组件能自动优化图片Link组件能实现智能的客户端导航这些细节让构建高性能、用户体验良好的应用变得更加容易。在 UI 组件库方面我选择了shadcn/ui结合Tailwind CSS。shadcn/ui 并非一个传统的 npm 包而是一套可以复制粘贴到项目中的高质量、可访问的组件代码。这带来了无与伦比的定制自由度你可以直接修改组件源码来满足任何设计需求同时避免了传统 UI 库带来的包体积膨胀和样式冲突问题。Tailwind CSS 的实用类Utility-First理念则让编写响应式、符合设计系统的界面变得高效而直观。2.3 后端Fastify 与 Prisma 的强强联合后端框架我选择了Fastify。相比于更流行的 Express.jsFastify 在性能上有显著优势其基准测试显示吞吐量可以达到 Express 的两倍左右。对于知识库应用虽然可能不会面临极高的并发但追求高性能是一个良好的工程实践。Fastify 的插件架构非常出色通过插件可以模块化地组织路由、数据库连接、认证等逻辑代码结构清晰。其内置的 JSON Schema 验证能让我们在请求进入处理函数之前就完成数据校验既安全又高效。数据库操作层我使用了Prisma作为 ORM对象关系映射工具。Prisma 的核心优势在于其类型安全的数据库客户端和直观的数据模型定义语言。// schema.prisma 示例 model Article { id String id default(cuid()) title String content String db.Text slug String unique published Boolean default(false) createdAt DateTime default(now()) updatedAt DateTime updatedAt author User relation(fields: [authorId], references: [id]) authorId String tags Tag[] } model Tag { id String id default(cuid()) name String unique articles Article[] }如上所示我们用一个声明式的schema.prisma文件定义数据模型。Prisma 会根据这个文件生成完全类型安全的 TypeScript 客户端。这意味着当你查询数据库时编辑器会提供自动补全并且会检查你查询的字段、条件是否合法从根本上杜绝了因拼写错误或字段不存在导致的运行时错误。此外Prisma 的迁移工具prisma migrate dev也能优雅地管理数据库 schema 的变更。数据库本身我推荐使用PostgreSQL。它是一个功能强大的开源关系型数据库对 JSON 数据的支持也很好非常适合存储结构化和半结构化的知识数据。如果你希望更轻量SQLite 也是一个不错的选择Prisma 对两者都有很好的支持。2.4 数据存储与检索Markdown 与全文搜索知识库的核心内容是文本。我选择将文章的原始内容以Markdown格式存储。Markdown 语法简单直观既是写作的格式也能轻松转换为 HTML 用于展示。相比于富文本编辑器产生的复杂 HTML 或 JSONMarkdown 是纯文本版本控制如 Git友好数据迁移和备份也极其简单。然而当笔记数量成百上千后如何快速找到所需内容就成了关键。这就需要引入全文搜索能力。我采用了FlexSearch这个纯客户端的全文搜索引擎库。它的好处是无需部署额外的搜索服务如 Elasticsearch所有索引和搜索都在浏览器端完成响应速度极快且完全保护了隐私数据无需上传到服务器进行搜索。实现原理是在应用启动或笔记更新时后端 API 会将所有公开或用户有权访问的笔记的标题、摘要、纯文本内容以及对应的 ID 和 Slug 返回给前端。前端使用 FlexSearch 在内存中创建索引。当用户输入搜索词时FlexSearch 会瞬间返回匹配的文档 ID 列表前端再根据这些 ID 去获取完整的文档内容进行展示。对于个人或小团队规模的知识库这种方案在性能和复杂度之间取得了很好的平衡。实操心得客户端搜索的局限性在于索引数据量受限于浏览器内存。实测表明对于上万篇中等长度文章FlexSearch 依然能良好工作。但如果你的知识库体量巨大或者需要更复杂的搜索功能如分词优化、同义词、拼音搜索那么服务端搜索方案如 MeiliSearch、Typesense 或 PostgreSQL 自带的全文搜索是更合适的选择。在 woongaksi 中我预留了搜索后端的接口方便未来扩展。3. 核心功能模块的详细实现3.1 知识组织双链笔记与图谱可视化现代知识管理的核心思想是“连接优于分类”。woongaksi 实现了类似 Roam Research 和 Obsidian 的**双链Bi-directional Link**功能。具体实现如下链接语法在 Markdown 编辑器中使用[[文章标题]]的语法来创建内部链接。编辑器会实时解析这种语法并将其渲染为可点击的链接。链接提取与存储当一篇笔记被保存时后端会解析其 Markdown 内容使用正则表达式如/\[\[([^\]])\]\]/g提取出所有[[...]]中的目标文章标题。然后系统会在数据库中建立两张表之间的关系源文章-链接关系-目标文章。一个链接关系记录会存储源文章 ID、目标文章标题或 ID以及链接在文中的上下文。反链查询当你在浏览《如何理解 React Hooks》这篇文章时系统会查询数据库“有哪些文章链接到了当前这篇文章” 查询结果就是所谓的“反链Backlinks”。页面上会展示一个“反链”面板列出所有提及当前文章的其他笔记并附上上下文片段。这让你能清晰地看到知识的交汇点是产生新洞见的关键。图谱可视化基于文章节点和链接关系数据我们可以使用前端图形库如Cytoscape.js或Vis.js来绘制知识图谱。每个节点代表一篇文章每条边代表一个链接。图谱可以全局展示也可以只展示当前文章的局部关联。这个视觉化的网络能帮助你宏观把握知识结构发现隐藏的联系。技术细节图谱的数据通常通过一个专门的 API 端点提供该端点返回所有文章和链接的列表。前端收到数据后进行布局计算和渲染。为了性能考虑对于大型知识库可以考虑只可视化最近活跃的或重要的文章节点。3.2 编辑器体验基于 TipTap 的沉浸式写作编辑器是知识库的“门面”其体验至关重要。我选择了TipTap作为富文本编辑器的内核。它是一个基于 ProseMirror 构建的无头headless编辑器框架提供了极高的定制灵活性。为什么是 TipTap完全可控你可以决定编辑器拥有哪些功能加粗、斜体、标题、列表、代码块、表格、图片上传等以及这些功能如何表现。这避免了像一些现成编辑器那样带来大量不必要的代码和样式。与 Markdown 的友好交互TipTap 可以很好地处理 Markdown 的输入和输出。你可以实现“Markdown 快捷键”例如输入##加空格自动转换为二级标题也可以将编辑器内容实时导出为 Markdown 字符串进行存储。扩展生态社区提供了大量扩展如图片拖拽上传、表格操作、代码块高亮、任务列表、数学公式支持KaTeX等可以像搭积木一样为编辑器添加功能。出色的协同编辑潜力TipTap 底层基于 ProseMirror而 ProseMirror 是设计来支持协同编辑的。虽然 woongaksi 初期聚焦于个人使用但选择这个技术栈为未来可能的“多人协作编辑同一文档”功能铺平了道路。实现一个基础编辑器的步骤安装核心包tiptap/react,tiptap/starter-kit。创建一个 React 组件初始化 TipTap 编辑器实例配置所需的扩展Starter Kit 包含了常用格式。将编辑器实例与一个contentEditable的 DOM 元素绑定。实现双向绑定当编辑器内容变化时通过onUpdate回调获取 HTML 或 Markdown 内容更新 React 状态同时将外部传入的初始内容从数据库读取的 Markdown通过editor.commands.setContent()方法设置到编辑器中。在编辑器上方或周围构建工具栏工具栏按钮通过调用editor.chain().focus().toggleBold().run()这样的命令来影响选中的文本。3.3 用户认证与数据隔离既然是个人知识库数据安全隔离是必须的。woongaksi 实现了基于会话Session的认证系统。流程如下注册与登录用户通过表单提交邮箱和密码。后端使用加密库如bcrypt对密码进行加盐哈希处理然后将用户信息邮箱、哈希后的密码存入数据库。登录时比对哈希值。会话管理登录成功后后端生成一个唯一的会话 IDSession ID将其存储在数据库的sessions表中关联用户ID、过期时间等同时通过 HTTP Cookie 或 Bearer Token如 JWT的形式发送给前端。请求鉴权前端在后续请求中携带这个 Session IDCookie 自动携带Token 需放在 Authorization 头。后端中间件会拦截请求验证 Session 的有效性和是否过期并从 Session 中提取出当前登录的用户 ID (req.userId)。数据隔离这是最关键的一步。在所有涉及数据查询文章、标签等的数据库操作中必须显式地加上where条件确保只操作属于当前req.userId的数据。例如prisma.article.findMany({ where: { authorId: req.userId } })。绝对禁止直接根据客户端传来的文章 ID 进行查询而不验证所属权这会导致越权访问。路由保护在前端使用 React Router 或 Next.js 的中间件将需要登录才能访问的页面如/dashboard,/editor保护起来。如果检测到用户未登录则重定向到登录页。安全警告密码哈希务必使用专业的、抗碰撞的算法如 bcrypt、scrypt 或 Argon2绝对禁止明文存储或使用弱哈希算法如 MD5、SHA1。JWT 如果存储在客户端如 localStorage需注意防范 XSS 攻击如果使用 Cookie务必设置HttpOnly、Secure和SameSite属性以增强安全性。4. 部署与持续集成实战4.1 使用 Docker 进行容器化封装为了让应用在任何环境都能一致地运行容器化是标准做法。我为 woongaksi 创建了Dockerfile和docker-compose.yml。Dockerfile (用于 Next.js 前端 API Routes):# 使用 Node.js 官方镜像作为构建阶段 FROM node:18-alpine AS builder WORKDIR /app # 复制包管理文件和源代码 COPY package.json pnpm-lock.yaml ./ RUN corepack enable pnpm pnpm install --frozen-lockfile COPY . . # 运行构建生成静态文件和优化后的服务端代码 RUN pnpm build # 使用更小的镜像作为运行阶段 FROM node:18-alpine AS runner WORKDIR /app ENV NODE_ENVproduction # 创建非root用户以增强安全 RUN addgroup --system --gid 1001 nodejs adduser --system --uid 1001 nextjs # 从构建阶段复制必要的文件 COPY --frombuilder /app/public ./public COPY --frombuilder --chownnextjs:nodejs /app/.next/standalone ./ COPY --frombuilder --chownnextjs:nodejs /app/.next/static ./.next/static USER nextjs EXPOSE 3000 ENV PORT3000 # 启动 Next.js 服务 CMD [node, server.js]docker-compose.yml (整合数据库):version: 3.8 services: postgres: image: postgres:15-alpine environment: POSTGRES_USER: woongaksi POSTGRES_PASSWORD: your_secure_password_here POSTGRES_DB: woongaksi volumes: - postgres_data:/var/lib/postgresql/data ports: - 5432:5432 healthcheck: test: [CMD-SHELL, pg_isready -U woongaksi] interval: 10s timeout: 5s retries: 5 app: build: . depends_on: postgres: condition: service_healthy environment: DATABASE_URL: postgresql://woongaksi:your_secure_password_herepostgres:5432/woongaksi NEXTAUTH_SECRET: your_generated_secret_here ports: - 3000:3000 volumes: - ./uploads:/app/uploads # 持久化上传的文件 volumes: postgres_data:这个组合确保了数据库数据持久化并且应用启动前会等待数据库健康检查通过。4.2 基于 GitHub Actions 的自动化 CI/CD每次代码推送到主分支自动完成测试、构建和部署这是现代开发的标配。我使用GitHub Actions来实现。.github/workflows/deploy.yml 示例name: Deploy to VPS on: push: branches: [ main ] jobs: test-and-build: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - uses: actions/setup-nodev4 with: node-version: 18 - name: Install pnpm uses: pnpm/action-setupv2 with: version: 8 - name: Install Dependencies run: pnpm install --frozen-lockfile - name: Run Lint and Tests run: pnpm run lint pnpm run test # 假设你配置了这些脚本 - name: Build run: pnpm run build env: DATABASE_URL: ${{ secrets.DATABASE_URL }} # 使用虚拟变量构建 NEXTAUTH_SECRET: dummy_secret - name: Upload Build Artifact uses: actions/upload-artifactv4 with: name: app-build path: ./ deploy: needs: test-and-build runs-on: ubuntu-latest steps: - name: Download Build Artifact uses: actions/download-artifactv4 with: name: app-build - name: Deploy to Server via SSH uses: appleboy/ssh-actionv1.0.0 with: host: ${{ secrets.DEPLOY_HOST }} username: ${{ secrets.DEPLOY_USER }} key: ${{ secrets.DEPLOY_SSH_KEY }} script: | cd /opt/woongaksi git pull origin main docker-compose down docker-compose build --no-cache app docker-compose up -d docker system prune -f # 清理无用的镜像和容器这个工作流做了几件事1) 在干净的 Ubuntu 环境中拉取代码2) 安装依赖并运行代码检查和测试3) 构建应用4) 通过 SSH 连接到部署服务器拉取最新代码然后用 Docker Compose 重新构建并启动服务。关键点所有敏感信息数据库连接字符串、服务器地址、SSH 密钥等都存储在 GitHub 仓库的Secrets中不会暴露在代码里。4.3 服务器配置与反向代理我选择在一台云服务器VPS上部署。系统配置要点如下基础安全更新系统apt update apt upgrade -y创建非 root 用户禁用 root 的 SSH 密码登录。配置防火墙UFW只开放 SSH22、HTTP80、HTTPS443端口。安装 Fail2ban 防止暴力破解。安装 Docker 和 Docker Compose按照官方文档安装最新稳定版。配置反向代理Nginx我们通常让 Docker 容器运行在 3000 端口然后用 Nginx 监听 80/443 端口将请求转发给容器并处理 SSL 证书。# /etc/nginx/sites-available/woongaksi server { listen 80; server_name your-domain.com; # 你的域名 return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name your-domain.com; ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; # ... 其他 SSL 优化配置 ... location / { proxy_pass http://localhost:3000; # 指向 Docker 容器 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }获取 SSL 证书使用Certbot自动获取和续签 Let‘s Encrypt 免费证书。sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d your-domain.com完成以上步骤后你的 woongaksi 知识库就可以通过https://your-domain.com安全访问了。5. 开发与维护中的常见问题与解决实录5.1 数据库迁移冲突与回滚在使用 Prisma 进行团队协作时最常遇到的问题就是数据库迁移冲突。A 开发者创建了一个迁移文件2024032001_add_email_to_user/B 开发者在自己的分支上也创建了一个迁移2024032002_rename_title_field/。当合并代码时如果直接运行prisma migrate deploy可能会因为执行顺序或依赖问题导致失败。解决方案沟通与顺序团队内约定在创建迁移前先拉取最新代码确保本地的迁移基线是最新的。重置开发数据库在开发环境如果迁移混乱了一个快速的方法是重置数据库。使用prisma migrate reset命令它会清空数据库并从头应用所有迁移。注意此操作会丢失所有开发数据因此务必确保开发数据库的数据不重要或者有种子脚本可以快速重建。手动解决冲突如果迁移文件本身冲突比如都修改了同一个模型需要手动合并migration.sql文件。合并后可以删除旧的冲突迁移记录创建一个新的合并迁移。# 1. 解决文件冲突后生成一个新的迁移 npx prisma migrate dev --name merge_conflicts # 2. 这会创建一个新的迁移文件包含了合并后的 schema 变更使用影子数据库Shadow DatabasePrisma 在运行migrate dev时会使用一个影子数据库来检测 schema 漂移drift。确保你的数据库连接有创建临时数据库的权限这能帮助提前发现潜在问题。5.2 前端构建体积过大与优化Next.js 应用构建后如果发现.next/static/chunks/下的文件特别大会影响页面加载速度。排查与优化步骤分析包体积使用next/bundle-analyzer插件。在next.config.js中配置后运行ANALYZEtrue pnpm build它会生成一个交互式图表直观展示每个依赖包占用的体积。识别罪魁祸首通常大型的 UI 库、图表库、未做 Tree Shaking 的旧式库是主要元凶。优化策略动态导入Dynamic Import对于非首屏必需的组件如编辑器、图表、复杂的设置页面使用next/dynamic进行懒加载。import dynamic from next/dynamic; const HeavyEditor dynamic(() import(../components/HeavyEditor), { ssr: false });选择更轻量的替代品例如用date-fns替代moment.js用react-markdown配合插件自己组装而不是引入一个全功能的 Markdown 编辑器包。检查导入方式确保从库中按需导入而不是导入整个库。例如import { Button } from some-ui-lib而不是import * as UILib from some-ui-lib。升级依赖新版本库可能进行了优化或拆包。配置代码分割Next.js 默认已做了很多优化。确保你没有意外地禁用了一些优化选项。5.3 图片上传、存储与优化知识库中插入图片是刚需。需要解决上传、存储、预览和优化问题。实现方案上传接口在 Next.js API Route 或独立后端中创建一个接收multipart/form-data的端点。使用busboy或formidable库解析上传的文件流。存储策略本地存储最简单将文件流写入服务器磁盘的特定目录如./public/uploads。需要确保该目录有写权限并且通过静态文件服务暴露出来Next.js 的public目录或 Nginx 配置一个静态资源路径。缺点是扩容和备份麻烦。对象存储推荐使用云服务如 AWS S3、Cloudflare R2、或兼容 S3 协议的服务如 MinIO。客户端可以直接上传到云存储需配置 CORS 和临时凭证或者通过你的服务器中转。这种方式扩展性强可靠性高。woongaksi 项目预留了对接 S3 的配置接口。前端实现在 TipTap 编辑器中通过扩展实现图片拖拽或粘贴上传。上传成功后将返回的图片 URL 插入到编辑器内容中。图片优化为了提升页面性能可以对上传的图片进行自动优化。Next.js Image 组件如果图片存储在本地public目录或配置了远程图案可以使用Image /组件它会自动进行格式转换、尺寸优化和懒加载。云服务优化很多对象存储服务提供图片处理功能如 Cloudflare Images/Transform AWS LambdaEdge可以在请求时实时裁剪、压缩。在上传时处理使用sharp库在服务器端对上传的图片进行压缩和生成 WebP 等现代格式。一个简单的本地存储上传 API Route 示例 (pages/api/upload.ts):import { NextApiRequest, NextApiResponse } from next; import { createWriteStream } from fs; import { join } from path; import { promisify } from util; import { pipeline } from stream; import formidable from formidable; export const config { api: { bodyParser: false } }; // 禁用默认解析使用 formidable const pump promisify(pipeline); export default async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method ! POST) return res.status(405).end(); const uploadDir join(process.cwd(), public, uploads); // 确保上传目录存在... const form formidable({ uploadDir, keepExtensions: true, filename: (name, ext) ${Date.now()}-${name}${ext}, }); try { const [fields, files] await form.parse(req); const file files.file?.[0]; // 假设前端表单字段名是 file if (!file) throw new Error(No file uploaded); const publicUrl /uploads/${file.newFilename}; res.status(200).json({ url: publicUrl }); } catch (error) { console.error(Upload error:, error); res.status(500).json({ error: Upload failed }); } }5.4 环境变量管理与敏感信息泄露项目会涉及数据库密码、API 密钥、加密盐值等敏感信息。错误的管理会导致严重的安全问题。正确做法使用.env文件在项目根目录创建.env.local文件已加入.gitignore存放开发环境变量。DATABASE_URLpostgresql://user:passwordlocalhost:5432/woongaksi_dev NEXTAUTH_SECRETyour-super-secret-and-long-string-here NEXTAUTH_URLhttp://localhost:3000在代码中读取Next.js 内置了环境变量支持。以NEXT_PUBLIC_开头的变量会在浏览器端可访问其他的只在服务器端 Node.js 环境中可访问。// 服务器端代码 const dbUrl process.env.DATABASE_URL; // 客户端代码仅在构建时替换 const appName process.env.NEXT_PUBLIC_APP_NAME;生产环境配置在部署服务器上如 Docker 容器、VPS 环境变量、Vercel 等平台的项目设置中设置这些变量。永远不要将.env文件提交到代码仓库。为 Docker 传递变量在docker-compose.yml中通过environment字段或引用外部.env文件来传递。services: app: environment: - DATABASE_URL${DATABASE_URL} env_file: - .env.production # 在服务器上创建这个文件密钥生成像NEXTAUTH_SECRET这样的密钥必须使用强随机字符串。可以通过命令行生成openssl rand -base64 32。遵循这些实践你的 woongaksi 知识库就能在一个安全、可控、高效的环境中运行和迭代。这个项目不仅是一个工具更是一个全栈开发的绝佳练手场涵盖了从构思、设计、编码到部署、运维的完整生命周期。希望这份详细的拆解能为你构建自己的数字花园提供扎实的参考。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2591608.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!