@airalogy/airalogy-bd 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  版本统一使用 `x.y.z`,公开版本记录从 1.0.0 开始。本文件记录版本内容;安装包、镜像和线上服务的发布状态分别确认。
4
4
 
5
+ ## [Unreleased]
6
+
7
+ ## [1.1.2] - 2026-10-26
8
+
9
+ - 源码开发直接使用 Next.js Fast Refresh,保留开发编译缓存;页面、样式和接口代码修改无需重启,安装工作区和生产构建继续使用独立运行目录。
10
+ - GitHub 正式 Release 自动构建并测试 Linux amd64 / arm64 镜像,使用临时 GitHub 凭据将同一测试归档发布到 GHCR,与 npm 保持同一版本。
11
+ - 增加镜像版本、提交、完整性及匿名拉取校验,拒绝覆盖不同内容的版本;自动提供锁定镜像摘要的部署包及校验文件。
12
+ - 团队部署默认使用预构建镜像,源码构建通过单独的 Compose 配置显式启用。
13
+
14
+ ## [1.1.1] - 2026-10-26
15
+
16
+ - 增加 GitHub Actions 可信发布流程:正式 Release 触发完整测试与安装包验证,通过 npm OIDC 发布同一归档;手动运行只检查,不发布。
17
+ - 发布环境仅允许版本标签,测试与发布权限分离,使用临时身份凭据,核对测试归档与 npm 公开包的完整性。
18
+ - 打包检查兼容 npm 12 按包名组织的 JSON 报告,保留此前 npm 版本的验证方式。
19
+
5
20
  ## [1.1.0] - 2026-10-25
6
21
 
7
22
  - 支持用户名或邮箱登录。受邀成员自行设置唯一用户名;已有账号可在“我的账号”中补充用户名,保留内部 ID、权限和历史记录。
package/README.md CHANGED
@@ -27,21 +27,30 @@ Airalogy BD 是一套支持本地使用与团队服务器部署的 BD 管理工
27
27
  - uv
28
28
  - Git
29
29
 
30
+ ## 安装方式
31
+
32
+ - 团队成员:打开公司部署的网址,无需安装。
33
+ - 公司服务器:优先下载 GitHub Release 的预构建镜像部署包,按[团队部署说明](docs/server-deployment.md)使用固定版本镜像;不需要在服务器安装开发依赖或构建程序。
34
+ - 本地工作台:用 pnpm 安装固定版本的 npm 包,步骤见下文。
35
+ - 开发与定制:检出 GitHub 源码。
36
+
37
+ 容器镜像与 npm、GitHub Release 使用同一 `x.y.z`,支持 Linux amd64 / arm64。以 Release 中的部署附件和工作流成功状态确认可用性,不根据 npm 版本推断镜像已经发布。
38
+
30
39
  ## 安装与初始化
31
40
 
32
- 在独立的业务工作区安装指定版本。以下以 `1.1.0` 为例,需要该版本已发布到 npm:
41
+ 在独立的业务工作区安装指定版本。以下以 `1.1.1` 为例,需要该版本已发布到 npm:
33
42
 
34
43
  ```sh
35
44
  mkdir company-bd
36
45
  cd company-bd
37
- pnpm dlx @airalogy/airalogy-bd@1.1.0 init --id company-id --name 公司名称
46
+ pnpm --allow-build=sharp --allow-build=unrs-resolver dlx @airalogy/airalogy-bd@1.1.1 init --id company-id --name 公司名称
38
47
  pnpm install
39
48
  ```
40
49
 
41
- 初始化会固定当前程序版本,不依赖临时下载目录。也可以先用 pnpm 安装,再初始化:
50
+ 首次安装需要明确许可 `sharp` 和 `unrs-resolver` 的构建脚本,上述命令只允许这两项。初始化会固定当前程序版本,不依赖临时下载目录。也可以先用 pnpm 安装,再初始化:
42
51
 
43
52
  ```sh
44
- pnpm add -D -E @airalogy/airalogy-bd@1.1.0
53
+ pnpm add -D -E @airalogy/airalogy-bd@1.1.1 --allow-build=sharp --allow-build=unrs-resolver
45
54
  pnpm exec bd init --id company-id --name 公司名称
46
55
  ```
47
56
 
@@ -55,7 +64,7 @@ pnpm exec bd init --id company-id --name 公司名称
55
64
  {
56
65
  "private": true,
57
66
  "devDependencies": {
58
- "@airalogy/airalogy-bd": "1.1.0"
67
+ "@airalogy/airalogy-bd": "1.1.1"
59
68
  },
60
69
  "scripts": {
61
70
  "dev": "bd dev",
@@ -113,6 +122,12 @@ pnpm dev
113
122
 
114
123
  `fixtures/demo/content/` 只包含虚构数据,用于平台回归测试。
115
124
 
125
+ 日常开发直接运行 `pnpm dev`,不构建 Docker。此命令通过 `bd dev --source` 直接运行 `dashboard/` 源码,由 Next.js 原生 Fast Refresh 处理组件、样式及接口代码更新,不复制源码或额外实现同步监听器。编译缓存保留在 `dashboard/.next/`,重启开发服务可继续复用;默认使用 Webpack,兼容链接依赖。业务资料变更仍通过数据服务自动刷新。
126
+
127
+ 源码开发可用 `bd dev --source --content /指定工作区/content` 选择资料目录;同一个源码目录同时运行一个开发服务。修改 CLI、依赖或启动环境变量后需重启,依赖变化还需重新执行 `pnpm install`。普通安装用户继续使用 `bd dev` 或双击启动文件,保留各自独立运行目录。
128
+
129
+ 按改动运行针对性测试;`pnpm test:dev` 在临时源码副本和虚构工作区中验证真实开发服务的热更新。发版前再执行完整测试。Docker 构建和双架构容器演练用于正式发版,以及 Dockerfile、系统依赖或容器运行配置的修改,不是每次开发都必须执行的步骤。
130
+
116
131
  需要在独立工作区调试源码时,可执行 `node /path/to/airalogy-bd/bin/bd.mjs init --source`,再安装工作区依赖。`--source` 仅为新依赖使用本地链接;初始化不会覆盖已有依赖版本或自定义命令。npm 安装包的验证和发布见[发布说明](docs/npm-publishing.md)。
117
132
 
118
133
  ### 目录与文件命名
@@ -276,9 +291,9 @@ bd dev --content /path/to/new-workspace/content
276
291
 
277
292
  页脚显示实际运行的软件版本,点击可查看构建时间、构建标识及本地代码版本。从源码构建时显示“构建来源:本地源码”;版本来自工作台软件自身,不读取公司工作区的包版本。构建标识随程序内容变化,用于区分同一版本号下的本地更新。
278
293
 
279
- 版本信息在 `bd build` / `bd dev` 准备运行目录时固定,`bd start` 沿用已有构建的信息;修改或升级源码后需重新构建并启动才能加载。界面仅展示当前运行版本,不自动查询远程发布,发布状态由发布标签与分发产物确定。
294
+ 版本信息在 `bd build` / `bd dev` 启动时固定,`bd start` 沿用已有构建的信息。源码开发的页面代码可热更新,版本卡片中的构建标识仍对应启动时的源码快照;重启开发服务可刷新此标识。正式运行时,修改或升级源码后需重新构建并启动才能加载。界面仅展示当前运行版本,不自动查询远程发布,发布状态由发布标签与分发产物确定。
280
295
 
281
- `pnpm version:check` 检查软件版本与更新记录是否一致,已纳入 `pnpm test`。代码提交和推送不自动创建发布标签、安装包或线上部署。
296
+ `pnpm version:check` 检查软件版本与更新记录是否一致,已纳入 `pnpm test`。代码提交和推送不自动发版或部署。正式发布 GitHub Release 后,已配置的[可信发布流程](docs/npm-publishing.md)会验证并发布 npm 安装包、同版本容器镜像和部署附件;服务器部署仍单独执行。
282
297
 
283
298
  公开前运行 `pnpm publication:check`,并按 [公开代码检查说明](docs/publication-check.md) 复核源码及实际分发文件。
284
299
 
package/bin/bd.mjs CHANGED
@@ -139,6 +139,8 @@ function workspaceRequest(contentDirectory, request) {
139
139
  }
140
140
 
141
141
  function runNext(command, contentDirectory, forwardedArguments) {
142
+ const sourceDevelopment = command === "dev" && forwardedArguments.includes("--source");
143
+ if (sourceDevelopment) forwardedArguments = forwardedArguments.filter(argument => argument !== "--source");
142
144
  const serverMode = process.env.BD_MODE === "server";
143
145
  if (process.env.BD_MODE && !["local","server"].includes(process.env.BD_MODE)) fail("BD_MODE 只支持 local 或 server。");
144
146
  if (serverMode && command !== "build") {
@@ -149,15 +151,19 @@ function runNext(command, contentDirectory, forwardedArguments) {
149
151
  }
150
152
  if (command !== "build") workspaceRequest(contentDirectory, {action:"checkpoint",origin:"checkpoint",label:"启动工作台时留存资料",force:true});
151
153
  const dataFile = command === "build" ? generateData(contentDirectory) : path.join(contentDirectory,"generated","dashboard.json");
152
- const dashboardDirectory = runtimeDashboardDirectory({prepare:command !== "start"});
154
+ // Let Next.js watch the real source tree and manage Fast Refresh itself.
155
+ // Installed workspaces and production builds retain their isolated runtime.
156
+ const dashboardDirectory = sourceDevelopment ? dashboardSourceDirectory : runtimeDashboardDirectory({prepare:command !== "start"});
153
157
  const nextBinary = require.resolve("next/dist/bin/next");
154
- const env = {...process.env, BD_DATA_FILE:dataFile, BD_CONTENT_DIR:contentDirectory, BD_SERVICE_FILE:path.join(scriptsDirectory,"workspace_service.py"), BD_CACHE_DIR:cacheDirectory, BD_CSRF_TOKEN:randomBytes(32).toString("hex")};
155
- if (command === "build") {run(process.execPath,[nextBinary,command,dashboardDirectory,...(forwardedArguments.some(x=>["--webpack","--turbopack","--turbo"].includes(x))?[]:["--webpack"]),...forwardedArguments],{env});return;}
158
+ const env = {...process.env, BD_DATA_FILE:dataFile, BD_CONTENT_DIR:contentDirectory, BD_SERVICE_FILE:path.join(scriptsDirectory,"workspace_service.py"), BD_CACHE_DIR:cacheDirectory, BD_CSRF_TOKEN:randomBytes(32).toString("hex"), NEXT_PUBLIC_BD_DEV_BUILD_INFO:sourceDevelopment ? JSON.stringify(createBuildInfo(packageRoot)) : ""};
159
+ const bundler = command !== "start" && !forwardedArguments.some(x=>["--webpack","--turbopack","--turbo"].includes(x)) ? ["--webpack"] : [];
160
+ if (command === "build") {run(process.execPath,[nextBinary,command,dashboardDirectory,...bundler,...forwardedArguments],{env});return;}
156
161
  const hosts = forwardedArguments.flatMap((arg,index) => ["--hostname","-H"].includes(arg) ? [forwardedArguments[index+1]] : arg.startsWith("--hostname=") ? [arg.slice(11)] : arg.startsWith("-H") ? [arg.slice(2)] : []);
157
162
  const suppliedHost = hosts.length > 0;
158
163
  if (!serverMode && hosts.some(host => !["localhost","127.0.0.1","::1"].includes(host))) fail("本地模式只允许绑定本机地址;对外服务请配置服务器模式和登录账号。");
164
+ if (sourceDevelopment) console.log("源码开发模式:由 Next.js 自动刷新,编译缓存保存在 dashboard/.next。");
159
165
  const watcher = spawn(process.execPath,[path.join(scriptsDirectory,"watch-content.mjs")],{env,stdio:"inherit"});
160
- const server = spawn(process.execPath,[nextBinary,command,dashboardDirectory,...(!suppliedHost ? ["--hostname","127.0.0.1"] : []),...forwardedArguments],{env,stdio:"inherit"});
166
+ const server = spawn(process.execPath,[nextBinary,command,dashboardDirectory,...bundler,...(!suppliedHost ? ["--hostname","127.0.0.1"] : []),...forwardedArguments],{env,stdio:"inherit"});
161
167
  const stop = signal => {watcher.kill(signal);server.kill(signal);};
162
168
  process.once("SIGINT",() => stop("SIGINT"));
163
169
  process.once("SIGTERM",() => stop("SIGTERM"));
@@ -182,7 +188,7 @@ function printHelp() {
182
188
  bd launch
183
189
  bd validate [--content <dir>]
184
190
  bd data [--content <dir>]
185
- bd dev [--content <dir>] [Next.js options]
191
+ bd dev [--source] [--content <dir>] [Next.js options]
186
192
  bd build [--content <dir>] [Next.js options]
187
193
  bd start [--content <dir>] [Next.js options]
188
194
  bd lint
@@ -7,7 +7,7 @@ import path from "node:path";
7
7
  export function createBuildInfo(packageRoot) {
8
8
  const manifest = JSON.parse(readFileSync(path.join(packageRoot, "package.json"), "utf8"));
9
9
  const hash = createHash("sha256");
10
- const ignored = new Set(["node_modules", ".next", "__pycache__", ".pytest_cache", ".DS_Store", "tsconfig.tsbuildinfo"]);
10
+ const ignored = new Set(["node_modules", ".next", "__pycache__", ".pytest_cache", ".DS_Store", "tsconfig.tsbuildinfo", "next-env.d.ts"]);
11
11
  const visit = relative => {
12
12
  const absolute = path.join(packageRoot, relative);
13
13
  if (!existsSync(absolute)) return;
@@ -1,4 +1,4 @@
1
- import buildInfo from "./lib/build-info.json";
1
+ import buildInfo from "./lib/software-build";
2
2
  import { productInfo } from "./lib/product-info";
3
3
 
4
4
  export default function SoftwareVersion({ locale, timezone }: { locale: string; timezone: string }) {
@@ -1,7 +1,7 @@
1
1
  import { boundedBody, privateHeaders, serverMode, trustedRequest } from "../../lib/server-auth";
2
2
  import { invokeRemote } from "../../lib/workspace-server";
3
3
  import { remoteTools } from "../../lib/remote-tools";
4
- import buildInfo from "../../lib/build-info.json";
4
+ import buildInfo from "../../lib/software-build";
5
5
 
6
6
  export const runtime = "nodejs";
7
7
  export const dynamic = "force-dynamic";
@@ -0,0 +1,9 @@
1
+ import packagedBuild from "./build-info.json";
2
+
3
+ // Source development keeps generated identity out of tracked files. Next.js
4
+ // embeds this public metadata consistently in the server and browser bundles.
5
+ const buildInfo: typeof packagedBuild = process.env.NODE_ENV === "development" && process.env.NEXT_PUBLIC_BD_DEV_BUILD_INFO
6
+ ? JSON.parse(process.env.NEXT_PUBLIC_BD_DEV_BUILD_INFO)
7
+ : packagedBuild;
8
+
9
+ export default buildInfo;
@@ -2,6 +2,8 @@ import type { NextConfig } from "next";
2
2
 
3
3
  const nextConfig: NextConfig = {
4
4
  poweredByHeader: false,
5
+ // Development must not generate instruction files inside the source checkout.
6
+ agentRules: false,
5
7
  serverExternalPackages: ["better-auth"],
6
8
  async headers() {
7
9
  return [{source:"/:path*",headers:[
@@ -11,16 +11,53 @@
11
11
  5. 对经过验证的同一个 `.tgz` 执行 `npm publish /path/to/release-artifacts/airalogy-airalogy-bd-X.Y.Z.tgz --access public --registry=https://registry.npmjs.org/`,按 npm 提示完成双因素验证,不重新从不同工作目录打包发布。
12
12
  6. 用 `npm view @airalogy/airalogy-bd@X.Y.Z version dist.integrity --registry=https://registry.npmjs.org/` 核对版本,再从公开仓库安装到另一个空工作区验证。完成后将 GitHub Release 的版本、提交和安装方式一并记录。
13
13
 
14
+ npm 接收发布后会扫描安装包,通常需等待数分钟才可按包名安装。先确认公开注册表可查询到该版本,再执行安装验证;等待期间不重复发布同一版本。首次 pnpm 安装需按 README 明确许可 `sharp` 与 `unrs-resolver` 的构建脚本。
15
+
14
16
  公开安装包只包含通用程序、模板、文档和许可证。产品包移除 `private: true`,独立业务工作区仍设置 `private: true`。工作区、数据库、密钥、业务附件和备份不应进入 npm 包。
15
17
 
16
18
  版本发布后不可覆盖;修复发布为新版本。应用版本发布、更新本地依赖、服务器部署分别执行。尚未验证的安装包不能仅因源码测试通过就视为可发布。
17
19
 
18
- ## 后续使用可信发布
20
+ ## GitHub 可信发布
21
+
22
+ 仓库提供 [Release packages 工作流](../.github/workflows/publish.yml)。正式发布 GitHub Release 时自动检查并发布 npm 和同版本容器镜像;普通提交、推送、仅创建标签、草稿 Release 和手动检查均不会发布 npm。预发布版本不允许发布到 `latest`。
23
+
24
+ ### 一次性配置
25
+
26
+ 1. 在 GitHub 仓库创建名为 `npm` 的 Environment,Deployment branches and tags 选择 Selected branches and tags,只添加类型为 Tag、名称为 `v*.*.*` 的规则,不允许分支进入此环境。
27
+ 2. 在 npm 包的 Settings → Trusted publishing 添加 GitHub Actions:组织 `airalogy`、仓库 `airalogy-bd`、工作流文件名 `publish.yml`、环境 `npm`。允许直接 Publish;本工作流只执行正式发布,不使用 staged publish 或独立的 dist-tag 管理。更改信任配置仍需管理员完成 npm 双因素验证。
28
+ 3. 也可使用 npm 11.15.0 以上的官方命令完成绑定:
29
+
30
+ ```sh
31
+ npm trust github @airalogy/airalogy-bd --repo airalogy/airalogy-bd --file publish.yml --env npm --allow-publish
32
+ ```
33
+
34
+ 4. 新建信任关系必须在两天内完成首次成功发布。仅保存配置、执行 `--dry-run` 或通过测试不会验证这项关系;超时需删除过期关系并重新创建。因此应在下一正式版本准备就绪时完成绑定。
35
+
36
+ 工作流使用 GitHub 托管的 Ubuntu runner、固定版本的 Node.js/npm/pnpm/uv,以及固定提交的 Actions。无需配置 `NPM_TOKEN` 或其他长期发布密钥,现有 npm 账号双因素验证继续保留。此文档与工作流文件不能代替上述远程设置;可用 `npm trust list @airalogy/airalogy-bd` 和 GitHub Environment 设置检查实际状态。
37
+
38
+ ### 日常发版
39
+
40
+ 1. 修改版本号与更新记录,完成审阅后将源码提交、推送到 `main`。
41
+ 2. 如需提前检查,在 GitHub Actions → Release packages → Run workflow 中选择 `main`。手动运行检查安装包及两种架构的镜像,不取得 npm 或 GHCR 发布权限。
42
+ 3. 为已准备好的提交创建 `vX.Y.Z` 标签,在 GitHub 正式发布对应的 Release。标签必须匹配 `package.json` 的 `x.y.z`,指向 `main` 历史中的提交;发布后不移动标签或覆盖版本。
43
+ 4. 工作流先执行完整测试,再打包并在独立工作区验证安装、初始化、启动器、Logo、资料保留和生产构建。测试任务只有源码读取权限,不具有 OIDC 发布权限。
44
+ 5. 两个原生架构 runner 分别构建并实际测试 Linux amd64 / arm64 镜像,按架构复用 GitHub Actions 构建缓存,覆盖邀请、登录、备份、重启和恢复。两者通过后才开始发布 npm。
45
+ 6. 独立发布任务进入 `npm` 环境,下载本次测试的同一份归档并核对 SHA-256、包名、版本及来源。该任务不检出业务程序、不安装程序依赖、不运行安装包脚本;通过 OIDC 临时身份向 npm 发布,并等待公开注册表中的 SHA-512 完整性校验通过。
46
+
47
+ GitHub Release 创建成功不表示 npm 已成功发布,须等待整个 **Release packages** 工作流完成;镜像发布、匿名拉取验证和 Release 附件均为独立步骤。npm 扫描或网络验证超时后,先检查注册表是否已存在该版本;不能盲目重发。工作流会拒绝覆盖已有版本。验证归档保存在该次 Actions 的 Artifacts 中,保留 14 天,测试镜像归档保留 7 天。失败时优先选择 GitHub 的 **Re-run failed jobs**,复用同一批已验证归档;不要移动标签或重新构建后覆盖已发布版本。服务器部署和业务工作区依赖更新仍需另外执行。
48
+
49
+ 仓库管理员及有权修改工作流、创建版本标签和 Release 的维护者能影响发布,应只向受信任人员授予相关权限。需要多人审批时,可在 `npm` 环境增加 Required reviewers,不必改回长期 npm 密钥。
50
+
51
+ ## 容器与 Release 附件
52
+
53
+ 镜像发布到 `ghcr.io/airalogy/airalogy-bd:X.Y.Z`,与 npm 和 GitHub Release 的版本一致。只提供固定版本及用于合并的 `X.Y.Z-amd64` / `X.Y.Z-arm64` 标签,不自动更新 `latest`。镜像记录源码提交号及版本,并由已测试的两份归档合并成一个多架构版本,发布任务不会重新构建镜像。
54
+
55
+ GHCR 使用该次 GitHub Actions 的 `GITHUB_TOKEN`,不需要保存个人访问令牌。构建和容器测试没有镜像写权限;只有镜像发布任务取得 `packages: write`,Release 附件任务单独取得 `contents: write`。正式发布任务共用现有的 `npm` 环境及版本标签限制,不修改 npm 的信任绑定。
19
56
 
20
- 推荐使用 npm Trusted Publishing,将该包绑定到 `airalogy/airalogy-bd` 仓库中专门的 GitHub Actions 工作流。首次包创建完成后,由包管理员在 npm 包设置中配置组织、仓库和工作流文件名;开启前应准备好流程,并按照 npm 当前的配置有效期完成首次验证。
57
+ **首次 GHCR 发布后**,包管理员需要在 GitHub Packages 的 `airalogy-bd` 设置中将 Visibility 设为 **Public**。GHCR 新包默认私有,不能根据源码仓库公开就假定镜像也已公开。工作流在全新任务中清空 Docker 登录配置,分别验证两种架构可匿名拉取;如果首次发布停在此处,设置公开后重跑失败任务。组织须允许该仓库创建和发布容器包。
21
58
 
22
- 工作流应从指定版本标签检出并核对版本,在不授予发布凭据的任务中安装、测试和生成归档,再由独立发布任务取得 OIDC 临时身份并上传已验证的同一归档。使用受保护的发布环境控制正式发布;普通提交和推送不触发发布。CI 使用支持可信发布的 npm CLI(至少 11.5.1)与 Node.js(至少 22.14.0),无需保存长期 npm 发布 Token。
59
+ 镜像验证完成后,Release 自动附上 npm 的同一 `.tgz` 及其校验文件、锁定镜像摘要的 `airalogy-bd-X.Y.Z-deploy.tar.gz`、`image.json` 与 `SHA256SUMS`。部署包不含账号、密钥或业务资料。普通提交和手动检查不创建这些正式发布附件,也不部署服务器。
23
60
 
24
- 此配置需要 npm 包和 GitHub 权限配合,文档本身不会启用远程自动发布。首次人工发布与后续可信发布都不要求用户改用 npm 安装;使用者仍可通过 pnpm 固定版本安装。
61
+ 不同注册表不能提供跨平台的原子发布:若 npm 已成功而镜像步骤失败,该 Release 尚未完整交付。按失败步骤重试,不更换已发布包。相同镜像摘要或 Release 附件可以安全重试;检测到同版本下不同内容时会拒绝覆盖。镜像归档过期后需人工检查发布状态,不能用新构建直接替换已有版本。
25
62
 
26
- 参考:[npm 公开组织包](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages/)、[npm Trusted Publishing](https://docs.npmjs.com/trusted-publishers/)。
63
+ 参考:[GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry)、[npm 公开组织包](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages/)、[npm Trusted Publishing](https://docs.npmjs.com/trusted-publishers/)、[npm trust 命令](https://docs.npmjs.com/cli/v11/commands/npm-trust/)。
@@ -5,8 +5,8 @@
5
5
  ## 成员使用
6
6
 
7
7
  - 维护人员初始化第一名管理员,管理员在“管理中心 → 成员与权限”发放 48 小时一次性邀请链接。系统不发送邮件,不开放注册。
8
- - 成员打开链接,设置至少 12 个字符的密码,并将密钥加入支持 TOTP 的验证器。此后使用邮箱、密码和 6 位动态验证码登录。登录分为密码和动态码两步;尚未完成验证器绑定或动态码验证的会话不能访问业务资料。设置中断后可从登录页面继续绑定。服务器和手机应开启时间同步。
9
- - 会话最长 12 小时;退出、停用账号、调整授权或重置登录会立即使相应旧会话失效。账号邮箱是登录标识,未通过邮件验证;管理员应把链接私下交给正确的人。
8
+ - 成员打开链接,设置唯一用户名、至少 12 个字符的密码,并将密钥加入支持 TOTP 的验证器。此后使用用户名或邮箱、密码和 6 位动态验证码登录。登录分为密码和动态码两步;尚未完成验证器绑定或动态码验证的会话不能访问业务资料。设置中断后可从登录页面继续绑定。服务器和手机应开启时间同步。
9
+ - 会话最长 12 小时;退出、停用账号、调整授权或重置登录会立即使相应旧会话失效。账号邮箱仍保留为联系方式和可用的登录标识,未通过邮件验证;管理员应把链接私下交给正确的人。
10
10
  - 管理员:全部资料、邀请和权限、共享人员/公司动态、事项创建、全局历史和备份。
11
11
  - 编辑成员:修改已授权事项、添加每日进展、维护关联附件。跨事项附件必须拥有全部关联事项权限。新增人员、对接方或将范围外人员关联到事项需管理员处理。
12
12
  - 只读成员:浏览、下载和导出已授权资料。导出基于同一份过滤后数据。
@@ -21,26 +21,52 @@
21
21
 
22
22
  可以和现有服务共用 ECS,但使用独立容器、数据卷和反向代理站点。先确认空闲内存、CPU、磁盘和备份容量;镜像构建建议在 CI 或开发机完成,避免构建影响生产站点。示例限制为 1 CPU / 1.5 GiB,需按实际负载调整。只有宿主机的 `127.0.0.1:3100` 暴露应用;使用现有 Nginx 接入 HTTPS,不抢占现有站点的 80/443 端口。
23
23
 
24
- 以下命令在本代码仓库执行。需要 Docker Engine 和 Compose v2。
24
+ ### 推荐:使用预构建镜像
25
+
26
+ 需要 Docker Engine 和 Compose v2。选择附带 `airalogy-bd-X.Y.Z-deploy.tar.gz`、且 **Release packages** 工作流成功的 GitHub Release。npm 上存在某个版本不代表该版本的容器镜像已经发布。
27
+
28
+ 下载并解压部署包到独立目录,无需下载源码或在服务器构建。部署包包含 `compose.yaml`、`.env.example`、`image.json` 和使用说明。镜像名为 `ghcr.io/airalogy/airalogy-bd:X.Y.Z`,支持 Linux amd64 / arm64;生成的配置进一步锁定该版本的镜像摘要,Docker 自动选择匹配的架构。核对 Release 的 `SHA256SUMS` 后,在解压目录执行:
25
29
 
26
30
  ```sh
27
- cp deploy/.env.example deploy/.env
28
- chmod 600 deploy/.env
29
- # 生成认证密钥,将输出填入 deploy/.env 的 BETTER_AUTH_SECRET,并单独妥善保管。
31
+ cp .env.example .env
32
+ chmod 600 .env
33
+ # 生成认证密钥,将输出填入 .env 的 BETTER_AUTH_SECRET,并独立妥善保管。
30
34
  openssl rand -hex 32
31
- # 编辑 deploy/.env,至少设置 BD_PUBLIC_URL 和 BETTER_AUTH_SECRET。
32
- docker compose -f deploy/compose.yaml build
33
- docker compose -f deploy/compose.yaml run --rm bd init --id company-id --name 公司名称
34
- docker compose -f deploy/compose.yaml run --rm bd account-init --email admin@example.com --name 管理员姓名
35
- docker compose -f deploy/compose.yaml up -d
35
+ # 编辑 .env,至少设置 BD_PUBLIC_URL 和 BETTER_AUTH_SECRET。
36
+ docker compose pull
37
+ docker compose run --rm bd init --id company-id --name 公司名称
38
+ docker compose run --rm bd account-init --email admin@example.com --name 管理员姓名
39
+ docker compose up -d
36
40
  ```
37
41
 
38
- 官方 npm 下载不稳定时,可在构建时传 `--build-arg NPM_REGISTRY=https://registry.npmmirror.com`。此选项仅影响依赖下载,仍按同一锁文件校验完整性,不改变运行时配置。
42
+ 安装过程不需要 Node.js、pnpm 或 uv,运行依赖已在镜像内。公开 GHCR 镜像支持匿名拉取。连接 GHCR 受限时,可由维护人员将同一镜像同步到公司镜像仓库并核对摘要,再设置 `BD_IMAGE`;不要改用不明来源的镜像。
43
+
44
+ ### 使用仓库中的配置或从源码构建
45
+
46
+ 仓库中的 `deploy/compose.yaml` 同样只拉取镜像。复制 `deploy/.env.example` 为 `deploy/.env`,填写已发布的 `BD_IMAGE` 版本或摘要及必要配置;使用下列命令使 Compose 同时读取镜像选择和运行环境:
47
+
48
+ ```sh
49
+ docker compose --env-file deploy/.env -f deploy/compose.yaml pull
50
+ docker compose --env-file deploy/.env -f deploy/compose.yaml run --rm bd init --id company-id --name 公司名称
51
+ docker compose --env-file deploy/.env -f deploy/compose.yaml run --rm bd account-init --email admin@example.com --name 管理员姓名
52
+ docker compose --env-file deploy/.env -f deploy/compose.yaml up -d
53
+ ```
54
+
55
+ 需要修改源码时,将 `deploy/.env` 的 `BD_IMAGE` 明确设为 `airalogy-bd:local`,增加源码构建配置:
56
+
57
+ ```sh
58
+ docker compose --env-file deploy/.env -f deploy/compose.yaml -f deploy/compose.build.yaml build
59
+ docker compose --env-file deploy/.env -f deploy/compose.yaml -f deploy/compose.build.yaml up -d
60
+ ```
61
+
62
+ 官方 npm 下载不稳定时,可仅在源码构建命令后添加 `--build-arg NPM_REGISTRY=https://registry.npmmirror.com`。它只影响构建依赖下载,仍按锁文件校验完整性。
63
+
64
+ 下文的仓库命令均显式指定 `deploy/.env` 和 Compose 文件。使用下载的部署包时,在解压目录改为 `docker compose` 即可。
39
65
 
40
66
  复制终端的一次性链接,由管理员本人打开设置登录。不要把该链接贴入公共日志或工单。初始化已存在管理员时会拒绝重复创建;丢失验证器或管理员账号无法登录时,由持有服务器权限的维护人员执行:
41
67
 
42
68
  ```sh
43
- docker compose -f deploy/compose.yaml run --rm bd account-recover --email admin@example.com
69
+ docker compose --env-file deploy/.env -f deploy/compose.yaml run --rm bd account-recover --email admin@example.com
44
70
  ```
45
71
 
46
72
  恢复命令立即注销该账号旧会话、密码和验证器,发出新的单次邀请。不会改变原有角色或事项授权。邀请过期也可重新签发。
@@ -61,7 +87,7 @@ docker compose -f deploy/compose.yaml run --rm bd account-recover --email admin@
61
87
 
62
88
  1. 创建专用私有 Bucket,开启阻止公共访问;不要为备份前缀配置公开策略、静态网站或公共下载域名。
63
89
  2. 创建专用 RAM 身份,仅允许目标 Bucket 的 `oss:GetBucketAcl`,以及 `bd-backups/*` 前缀的 `oss:PutObject`、`oss:GetObject`(含 HEAD)。不需要删除、列举全 Bucket 或修改 ACL 的管理权限。通过 ECS 环境配置专用 AccessKey,或配置会被外部系统及时轮换的临时 STS 凭据;应用本身不负责 STS 续期,不要使用主账号密钥。
64
- 3. 填写 `deploy/.env` 的地域、Bucket、HTTPS Endpoint、前缀和 `OSS_ACCESS_KEY_ID` / `OSS_ACCESS_KEY_SECRET`。同地域 ECS 可用对应 `-internal` Endpoint。凭据只存在部署环境,页面、业务资料和备份均不保存它们。限制环境文件及 Docker 管理权限。
90
+ 3. 填写部署环境文件 `.env` 的地域、Bucket、HTTPS Endpoint、前缀和 `OSS_ACCESS_KEY_ID` / `OSS_ACCESS_KEY_SECRET`。同地域 ECS 可用对应 `-internal` Endpoint。凭据只存在部署环境,页面、业务资料和备份均不保存它们。限制环境文件及 Docker 管理权限。
65
91
  4. 设置 `BD_OSS_BACKUP=1`,重新创建容器。若曾在页面保存过设置,页面设置优先于环境默认值;需在“备份”页面开启“同步到私有 OSS”。立即备份一次,确认页面同时出现本地位置和 OSS 对象位置。
66
92
  5. OSS 对象使用唯一名称、私有 ACL、AES256 服务端加密和 Content-MD5 校验。上传后再次核对大小与 SHA-256 元数据,确认后才标记整次备份成功。备份含密码哈希和已加密的验证器密钥,必须按敏感资料管理。
67
93
  6. OSS 生命周期由管理员在 Bucket 中配置,例如仅对 `bd-backups/` 保留 90 天。程序没有删除 OSS 对象的权限。是否启用版本控制/保留策略由公司运维决定。
@@ -87,8 +113,8 @@ docker compose -f deploy/compose.yaml run --rm bd account-recover --email admin@
87
113
  从 OSS 控制台下载 ZIP(维护人员身份)或选择本地 ZIP。保持原工作区不动,先恢复到尚不存在的新目录,例如在维护用容器中:
88
114
 
89
115
  ```sh
90
- docker compose -f deploy/compose.yaml stop bd
91
- docker compose -f deploy/compose.yaml run --rm bd restore-backup --archive /backups/备份文件.zip --destination /workspace/restored
116
+ docker compose --env-file deploy/.env -f deploy/compose.yaml stop bd
117
+ docker compose --env-file deploy/.env -f deploy/compose.yaml run --rm bd restore-backup --archive /backups/备份文件.zip --destination /workspace/restored
92
118
  ```
93
119
 
94
120
  此时数据在 `/workspace/restored/content`,账号在 `/workspace/restored/.bd-auth`。将部署服务的 `command` 设置为 `["start", "--content", "/workspace/restored/content", "--hostname", "0.0.0.0", "--port", "3000"]` 后启动;账号恢复等维护命令也传同一 `--content`。应用会重新校验全部文件及关联、重建显示数据;恢复原 `BETTER_AUTH_SECRET` 后,已绑定成员重新登录,未完成激活的成员可重新签发邀请。重新配置并验证备份。确认事项、附件下载、权限和历史完整后,才处理恢复前的工作区目录。勿执行 `docker compose down -v`,它会删除持久卷。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@airalogy/airalogy-bd",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Business development workspace for local use and team collaboration.",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -18,7 +18,6 @@
18
18
  "dashboard/app/**/*.json",
19
19
  "dashboard/public/airalogy-logo.svg",
20
20
  "dashboard/eslint.config.mjs",
21
- "dashboard/next-env.d.ts",
22
21
  "dashboard/next.config.ts",
23
22
  "dashboard/postcss.config.mjs",
24
23
  "dashboard/tsconfig.json",
@@ -45,12 +44,13 @@
45
44
  "version:check": "node scripts/check-version.mjs",
46
45
  "validate": "node bin/bd.mjs validate --content fixtures/demo/content",
47
46
  "data": "node bin/bd.mjs data --content fixtures/demo/content",
48
- "dev": "node bin/bd.mjs dev --content fixtures/demo/content",
47
+ "dev": "node bin/bd.mjs dev --source --content fixtures/demo/content",
49
48
  "build": "node bin/bd.mjs build --content fixtures/demo/content",
50
49
  "lint": "node bin/bd.mjs lint",
51
50
  "test": "pnpm version:check && pnpm publication:check && pnpm validate && pnpm lint && pnpm build && node --test tests/*.test.mjs",
52
51
  "publication:check": "node scripts/check-publication.mjs",
53
- "test:package": "node tests/package-smoke.mjs"
52
+ "test:package": "node tests/package-smoke.mjs",
53
+ "test:dev": "node tests/dev-smoke.mjs"
54
54
  },
55
55
  "dependencies": {
56
56
  "@radix-ui/react-dialog": "^1.1.23",
@@ -1,6 +0,0 @@
1
- /// <reference types="next" />
2
- /// <reference types="next/image-types/global" />
3
- import "./.next/types/routes.d.ts";
4
-
5
- // NOTE: This file should not be edited
6
- // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.