Commit Graph
12 Commits
Author SHA1 Message Date
tamakyi 770e752a7a 图片恢复支持对象存储(R2);专题也改成归人不归数据集
R2 上的图怎么救:库里的行没了就只剩桶里有那些键,不列桶无从得知它们叫什么。
给 internal/media 加了 ListObjects(ListObjectsV2 + SigV4 + 自动翻页 + XML 解析):
- 路径式访问、请求只到桶;查询串必须**先百分号编码再签名**(canonicalQuery 按原样取
  RawQuery,两边得是同一份字节,prefix 里的 / 要写成 %2F)。
- ⚠️ R2 的 API Token 默认只给对象读写,没有 s3:ListBucket 就 403。列桶失败**不让整个
  恢复失败**:本地那半照救,原因进 Warnings、页面用红色提示条显示(否则站长会以为恢复完了)。
- 候选对象 = 本地目录 ∪ 桶里 .webp(同键以本地为准);行的 storage 按「对象实际在哪」写,
  bytes 用桶里报的 Size。另加一条 warning:挂回了却没配 s3_public_base ⇒ 行有了页面空白,
  这比「没恢复」更难懂。

专题(用户拍板「一并做」):topics.dataset_id 同样带 CASCADE,删数据集带走专题,而专题
只存在这张表里、没有恢复来源。外键摘掉,所有查询 dataset_id → user_id(loadTopics、
topicPage、保存/删除/开关、pageBase.HasTopics);**内容仍照当前生效数据集算**
(topicContent 不动)——变的是「这份定义归谁」。Dataset 补 UserID 供前台按属主定位
用户级数据;管理专题不再要求有生效数据集。

导出链路未改动:place_images / topics / Dataset.UserID 都不参与 .rondbackup 导出,
全量验收(含导出保真、ZRAW 夹取、编号对齐那批)PASS=331 FAIL=0 SKIP=0。
2026-09-30 23:31:17 +08:00
tamakyi 881f2933ff 收尾:验收脚本自动清死元组、城市圈首末到访按可见到访算、补使用说明
verify.sh:测试库 ≥ VACUUM_MIN_MB(默认 200MB)时先 VACUUM (ANALYZE)——一轮全量会留几百 MB
死元组,级联删除随之变慢(同一夹具用例实测 13.6s → 10.2s)。只用普通 VACUUM:FULL 要
ACCESS EXCLUSIVE 锁,有别的服务连着测试库时会把验收整段卡住。

/api/cities 的首末到访改成按可见到访的到达时间算(内层 min/max(v.arrival)),不再取
places.first/last_visit_at——那两列是全量的,会被已并入 / 子段的到访推早推晚。

README 补两节:「数据编辑页上的重复到访」(判定口径与清理范围)、「为什么有些到访在页面上看不到」
(已并入 / 子段不计入显示与统计,但导出必须原样带着),并在开发提示里记下验收环境的死元组与
is_active 两个坑。

回归:city_agg_test.go 补了一段能区分的断言——把某地点最晚那次到访标成已并入后,城市最近到访
必须从 09-13 退到 09-08(原先只比对同口径时,两种算法在夹具数据上结果一样,是条假绿的断言)。
2026-09-29 23:49:39 +08:00
tamakyi 3d03aae018 修地图城市圈的聚合口径:先按地点汇总,再按城市汇总
/api/cities 原来把聚合打在 places ⋈ visits 上:一个地点有 N 条到访,它的 visit_count 与
dwell_minutes 就被累加 N 次,count(*) 数出来的到访条数又被当成「地点数」显示——实测最大的
那个城市气泡写着「到访 72661 次 · 568 个地点」,真值是 568 次 / 86 个地点(差 128 倍)。
改成内层按地点 GROUP BY、外层按城市 sum/count,并补上「已并入 / 子段不算数」的判据,
圈的位置、排序与返回列序都不变。

回归 city_agg_test.go:手写同口径 SQL 对账 + 「地点数不可能多于到访数」的不变量;
变异验证(sum(pa.visits) *2)立刻红。
2026-09-29 22:07:23 +08:00
tamakyi 4597047989 口径:已并入 / 子段的到访不再计入时间线与统计(导出侧一个字节不动)
真机里两行到访可能「不独立成立」:ZMERGEDTO 指向它被并入的那条、ZPARENT 说明它只是某个
父段的一部分。app 对这两种行既不显示也不计数,本站以前当成普通到访 ⇒ 时间线上出现
「同一时刻同一地点两条」、日停留重复计入(实测数据集 9 有 64 条,26 条到达时间与原件相同)。
这些行**不能删**——导出要靠它们认这次合并发生过,所以判据只立一份 stats.SoloVisitSQL,
在读的一侧收口:visitsWhere / VisitsByPlace / Bookmarked / placeCols 子查询、首次到达城市、
地图极值点、专题(详情 + 列表批量)、三处聚合的 visit_count 与 dwell_minutes,
外加 schema.sql 一段幂等回填把存量库拉正。

天气与位移**不收口**(那几小时、那段路真实发生过);导出侧一个字节不动(rond 只读
places.last_visit_at,保持全量,压根不读 visit_count / dwell_minutes)。编辑页照样列出
这些行,但打上「已并入 #562 / 子段 #374」,免得以为数据丢了。

顺带修两个自测抓出来的问题:
- ingest 的地点聚合回填排在 insertEntityRaw 之前 ⇒ 判据读到空留档 ⇒ 每行都算独立到访
  (整整多算一个「已并入」的量)。
- 收口后 last_visit_at 保持全量,会凑出「0 次却有最近到访」(数据集 9 有 4 个地点),
  展示侧按可见到访数兜住。

验收:304 PASS / 0 FAIL / 0 SKIP(新增 3 个用例:标记后导出仍带该行、存量回填拉正、
判据只出现在读侧)。
2026-09-29 21:15:25 +08:00
tamakyi b4c2a8452f 审计修复:后端(安全 / 数据一致性 / 性能)
audit-2026-09-21.md 里的后端条目落地。每条都配了回归守卫,并逐条做过变异验证
(注入原 bug → 确认按正确理由变红 → 还原 → 变绿)。

安全
- CSRF 只加同源 Origin/Referer 守卫(csrf.go),不动模板
- 会话 cookie 的 Secure 按请求判断;两步验证两闸(loginGuard + 验证码一次性)
- 跳转收口到 safeInternalPath;clientIP 只认 XFF 最后一段
- GPX 按属主圈定且查 RowsAffected;下载名走 downloadDisposition
- 上传口统一 MaxBytesReader;落盘后的失败路径清掉半成品

数据一致性
- 区域判定两端各过一遍再 AND(apiTrack 与 movementsWhere 对齐)
- Filter.Verdict 全域一致(下推到 visitsWhere);聚合刷新必须返回 error
- 附属数据改挂坐标键,Go 与 SQL 两套表达式逐位一致
- 脏备份的伪时间/越界坐标不再进领域模型;rows 循环统一 drainRows
- 合并与导出:writeRawRow 上抛错误、悬空引用清理、原生列补全

性能
- placeCols 相关子查询带 dataset_id 前导列;findSourceArchive 先按大小筛
- 批量勾选改 ANY($3::bigint[]);fillupCache 加上限;同一查询不再查两遍

另:新增「全新库」冒烟测试 —— 空库跑完 Migrate 再用应用侧读查询真打一遍,
迁移块排到依赖表之前这种错只有新库会炸,老库毫无症状。
2026-09-24 20:37:16 +08:00
tamakyi 82e63412c0 类别显示名可自己维护,顺手把两套对不上的中文名合成一套
你要改的那个「海滩」原来根本不在数据里——它是 Go 里硬编码的 map,所以改不动。
更糟的是这样的 map 有**两张**,而且对不上:

  MKPOICategoryFoodMarket   菜市场(编辑页)  /  食品市场(补全页、GPX)
  MKPOICategoryCafe         咖啡馆              /  咖啡厅
  MKPOICategoryFitnessCenter 健身房             /  健身中心
  外加 ATM / Atm 大小写各写一份、一条永远匹配不上的 MKPOICategoryMarina2

现在合成一张内置表(42 条,冲突处取编辑页那套),并在它上面加了一层站点覆盖:

- 新表 category_labels(value, label),站点级、不挂 dataset——值本身才是稳定键
- 端点 POST /admin/edit/category/label;传空 label = 删掉覆盖行、恢复内置默认名
- 类别台账那行改成两个带标签的输入框:
      导出值 [MKPOICategoryBeach]   ← 会跟着导出写回手机
      显示名 [               ]      ← 只影响站内显示,placeholder 写着默认值
  是 MKPOICategory 枚举但内置表里没有的,会提示「填一个中文名」,这就是你要的补全入口

**显示名绝不写进 places.poi_category**——中文跟着写进去就把导出数据污染了,
专门加了 TestCategoryLabelNeverTouchesValue 钉这条。显示名会贯穿到所有中文名的地方:
编辑页/照片页/补全页的下拉、补全页「在用」标签、访客地点页、GPX 的 desc。

连带删掉两个绑在旧表上的模板函数 catName / poiname:模板里算不出显示名(要读站点覆盖),
改成在 Go 侧算好塞进数据(FillupRow.CatLabel、PlaceData.CategoryLabel)。
2026-09-20 10:54:51 +08:00
tamakyi 30c502ce7b 备份与迷雾的差异分析、合并执行,附属数据改挂坐标键
备份(.rondbackup)与迷雾(.fwss)各加一层「先看差异再动手」:

- 迷雾:上传先出差异页,说清叠加能补多少、整体替换会丢多少,并在真实底图上
  用绿/灰/红标出会新增 / 不变 / 会丢的区域
- 备份:与当前数据集按 UUID 逐条比对(rond 每次导出都会重排 Z_PK,编号认不出人),
  新增合入、冲突逐条选、仅站内有逐条勾选删除,全在一个事务里执行;
  合入的行写回 entity_raw,保证再传同一份备份时差异归零
- 地点按坐标对齐:站点的「补全地址」会把地点改名,拿名称当键会让一整个地点的
  到访全变成假冲突
- 附属数据(备注/结论/访客票/图片)从 dataset_id+src_pk 换成坐标键,换数据集不再失联;
  访客票没有 dataset_id,回填按活跃数据集认领
- 修正 contentHash 拿 Z_PK 当指纹的隐患,以及两处「src_pk 跨快照稳定」的错误注释

导出格式(.rondbackup / .fwss)保持原样,往返测试通过。
2026-09-19 16:04:00 +08:00
tamakyi 96e76318ab 修复访客在地点详情页看不到「图片」按钮
全屏画廊的地址列表原先只从 #imgs-grid 反推,而那个缩略图墙整块包在
{{if .IsAdmin}} 里——访客页根本没有这个元素,于是 syncGallery() 数到 0 张,
把服务端已经渲染好的「图片 N」按钮 remove 掉(表现成刷新后按钮闪一下就没了)。
站长自己打开一切正常,所以只有按访客身份渲染才看得到。

首版 b327bc1 就有,不是新引入的。

- 新增 PlaceData.ImageURLs:随页面把地址列表发给浏览器,访客页自带数据源。
- cellURLs() 的判据改成「缩略图墙在不在」,而不是「墙里有几张」:
  站长把图删光时墙还在、只是空了,按张数回退会把删掉的图又数回来。
- 新增回归 TestVisitorPlacePageCarriesImageURLs:按访客身份渲染详情页,
  要求页面里有「图片」按钮、且把图片地址发给了浏览器(去掉数据源即失败)。

实测(390 访客,/places/2254 三张图):按钮回归、点开 1/3 → 2/3 → 回绕 3/3 →
关闭正常,第 2 张 1200×900 实际加载;320/390/430 横向溢出均为 0。
2026-09-18 19:42:52 +08:00
tamakyi 002755129d 筛选在列表→详情→编辑之间保留,修复编辑页翻页丢筛选,收拾移动端触控与字号
- 新增 ?back= 贯穿链路:列表页(地点库 / 时间线 / 统计 / 专题地图 / 主页)生成详情链接时
  带上当前完整地址,详情页的「返回」「编辑」与编辑页的返回按钮据此回到原来那份筛选结果。
  只放行站内路径(挡 //host、伪协议、控制字符),参数编码走 template.URL 避免二次转义。
- 修 EditData.PageLink 把 & 手工写成 & 又被模板转义一次的 bug(&)——
  参数名会变成 amp;vpage,表现为「带筛选时翻页没反应、筛选还丢了」(既有问题)。
- 编辑页三个筛选表单与三个「重置」带上 back(重置改走 EditData.EditLink,各清各的,
  顺带修掉搜索词含 & 或空格时重置链接被拆坏)。
- 详情页「在地图中查看」的地点名改走 QueryEscape(名字含 & / # 会拆坏地址)。
- 窄屏修正:把被基础规则压掉的 .chip / .btn / .check 覆盖挪到最后;
  checkbox 20px、select 44px、file/color 字号 16px(iOS 聚焦不再自放大整页)、
  .tag 12px、导航 logo 触摸区 44×44。
- 新增回归 internal/web/pagelink_test.go(翻页链接、返回文案、地图链接)。
2026-09-18 19:03:50 +08:00
tamakyi ad2531c113 修复图片上传分类无法新增、潜在movementWindow容差问题、404页面未生效问题 2026-09-18 17:06:22 +08:00
tamakyi fd23560bab 优化移动端显示,解决筛选项潜在问题 2026-09-18 15:42:07 +08:00
tamakyi b327bc1230 first release 2026-09-18 13:05:49 +08:00