docs: organize project guides and consolidate historical records
Community checks / verify (push) Skipped
Verify Frame Flow / verify (push) Successful in 4m49s

This commit is contained in:
渡口浪人
2026-10-18 17:59:20 +08:00
parent b1c41e91ea
commit e92a7a51fa
18 changed files with 225 additions and 564 deletions
+22
View File
@@ -0,0 +1,22 @@
# 文档目录
安装、连接及日常使用从[中文首页](../README.zh-CN.md)或[英文首页](../README.md)开始。本目录收录仍适用的功能、配置与开发说明;版本变化见[版本记录](../RELEASE_NOTES.md)。
- [自动拼图](AUTOMATIC_COLLAGE.md)
- [构建、缓存与 CI](BUILDING.md)
- [可选连接与扩展](EXTENSIONS.md)
- [厂商请求失败与未知写入处理](KOKONNA_RECOVERY.md)
- [Docker 与群晖安装](NAS.md)
- [照片来源配置](PHOTO_SOURCES.md)
- [照片来源与共享连接](PHOTO_SOURCE_CONNECTIONS.md)
- [公开源码与隐私边界](PUBLICATION.md)
- [真实画框测试步骤](REAL_DEVICE_TEST.md)
- [厂商接口研究概览](RESEARCH.md)
- [Synology Photos API 与来源迁移](SYNOLOGY_PHOTOS_API.md)
- [Ticktar 外部集成契约](integrations/TICKTAR.md)
- [厂商账号能力研究](research/KOKONNA_ACCOUNT_CAPABILITIES.md)
- [厂商内容订阅研究](research/KOKONNA_CONTENT_SUBSCRIPTIONS.md)
- [厂商本地控制研究](research/KOKONNA_LOCAL_CONTROL.md)
- [开发与贡献](../CONTRIBUTING.md)
- [安全问题反馈](../SECURITY.md)
- [第三方声明](../NOTICE.md)
-388
View File
@@ -1,388 +0,0 @@
# Gitea Actions production CD v1 (historical)
> This NAS production deployment procedure is retired. Current Gitea Actions
> only runs isolated verification; production uses the maintainer-specific
> Ubuntu workflow in `scripts/server-release.py`. For a new installation use
> the Docker Compose instructions in README.md. Filesystem/NFS photo sources
> are disabled; use Synology Photos API or WebDAV. The configuration below is
> retained for historical reference and must not be used for new deployments.
## Audit and adoption boundary
Production `docker-compose.yml` is unchanged: AMD64 image, UID/GID 10333,
`unless-stopped`, read-only rootfs, `/tmp` tmpfs, dropped capabilities, limited
logs, `/data` and `/config` bind mounts, default private bridge, and configurable
host bind/port. SQLite/images/generated/cache live under `/data`; accounts,
vendor sessions and configuration live under `/config`. Neither is disposable.
The optional photos mount is read-only and has supplementary group access.
Historical repository receipts mention `/volume1/docker/pigway-frame-flow/data`,
`/volume1/docker/pigway-frame-flow/config`, `/volume1/photo`, port 18787, and
container/project `pigway-frame-flow`. These are **confirmation candidates**, not
script defaults. The deploy action accepts only explicitly configured paths
that match the existing running container on the Runner's Docker daemon.
It rejects different projects, ports, unknown mounts, host/custom networking,
missing photos confirmation, or different user/restart policy. The deploy action does not create NAS host directories or migrate/adopt an unrelated
container. First-time directory creation is limited to the manual bootstrap below.
CI uses `ffci-*` projects, per-run image tags and named volumes, no host ports.
Its cleanup does not refer to any production resource. Production uses fixed
configured names and existing bind mounts, with `create_host_path: false`.
## Gitea configuration
Repository Settings → Actions configuration (private paths/addresses use Secrets):
| Variable or Secret | Value to explicitly confirm |
| --- | --- |
| `PROD_DEPLOY_ENABLED` | Initially `false`; change to `true` only after plan acceptance |
| `PROD_PROJECT` | Existing Compose project label; candidate `pigway-frame-flow` |
| `PROD_CONTAINER` | Existing container name; candidate `pigway-frame-flow` |
| `PROD_IMAGE_REPO` | Fixed local image repository; suggested `pigway-frame-flow` |
| `PROD_DATA_DIR` (Secret) | Existing absolute NAS host data path; no default |
| `PROD_CONFIG_DIR` (Secret) | Existing absolute NAS host config path; no default |
| `PROD_PHOTOS_DIR` (Secret) | Existing read-only photos source if present; otherwise empty |
| `PROD_WEB_BIND` (Secret) | Exact existing Docker HostIp (`0.0.0.0` or NAS LAN IP etc.) |
| `PROD_WEB_PORT` | Exact existing mapped port |
| `FRAME_FLOW_STORAGE_NAME` | Optional NAS display name for the local gallery; defaults to NAS |
| `PROD_STATE_VOLUME` | Dedicated new deployment journal volume, e.g. `pigway-frame-flow-cd-state` |
| `PROD_MOCK` | Explicit `true`/`false`, consistent with intended production mode |
| `PROD_WRITE_ENABLED` | Explicit `true`/`false`; preserve owner's existing write policy |
The state volume must be separate from application/CI storage. An existing
volume without the matching `frameflow.deploy.project` label is rejected.
Supplementary groups are read from the existing container; no host ACL changes.
Keep existing `DEBIAN_MIRROR`, `DEBIAN_SECURITY_MIRROR`, `CI_PIP_INDEX_URL`, and
`CI_PIP_FALLBACK_INDEX_URL` settings from Verify; CI/production builds share the
Dockerfile, pinned base, lockfile, and BuildKit caches.
Repository Settings → Actions → Secrets:
`PRODUCTION_ENV`: multiline **unquoted** `KEY=value` entries, without shell
expansion. At least:
```dotenv
FRAME_FLOW_TOKEN=<existing Frame Flow administrator token>
KOKONNA_API_KEY=<existing KoKonna key, or empty when mock>
```
Optional additional runtime secret variables can be included. No key values are
committed, passed to image builds, or printed. Nonsecret mock/write flags use
Variables. Other existing runtime environment values are retained. The script
sets commit/build time and internal data/config paths explicitly. Dollar signs
in secret values are escaped before Compose interpolation. Snapshots containing
old runtime secrets are stored only in a private journal file (0600, directory
0700) on the dedicated Docker volume; Docker administrators can access it.
Never upload that journal or a full Docker inspect as a public CI artifact.
## First safe trial
1. On NAS, inspect only the necessary fields (use existing Docker/sudo access):
```sh
docker inspect pigway-frame-flow --format '{{index .Config.Labels "com.docker.compose.project"}}'
docker inspect pigway-frame-flow --format '{{json .Mounts}}'
docker inspect pigway-frame-flow --format '{{json .HostConfig.PortBindings}} {{.HostConfig.NetworkMode}}'
```
Confirm the Variables/Secrets against these actual values, including photos.
2. Configure the Secret privately. Keep `PROD_DEPLOY_ENABLED=false`.
3. Manually run **Verify Frame Flow** on `main`, `deploy_action=plan`.
Verify must pass first. Plan checks resource identity, paths/port, required
Secret keys, current `/ready`, smoke endpoints and commit. It performs no
build, stop, restart, tagging, lock creation, volume creation, or data writes.
If no production Variables exist, it reports configuration missing and does
nothing; that is an unconfigured plan, not production acceptance.
4. Review `PLAN ONLY` output and arrange a maintenance window for the first real
deploy/restart. Set `PROD_DEPLOY_ENABLED=true`, manually run `deploy_action=deploy`.
5. After `DEPLOY VERIFIED`, subsequent pushes to `main` run Verify → deploy.
Pushes to other branches and pull requests never deploy. A manual run defaults
to plan, even when automatic deployment is enabled.
The deploy action supports updates to an existing healthy deployment. For first-time
creation use the explicit manual bootstrap flow below. No real production deployment or rollback drill has
been performed during implementation; those are first-run acceptance steps.
## Deployment transaction and rollback
1. Verify job must succeed completely, including isolated Docker tests/cleanup.
2. Deploy job checks out the same revision and prepares tools. An atomic
`docker create` reservation named `<PROD_CONTAINER>-deploy-lock` serializes
production changes on the daemon. Job `concurrency` is also declared, but
correctness does not depend on Gitea implementing it. A competing deploy
fails safely instead of changing production. No other job may remove a lock
whose owner label differs from its own.
3. Re-read the current baseline under the lock; confirm ready/smoke. Record exact
image ID, runtime Compose/environment, version/commit. Pin the old image with
an immutable rollback tag so normal dangling-image cleanup cannot remove it.
4. Refuse a stale checked-out `main` revision that no longer equals remote main.
Build an immutable `release-<commit>-<owner>` tag locally, without a registry
then point `latest` at the candidate; CI image tags are never changed.
5. Persist a `prepared` journal with old/new runtime configs. Create an additive
SQLite online backup under `/data/deploy-backups/<owner>.db`. No data/config
directory or file is removed, replaced or recursively chowned.
6. `compose up -d --no-build --pull never` replaces only the configured service.
Check `/ready`, the unchanged nine-endpoint read-only smoke test, and exact
`/api/v1/version` commit. Only all checks passing produce `DEPLOY VERIFIED`.
7. Any activation/verification failure runs `up` again with the saved exact old
image ID and old runtime environment/mounts, then repeats ready/smoke/commit
verification. A failed deploy remains a failed workflow even if rollback
succeeds. If rollback fails, the journal/lock are retained, failure is explicit,
and redacted scoped diagnostics are emitted.
8. An `always()` step uses the recorded owner to recover an interrupted prepared
transaction and release only its own lock. Abrupt host loss or termination of
the entire runner can prevent both handlers: inspect the journal/lock before
manually recovering; never automatically force-unlock an unknown owner.
Rollback is an **image/config rollback**, not an automatic database rewind.
User data accumulated during deployment remains. The SQLite backup is for
operator-reviewed recovery; destructive or backward-incompatible future schema
changes must not be auto-deployed without a separate migration/backup plan.
Baseline artifacts and additive backups are retained for the operator; there is
no automated pruning of production rollback history or data.
After enabling CD, use its workflow/script as the production lifecycle owner.
The old NAS checkout's Compose/.env files are not rewritten remotely by CD and
may describe an older deployment. Do not concurrently recreate production from
that old checkout. The repository's standalone Compose remains usable for an
independent deployment; the private journal records the CD runtime configuration.
## Actual commit and manual rollback
```sh
curl -fsS http://NAS_LAN_IP:PORT/api/v1/version
# Check `commit`, `version`, and `build_time` against successful deployment output.
docker inspect PRODUCTION_CONTAINER --format '{{.Image}}'
```
For a manual rollback: keep CD enabled and run **Verify Frame Flow** on `main`
with `deploy_action=rollback`. After Verify passes, the script locks production,
loads the last journal's `previous` image/config and verifies recovery. This is
last-baseline rollback, not an arbitrary image selector. Never use `down -v`,
volume pruning, or delete data/config to roll back.
If a failed run retained a lock, inspect only its owner label:
```sh
docker inspect PRODUCTION_CONTAINER-deploy-lock --format '{{index .Config.Labels "frameflow.deploy.owner"}}'
```
With the documented Variables configured in a trusted Docker-enabled shell:
```sh
FRAME_FLOW_DEPLOY_OWNER=<confirmed failed owner> CD_ACTION=recover python scripts/production-deploy.py
```
`recover` retries that owner's journaled rollback and retains the lock again if
recovery fails. If the very first attempt stopped before a journal was written,
confirm that the original image is still running and healthy before an operator
removes the stale lock. Do not delete a live lock or any persistence volume.
## First-time production bootstrap (explicit manual action)
The confirmed NAS residue is a `created`, never-started container with dead
`/workspace/way/...` bind paths. It is not an adoption/rollback baseline.
No migration from those paths is performed. Production Compose remains independently usable.
Set the ordinary repository Actions Variables below; set paths and addresses as Secrets (see docs/PUBLICATION.md):
```text
PROD_DEPLOY_ENABLED=true
PROD_PROJECT=pigway-frame-flow
PROD_CONTAINER=pigway-frame-flow
PROD_IMAGE_REPO=pigway-frame-flow
PROD_DATA_DIR=/volume1/docker/pigway-frame-flow/data
PROD_CONFIG_DIR=/volume1/docker/pigway-frame-flow/config
PROD_WEB_BIND=192.0.2.10
PROD_WEB_PORT=6005
PROD_STATE_VOLUME=pigway-frame-flow-cd-state
PROD_MOCK=true
PROD_WRITE_ENABLED=false
```
Leave `PROD_PHOTOS_DIR` unset/empty. Existing mirror Variables still apply.
Enabling CD does not enable real frame writes. Before the first successful bootstrap,
ordinary main pushes report `production not bootstrapped / bootstrap required`.
They cannot create production. `bootstrap` additionally requires the Actions event
`workflow_dispatch`; the default action remains `plan`. Every action is gated by
successful complete Verify on main.
Create repository Actions **Secret** `PRODUCTION_ENV` as multiline bare `KEY=value`:
```dotenv
FRAME_FLOW_TOKEN=replace-with-a-long-random-private-token
KOKONNA_API_KEY=
```
Do not add shell quotes, `export`, interpolation or spaces around `=`. An existing
KoKonna key may be supplied but first bootstrap forcibly uses Mock with writes off.
Optional application secrets/settings may be added in the same format; bootstrap
always overrides Mock/write flags, data/config paths, timezone and build identity.
This token remains useful for API/smoke checks even if Web UI uses account login.
Do not paste the real Secret into logs or repository files.
### Safety and cleanup
Bootstrap builds the verified main revision first, then acquires the same atomic
Docker daemon deployment lock used by deploy. Host path checks run in a short-lived,
network-disabled helper with **read-only** NAS root mounted, not CI workspace paths.
Synology does not automatically create missing bind sources with `-v`. A temporary
network-disabled helper mounts the explicitly configured existing parent directories
and creates only their data/config leaves, owned `10333:10333`, mode `0750`. It never
mounts NAS root writable, recursively changes parent permissions, or deletes contents.
Parents must already exist; missing parents fail closed. Nonempty directories, symlinks
(including ancestor symlinks), overlapping paths and unknown journal resources fail closed.
A same-name residue can be removed **without force** only after checking all of:
Compose project/service labels; `Status=created`; `Running=false`;
`StartedAt=0001-01-01T00:00:00Z`; exactly two bind mounts `/data` and `/config`;
and both old host sources absent. A running, previously started, unknown or data-bearing
container is refused. An existing default network must be owned by this Compose
project and contain no endpoints other than the validated residue.
The production service uses `create_host_path=false`, the explicit NAS LAN bind,
non-root UID, `unless-stopped`, normal bridge network and existing resource/security
limits. Acceptance runs ready, all read-only smoke endpoints, version/commit,
preflight mount/port/project/user/restart checks, one restart, repeated checks,
Docker health and exact built-image ID before `BOOTSTRAP VERIFIED`.
On failure after transaction preparation, cleanup removes only this transaction's
owner-labelled new container and its newly created, empty, project-labelled network.
The previously validated never-started residue has no rollback value and is not recreated.
**Data/config files, images/build cache and the private CD journal volume are retained.**
No `down -v`, volume prune or removal of unrelated/CI resources is used.
Cleanup failure retains the lock so the always recovery step can retry using the journal.
Only an explicitly dispatched bootstrap may retry a failed first-install journal, and
only when its project/container/mounts/port match, its volume ownership matches, and
target directories remain empty or absent. Prepared/success/foreign journals are refused.
On a new transaction, the prior journal is archived as `deploy.<owner>.json` inside
the private state volume before replacing the active journal; generated data is never
automatically emptied and journals are never deleted.
Abrupt host/runner loss still requires operator review of the lock/journal.
The journal is private (0700/0600) and may contain prior/candidate secrets; never export it
as an Actions artifact. First bootstrap has no prior healthy version to roll back to.
### First run and acceptance
1. In Gitea repository **Actions → Verify Frame Flow → Run workflow**, choose branch
`main`, action **plan**. This is read-only and reports bootstrap required for the
absent/created instance; it is not a bootstrap safety acceptance. Detailed host
residue/directory checks happen under the lock in bootstrap.
2. Run the same workflow on `main` with action **bootstrap**. Verify runs in full first.
No NAS bootstrap is executed merely by committing this implementation.
3. Require `BOOTSTRAP VERIFIED` in the deploy log. In Container Manager confirm
container `pigway-frame-flow` is running/healthy, user 10333, restart unless-stopped,
exact `/volume1/docker/pigway-frame-flow/{data,config}` mounts and
`192.0.2.10:6005` binding (not loopback).
4. Open `http://192.0.2.10:6005/api/v1/version`; its `commit` must equal the full
workflow checkout commit. Check `/ready` returns HTTP 200. The immutable image tag
is `pigway-frame-flow:latest`; compare its image ID in
Container Manager with the running container.
5. Keep `PROD_DEPLOY_ENABLED=true`. Subsequent main pushes Verify then deploy using
this same runtime and journal mechanism. The first update records bootstrap as
its rollback baseline. Repeating bootstrap against this instance is refused.
Enable real-device read-only access and write access only through separate explicit
operator decisions; no automatic change is made by bootstrap.
Docker tests are mocked locally. The first manual NAS Runner bootstrap, including
real host mounts and restart, remains the required live acceptance.
## Actions download transport
Verify and deploy reference official GitHub Actions directly, pinned to immutable
commits rather than moving tags:
| Action | Official upstream commit |
| --- | --- |
| actions/checkout v4 | 11d5960a326750d5838078e36cf38b85af677262 |
| actions/setup-python v5 | a26af69be951a213d495a4c3e4e4022e16d87065 |
The workflow uses explicit `https://github.com/actions/...` URLs so Gitea's
configured default Actions host cannot redirect downloads to the project owner's
server. Forks download Actions through their own Runner/network; no public action
mirror is served by this project. The former Tea auxiliary repository is private
and is no longer required by current workflows.
Keep the Runner's action cache and Python toolcache persistent. For Gitea Runner
versions supporting `cache.offline_mode`, use a private Runner configuration:
```yaml
runner:
file: /data/.runner
cache:
offline_mode: true
```
In the Runner's own Compose service (not the application), set `HOME=/data` and
`CONFIG_FILE=/data/config.yaml`, with `/data` already persisted. Before recreating
an idle Runner, back up its configuration and copy the existing action cache from
`/root/.cache/act` to `/data/.cache/act`. Preserve registration, labels, image,
mounts and networks; do not interrupt active jobs or recreate other services.
Verify cached actions against the pinned upstream commit and tree before reuse.
This is administrator configuration, not a public workflow dependency.
Offline reuse avoids refreshing cached actions from GitHub on each job. Moving
tags/branches may remain at the cached version; this workflow deliberately pins
immutable SHAs. A new action URL or commit requires an initial download or verified
administrator prewarming; an old mirror subtree is not automatically equivalent
to an upstream Git repository. Do not prune Runner caches between jobs. Python
toolcache misses still download Python from its upstream release source. Network
failures remain failures, never reasons to skip validation or silently fall back
to the owner's Tea server.
Administrators needing a mainland-specific download route can configure their
own Runner/network cache privately. Such settings must not introduce public
workflow references to a personal mirror. This change does not modify NAS VPN,
proxy, firewall or other applications. All validation and deploy gates remain.
### Synology Photos dependencies
For a production photo source using Synology Photos person filtering, configure
`SYNOLOGY_PHOTOS_URL` and `SYNOLOGY_PHOTOS_CERT_SHA256` as Gitea Secrets. The
certificate fingerprint must match the configured HTTPS endpoint. Keep the Photos
session in the persistent `/config` directory; never put session credentials in
Variables or repository files.
`PROD_PHOTOS_DIR` must identify the actual NAS photo directory mounted read-only
at `/photos`. Adoption requires that mount to exist on the current container;
changing this Variable alone does not create a new mount. Existing supplementary
permission groups are preserved by deployment.
Restoring SQLite and session files does not restore these runtime dependencies.
Production smoke checks now reject an enabled people-filtered source if its
Photos configuration or stored connection is missing. These checks do not prove
session validity or scan the complete catalog: after restoring a source, also
verify its read-only `/api/v1/photo-sources/{id}/images?limit=1` endpoint before
running an automation task.
### Advisory-service network resilience
CI dependency installation uses the domestic `CI_PIP_INDEX_URL` first and the
`CI_PIP_FALLBACK_INDEX_URL` sequentially on failure. These package indexes do not
replace PyPI's vulnerability JSON API.
`python scripts/ci-audit.py` retains the pinned `requirements.lock`, PyPI advisory
service and `--no-deps --disable-pip` checks. It uses a 60-second socket timeout,
at most three attempts, and 5/10-second backoff only for network failures. Known
vulnerabilities, malformed/incomplete reports and skipped dependencies fail
immediately. Every attempt has a five-minute process limit. A timeout or failed
final attempt still blocks deployment.
The advisory HTTP cache is reused within the job (including retries) and follows
the audit client's normal HTTP freshness rules. It is not a permanent offline
snapshot or a cross-job cache. Raw network exceptions are omitted because proxy
URLs may contain credentials. Logs identify the advisory host and whether the
complete audit succeeded.
### Production image retention
Production uses `pigway-frame-flow:latest`. Builds first create a unique release
image, then tag it as latest before activation. The old image is pinned during
an update so a failed deployment can restore it. Only after the new version
passes verification are old release/rollback images and duplicate tags removed.
After successful deployment, only the current production image remains; there
is no retained historical image for manual rollback. Rebuild a historical
revision before manually reverting a successful deployment.
Images referenced by other containers (including stopped containers), images
with unrelated tags, and CI resources remain protected. Cleanup never prunes
volumes, data, or shared build cache. Cleanup failure is a warning and does not
roll back a verified deployment. Failed deployments do not run cleanup.
-7
View File
@@ -1,7 +0,0 @@
# v0.1.11
照片底部单行按“日期 · 已命名人物 · 主题 · 地点 · 文件名”排列,空项省略,人物之间也使用 ` · `。主题、日期和地点沿用最近的日期文件夹解析;没有结构化日期目录时仍保留文件名。人物来自 Synology Photos 已命名人物相册的实际图片归属,按账号会话和空间缓存 15 分钟,不显示未命名人物编号。人物查询失败时保留图片及其他描述。
新建照片源默认开启底部文字,既有来源保留明确设置。横向来源继续同时约束选图和生成画布,不拉伸图片。更新来源表单说明与浏览描述顺序。
使用既有 Ubuntu Server 发布流程,备份配置、数据库与 Compose,从提交源码构建并核验部署哈希;失败恢复旧 Compose。发布过程不主动切换真实画框,不重绘历史图库图片。
-5
View File
@@ -1,5 +0,0 @@
# v0.1.12
修复临时展示到期或手动恢复后,“上一张图片”仍指向当前图片,导致已确认删除仍被恢复保护拦截的问题。只有设备已确认同步到受管理的当前图片、且没有基础恢复目标、临时展示或待确认写入时,才清除这条自身引用;不同图片的有效恢复引用继续受保护。既有残留引用在读取设备状态或删除校验时自动修正,不需要强制删除图片或重置数据库。
有效恢复引用仍拒绝删除,并通过结构化原因显示中英文提示。保留当前图片删除确认,不主动删除照片或切换画框。
-3
View File
@@ -1,3 +0,0 @@
# v0.1.13
照片底部同时显示所有已识别且已命名的人物,人物之间使用 ` & `;日期、人物、主题、地点及文件名之间继续使用 ` · `。例如 `2026-10-18 · Alice & Bob · Family · one.jpg`。人物仍来自 Photos 实际相册归属,未命名人物不显示;历史生成图片不自动重绘。
-5
View File
@@ -1,5 +0,0 @@
# v0.1.14
底部文字仅显示日期、已命名人物(使用 & 连接)、文件夹主题及地点,不显示原始文件名。原始文件名仍用于图库和诊断记录。
上传传输区分明确的 DNS/连接建立失败与已建立连接中断:前者尚未发送 HTTP 写入,最多重试三次,失败后结束该次操作,不进入阻塞后续写入的 UNKNOWN;读超时或连接中断等不确定结果继续保留核对保护,不盲目重放上传。既有未知操作通过只读设备/图库核验后使用原有 acknowledge 流程关闭,保留原始错误和审计记录。
-9
View File
@@ -1,9 +0,0 @@
# v0.1.15
自动照片、拼版、模板及数据模板任务在上传失败后,持久保存同一张暂存图片,并在下一次计划之前安排最多 5 次额外重试。间隔按 1、2、4、8、16 权重递增,随剩余窗口缩放,计划时间集中在窗口前半段,为上传与设备同步留出时间。重试不移动原定计划,也不复用旧操作 ID;每次独立记录操作及事件。成功后取消剩余重试,重启后沿用已有计数与截止时间;停用任务不再追加重试,删除任务取消其重试计划。
若额外重试均失败,下一次计划仍先上传同一张图;若这一次仍失败,只删除该任务未入库、未星标的生成缓存,再按照片源生成并上传新图。NAS 原照片、用户上传文件和成功图库图片不由此流程删除。新图仍失败时,进入它自己的下一轮恢复窗口。
上传结果未知不再阻塞后续独立上传。每次重试前先只读核对设备及云图库,精确确认已成功的上传不再重传;需继续尝试时关闭旧尝试并保留错误和核对审计。删除、恢复及自动清理仍保留各自的保护条件。重试窗口到期后不再启动额外上传,待同步尝试经核对结束后交给原计划执行。
任务生成图片先保存在缓存,确认任务成功后才进入本地图库;失败不会产生看似成功的本地图库记录。额外重试仍归属原任务的云端保留规则,任务列表显示最近尝试结果。
-12
View File
@@ -1,12 +0,0 @@
# v0.1.16
统一 PIGWay 品牌写法,优化图库、自动化、历史记录、设置、连接中心和拼图页面布局。
- 图库直接点击图片查看,移除重复的查看按钮;缩略图底框为正方形,卡片宽度适配单行操作按钮。
- 全站共用更宽的内容区域,宽屏图库可一行显示三张卡片;搜索、排序、来源和任务筛选合并排列。
- 自动化与历史记录状态改为仅保留颜色的文字,优化列宽与操作对齐。
- 设置与鉴权信息保持左右并排,鉴权卡片内部信息改为单列;相关设置控件紧凑排列。
- 连接中心和自动拼图短字段合并排列,按钮按内容宽度显示,空结果提示不再占据额外空间。
- 窄屏自动换行,保留图片预览、长文本和表格所需空间。
本轮界面检查覆盖 11 个主页面、本地图库及弹窗,中英文、明暗主题和四种屏幕宽度共 289 项布局检查通过;隔离环境拼图流程 8 项检查通过。生产部署后的界面复查使用隔离数据,没有执行真实画框写入。
-11
View File
@@ -1,11 +0,0 @@
# v0.1.17
- 总览预览改用原图,避免放大低分辨率缩略图。
- 云端图库缩略图升级为最大 860×860,等比缩放、JPEG 质量 88;原位替换旧缓存,仍只保留一档。点击放大继续读取原图。
- 照片源新增最小短边、最小长边参数,同时检查源照片和实际取得的预览尺寸,默认 0 不限制。
- 本地图库显示 NAS 原照片完整路径并支持换行,保留原文件名大小写和后缀;历史四张图片已按照片 ID 核实并补齐来源。
- 自动化新增“目标相框”列;历史记录的状态、结果、调用方及操作按钮垂直居中。
- 左上角统一显示 PIGWay Frame Flow,移除图标和重复品牌前缀。
- 设置与鉴权保持左右并排、卡片等高,鉴权内部单列。图片预览弹窗保留原有布局。
不修改 NAS 原照片,不主动切换真实画框。清理仅针对项目临时构建物及过期镜像,保留持久数据和近期回滚资源。
-6
View File
@@ -1,6 +0,0 @@
# v0.1.18
- Synology Photos 列表显式请求照片方向信息;按 EXIF 旋转后的宽高筛选横向、竖向和自动方向,避免存储像素为横向的竖拍照片误入横图来源。
- 渲染前复核实际取得图片的 EXIF 方向;若元数据或缓存预览与来源方向不符,则跳过该候选。显式选择方向不符的照片时返回明确错误。
- 保持既有水印和铺满布局,不修改 NAS 原照片、来源设置或现有图库;修复不自动重新生成、上传或切换已显示图片。
- 源码及镜像保留 LICENSE、NOTICE;公开验证只使用合成照片和通用示例,私有部署参数与回执保存在仓库之外。
-31
View File
@@ -1,31 +0,0 @@
# PIGWay Frame Flow v0.1.5
## 简体中文
- 图片仅在真实图片区域内居中显示加载动画,无页面骨架、虚构图片卡片或人为展示延时;请求及解码完成后立即显示,失败时显示局部提示。
- 图库搜索、排序、卡片操作及写入保护先于图片请求初始化,复用真实列表元数据;本地任务筛选异步填充,不阻塞其他控件。
- 手动拼版改为并行加载,各图独立完成或失败;固定区域容器保留坐标和拖动交互,加载前后位置一致。
- 修复手机底栏文字裁切、窄屏页头拥挤和横屏导航可达性,支持底部安全区域,补齐表单标签和当前导航无障碍状态。
- 默认对外访问端口改为 **6005**。本地启动、Compose、测试地址及文档同步;容器内部仍监听 18787。
### 验证
本地 505 项 Python 测试、Ruff、格式检查、mypy、JavaScript 语法和差异检查通过。
浏览器回归:布局 305 项、图片加载 45 项、图库加载顺序 14 项、手动拼版 31 项通过。
先行 UI 部署的生产静态文件哈希、health/ready 和拦截测试数据下的浏览器交互已验证;
不代表真实 AI 生成、画框写入、手机实机或软键盘测试。
### 升级说明
已有安装须更新私有环境配置中的 `WEB_PORT=6005`,并重建服务后生效。
自动部署的 `PROD_WEB_PORT` 必须与现有实例的映射一致;仅修改该变量不能迁移端口。
NAS 附件是源码部署包,需自行构建 Docker 镜像,不含密钥、运行配置、数据库或私人照片。
## English
Image loading indicators stay inside real image regions, without page skeletons or artificial delays.
Gallery controls initialize before image requests. Manual collage images load independently in parallel,
with stable regions and working coordinate/drag controls. Mobile navigation, safe-area spacing and form
accessibility are improved. The default published port is now **6005**, mapped to container port 18787.
Existing installations must update their private port configuration and recreate the service.
NAS source package and SHA256 checksum are included; this is not a prebuilt Docker image.
-29
View File
@@ -1,29 +0,0 @@
# PIGWay Frame Flow v0.1.6
## 简体中文
- 图库使用具体目的地标签:`KoKonna 云端图库` 与 `<NAS 名称> 本地图库`,NAS 名称通过 `FRAME_FLOW_STORAGE_NAME` 配置。
- Settings API 增加目的地元数据,标签仅展示连接已配置、明确支持保存且存在适配器的目的地;全局写入保护保持独立。
- 后续网盘须实现读取/保存适配器并完成连接后才能加入标签栏,显示具体服务商/实例名称。当前只读照片来源不会作为保存目的地展示。
- 长标签在手机上换行,避免整页横向溢出;中英文保持相同目的地身份。
- Compose 和自动部署透传 NAS 展示名称;分支 CI 完整验证后发布标签,避免相同提交的标签推送重复占用构建队列。
### 验证
本地 507 项 Python 测试、Ruff、格式检查、mypy、JavaScript 语法检查通过。
图库目的地标签与能力过滤 18 项浏览器检查通过;覆盖 320–1440 像素、中英文、明暗主题和长 NAS 名称。
本次不增加任何网盘写入功能,不改变画框写入策略。
### 升级
Compose 设置 `FRAME_FLOW_STORAGE_NAME`;Actions 设置同名仓库 Variable。
名称只描述实例,不作为路径或授权凭据。未设置时回退为 NAS。
默认访问端口仍为 6005,容器内部端口仍为 18787。
NAS 源码包与 SHA256 附件不含运行配置、密钥、数据库或私人照片,需自行构建镜像。
## English
Gallery tabs identify the concrete destination: KoKonna cloud gallery and the configured NAS name plus Local gallery.
Destination metadata includes connection and upload capabilities; only implemented writable adapters are shown.
Existing read-only cloud photo sources are not presented as save destinations. Long labels wrap on mobile.
Set FRAME_FLOW_STORAGE_NAME in Compose or the Actions repository Variables. No cloud-drive write support or device write policy is changed.
-24
View File
@@ -1,24 +0,0 @@
# PIGWay Frame Flow v0.1.7
## 简体中文
修复首次打开图库时内容区空白、必须等待云端图片列表返回才出现控件的问题。
- 目的地标签、搜索、排序、刷新和上传按钮立即初始化,图片列表独立请求。
- 仅在工具栏提示正在读取列表;未知数量时不生成图片卡片,不提前显示“图库为空”。实际图片仍在自己的区域内独立加载。
- 启动使用轻量设备身份目录,完整设备状态在后台更新,避免厂商状态请求阻塞首屏。
- 慢请求期间可以切换到 NAS 图库;过期响应不会覆盖当前页面。
- 列表失败时保留控件并在工具栏显示错误,仍可刷新或切换目的地。
- 保留等待期间输入的搜索词和排序选择;本地任务筛选请求在同一次导航内复用。
### 验证
本地 508 项 Python 测试、Ruff、格式检查、mypy 和 JavaScript 语法检查通过。
新增首次未缓存列表的控件就绪、输入保留、慢云端切换和列表失败回归。
不增加图库列表的服务端缓存,不修改厂商请求重试、照片、生成内容或设备写入策略。
## English
Fix the blank gallery on its first uncached visit. Destination tabs and gallery controls initialize before metadata requests complete.
Slow or failed cloud listing does not prevent switching to NAS storage. Search and sort choices survive list arrival, and stale responses cannot replace the active destination.
Only a small toolbar status indicates metadata loading; real images keep independent loading indicators.
-13
View File
@@ -1,13 +0,0 @@
# PIGWay Frame Flow v0.1.8
增加 NAS 本地图库反选、放大总览图片,并统一图片查看器与界面表达。
- 反选只切换当前页可见图片的勾选状态;隐藏勾选项的批量操作范围明确提示。
- 总览当前图片预览增大,点击或键盘打开与图库相同的查看器,读取原图并支持适应屏幕、原始尺寸和 Esc 关闭。
- 修正图库排序、播放顺序、型号信息来源、云端确认状态等标签,补齐天气与连接状态翻译。
- 区分本地与云端删除影响,解释星标保留规则,避免对未知来源作无依据判断。
- 修正数据源空态、路径与凭据说明;同步 README 和操作文档中的共享 Photos 登录机制与入口。
验证:305 项布局检查、8 组星标与反选检查、12 组总览查看器检查、45 项图片加载检查及新增中英文文案检查通过。全套后端与静态检查由本次发布流水线再次验证。检查不涉及真实照片删除、设备写入或收费 AI 调用。
Improve NAS gallery selection, dashboard image viewing and UI wording. Invert selection affects visible items on the current page. Dashboard previews open the same full-image viewer as the gallery. Storage destinations, deletion scope, server-side stars, cloud confirmation and shared Photos credentials are clarified in both languages.
-19
View File
@@ -1,19 +0,0 @@
# v0.1.9
照片来源通过 Synology Photos API 按账号权限读取,共享/个人空间、人物 any/all 筛选和有界 XL 预览缓存可用。生产拒绝文件系统照片来源及 /photos 挂载;本地上传、生成图片和 Server 本地图库继续保留。NAS 原图下载接口曾被拒绝,本版不宣称支持原图下载。
自动化新增 1~10080 分钟的真实间隔,跨整点与跨天不按 Cron 字段重置,既有 Cron 任务保持原样。显示时长明确为到期恢复期限。统一来源快捷创建任务编辑器,改善登录及来源表单响应式布局、设备显示名与历史记录中英文;诊断详情保留原始标识。
## 生产部署
生产已迁至 Ubuntu Server,由 systemd 管理 Docker;业务、Docker 数据和恢复资料位于 T7,并有 UUID 与挂载依赖保护。NAS 旧 Frame 专属资源已清理且独立复核 PASS。CI 保留隔离验证,移除 NAS 自动生产部署任务,不再向 NAS 发布。
正式发布使用 scripts/server-release.py:仅在既有 Ubuntu Server 环境运行,从已提交源码包构建,校验依赖锁、源码哈希、T7 UUID、容器安全约束和真实写入设置;备份 SQLite、配置及 Compose 后切换镜像,失败恢复旧 Compose,不自动回写旧数据库。它不执行上传、显示、删除或恢复图片等设备操作。成功后记录正式提交号、保存源码包及审计回执,删除本次暂存目录;白名单内的 Frame 旧迁移输入归档到本次 recovery,清除无恢复引用的临时镜像别名,共享 Console 资料不动。旧镜像及历史恢复资料保留供回滚,不执行全局 prune。
脚本要求由 git archive 生成的源码放在 <FRAME_FLOW_ROOT>/migration-inbox 的独立子目录;目录内同时提供 RELEASE_COMMIT、RELEASE_HASHES.json 和原始 source.tar.gz。哈希清单涵盖源码与源码包,不含自身。执行 sudo python3 <暂存目录>/scripts/server-release.py;成功后读取 <FRAME_FLOW_ROOT>/apps/pigway-frame-flow/release-verification.json 并独立检查线上接口。
## 验收范围
完整后端测试、静态检查与桌面/平板/手机的中英文浏览器回归纳入发布检查。线上历史补丁已核验,真实写入保持开启;本轮正式发布不重复真实设备写入测试。隔离浏览器验证与真实设备写入证据由维护者私下保管。
局域网 HTTPS、独立加密备份及恢复演练仍是后续工作;T7 recovery 不属于独立备份。没有执行 USB 断连、服务器重启或压力测试。