Repository navigation
Releases
v2.1.0
v2.1 全新设计了网页 UI:房源浏览、账号设置和管理后台统一成收件箱式界面,公共页面
换成单独的外壳,并补齐手机端、键盘操作和中英文文案。另外区分了官方站点与自部署
副本,简化了本机自用的启动方式。监控、抓取与预订逻辑没有变化;OurDomain、
OurCampus 与 Xior 的预订验证移到 v2.2。
全新设计的网页 UI
-
收件箱式工作区(e52a89a)
收件箱、日历、地图和统计共用「侧栏 + 列表 + 详情」的外壳,首页就是收件箱,
未登录时以访客身份进入。普通用户可以在「我的匹配」和「全部房源」之间切换,
已读状态按用户单独保存。旧的/listings列表页已删除。 -
账号设置与管理后台(e52a89a)
账号设置按分组和条目编辑筛选、通知、账号与偏好。用户、公告、运行设置、客户端、
数据健康、日志、崩溃和系统信息页迁到同一外壳,公告管理拆成独立页面;运行设置
区分已保存、已应用、被环境变量覆盖和需要重启。 -
登录、分享、邮箱验证、错误页、帮助、法律、赞助和使用指南改用公共页外壳。
使用指南按新界面重写。字体、图标与 Chart.js 改为自托管,CSP 随之收紧。 -
手机端与可访问性(cb04487)
手机侧栏关闭时不再进入 Tab 顺序,展开时锁定焦点,Esc 关闭并回到菜单按钮;
房源和用户详情在刷新、返回时保持正确状态;日历窄屏完整显示「今天」,日期的
辅助名称标明今天;登录密码字段使用独立标签。 -
数据健康的原因说明、英文房源状态(
Book显示为 Available)、邮箱验证页、
登录失败与限流提示、用户管理提示都按界面语言显示。登录失败后保留原本要去的页面;
启停、调整用户优先级后继续选中该用户。分享页不再显示占位的入住日期。
自部署
-
不在
flatradar.app上运行的副本,会在品牌名和页面标题后标注「自部署版本」,
管理员首次进入时看到免责与禁止商用的提示。自部署副本不显示赞助入口(/donate
返回 404)和 App 推送设置;入站邮件转发按实际收件地址显示,不再写死官方邮箱。 -
本机一条命令启动(83588b6)
python launcher.py会在首次运行时生成.env、下载浏览器内核,并同时启动面板与
监控;关闭终端时一起停止。README 与使用指南的快速开始分成「在自己电脑上用」
(Python)和「公网部署」(Docker)两种。
条款与隐私
- 使用条款明确禁止商用和再分发房源数据,第 9 节限定为以商业目的修改、转售、再许可
或再分发;条款与隐私政策中的「收藏」改为「房源已读记录」。 - App 不再支持用 Holland2Stay 网站账号密码登录,只认本地 App 密码。
测试
升级注意
- 数据库迁移在启动时自动执行:新增
listing_reads表,删除user_configs的
allow_h2s_login列。 - API 契约升到 1.26.0:
/me/export增加listing_reads[],用户配置去掉
allow_h2s_login。曾用 Holland2Stay 账号登录 App 的用户需要先设置 App 密码。 - 条款文本在启动时读入,部署后需要重启 Web 进程(重建容器即可)。
- 官方站点按请求 Host 或
PUBLIC_BASE_URL识别;反代改写了 Host 的官方部署,
需要确认PUBLIC_BASE_URL设置正确。
已知限制
- Xior、OurDomain、OurCampus 的 RENTCafe 预订仍未开放,验证移到 v2.2。
- 新界面只在桌面与模拟手机视口的 Chromium 中验收过;Safari、Firefox、真实手机和
屏幕阅读器尚未验证。 - 英文数量文案仍有单复数问题(如
1 listings)。 - Holland2Stay 取消预留的路径尚未用真实操作验证;Plaza 的 DTH 房源不自动应征。
- 单机 SQLite,不支持多实例水平扩展。
v2.0.0
v2.0 以监控正确性、可维护性和回归保障为目标,不新增平台或客户端功能。主要变化
是把 monitor 的单体实现按阶段拆成独立模块、统一配置解析与运行时快照、补齐通知与
预订的故障边界,并把 CI 与文档纳入发布流程。自动预订仍只开放 Holland2Stay 与
Plaza(Plaza 需用户单独启用)。
架构与可维护性
-
monitor 按阶段拆分(79e7a0d、32207ae、57f5afd、0ab2195、5e4d3f3)
run_once()拆成抓取、预热、后处理三段;startup / stale / dispatch / telemetry
各自独立;抓取失败处置移到round_failures,预订流程移到booking_round,
通知与事件重放移到notify_round。平台标识、显示名、抓取器入口和基础能力统一
登记在SourceSpec。monitor.py只剩主循环与阶段编排。 -
运行时状态收进
RuntimeState(57f5afd)熔断、自适应节流、持久化退避、预加载缓存与竞败重试队列有了单一归属;热重载和
测试隔离不再依赖直接修改模块全局。 -
配置解析收口(7de759d、f65de0f、8de2c73、38e926f、5677216)
load_config()改走target_config严格解析,布尔与整数统一到env_utils,
已登记平台的解析器补齐。热重载先构造并校验候选配置,失败保留旧配置;坏配置由
测试矩阵覆盖,不再静默回落到默认值。 -
路由中散落的 SQL 与
feedback建表移入mstorage;GDPR 导出与反馈写入成为
存储层方法。Web 侧的登录、注册、测试通知、访客房源、崩溃上传与用户名枚举统一
到app/rate_limit.py,空闲键定期清理。 -
测试与 CI(0fa476a、f42b0b7、4467480)
合并重复测试、参数化规则表、清理失效用例;push / PR 运行 Ruff 与 pytest;
CI 安装 Node,使浏览器端 JS 的执行路径不再被跳过。
监控正确性
-
H2S REST 快速通道(09f253e、83d3ddb)
在自家线路上按可配间隔观察 REST 信号,发现新放出的房源时叫醒主循环,只补抓
Holland2Stay,而不是等下一轮全量调度。 -
首次全量扫描计时(5dc89ce):计时器在全量扫描真正完成后才推进,避免第一轮
把「计划做全量」当成「已经做完全量」。 -
阶段边界与故障隔离(faaeb55、dcba13e、c86f8b6、dc0d905)
抓取、预订提交、通知与收尾的异常不再互相带走;平台调度与浏览器工作进程超时后
可回收恢复。
通知与预订
-
状态变更按事件主键标记(5487294):未完成通知可重放,影子平台过滤在重放
之后执行,不再依赖 listing 级的notified标志。 -
SSE 短期票据(fdcebbb):EventSource 客户端用 60 秒票据连接,不再接受 URL
中的长期 token。 -
公告投递记录(7d4f9a4):逐用户、逐渠道记录投递结果,失败与未完成项可精确
补发。 -
预订保护与结果等待(002ae15、08f6f51):Holland2Stay 按账号、Plaza 按
账号和房源保留不确定结果保护;预订结果等待增加墙钟上限,后台任务卡住时不会拖住
整轮。 -
Holland2Stay 当前
/api/booking路径已用真实账号走通到付款链接。Xior /
OurDomain / OurCampus 的 RENTCafe 预订仍未对用户开放,验证列入 v2.1。
部署与文档
docker-compose.yml默认传TRUSTED_PROXY_HOPS=1,反代后限流与日志能看到真实
客户端 IP;直接暴露端口时应在.env设为 0。新增
DEPLOYMENT.md 说明 Caddy、TLS、端口、日志与自有反代。- 文档重写:
ARCHITECTURE、H2S、SCRAPING_RECON、XIOR、OURDOMAIN、PLAZA
改为当前状态;新增RENTCAFE.md承接三平台共用预订流程;API.md增加目录并
修正响应字段漂移,openapi.json升到 1.25.0;FUTURE_PLAN只保留未完成项,
并新增 v2.1–v2.5 的 Web 界面规划。
升级注意
- 数据库迁移在启动时自动执行(新增
feedback表),无需手工操作。 - API 契约 1.25.0 为增量变更,既有客户端不受影响。
- 部署方式与数据库位置未变;仍是单机 SQLite 与 Web / monitor 双进程。
已知限制
- Xior、OurDomain、OurCampus 的 RENTCafe 预订未开放,验证在 v2.1 进行。
- Holland2Stay 的取消预留路径尚未用真实操作验证。
- Plaza 的 DTH 房源不自动应征(确认框的影响范围未查明)。
- 单机 SQLite,不支持多实例水平扩展。
v1.44.0
v1.40.0
v1.40.0 — OurCampus 预订侧就绪(未开放);TLS 指纹按实测重排 OurCampusBooker 写好,止于开始申请,未注册:「开始申请能占住单元」还没实测。 对照真实响应修掉 onclick 双引号解析缺陷、抽签单元不开始申请、单元表 403 时冷却 指纹重开会话。 SecureRC 此刻只放 chrome150 这一个桌面 Chrome,146 及以前全部 403;指纹池改为 Safari 打底,curl_cffi 升到 0.16.3。
v1.39.0
v1.39.0 — 楼盘过滤;OurCampus 抽签不再报成可订 过滤器加「楼盘」:只要这栋楼里的任何一间,通知与自动预订两侧都生效。 自动预订的「能通知到」把推送也算进去——只用 App 的用户此前永远产生不了候选; 启动摘要的三条假警告改为与闸同一判据。 OurCampus 先到先得与抽签并存,两者只差按钮文字;判据此前只看按钮在不在, Join Lottery 的单元因此按可订推送。留档文件改为只记变化、满了轮转。
v1.38.0
v1.38.0 — Plaza 自动应征 先修掉抓取侧「一多半房源报错了状态」的缺陷(49 条荷兰住宅里 31 条根本应征不了, 却按可预订推送),再把自动应征做到端到端跑通并放进面板,默认关。 DTH 一律不应征且刻意没做成开关:确认框那句「不再收到其它 offer」的范围站点没有 说明,事实未知时两边代价不对称。 过程中有五处「错了不报错」的实现缺陷,全部由真实账号的端到端验证暴露——在那之前 单元测试是全绿的。 另含运河屋图标、登录页无底色标识、README 平台数修正。
v1.37.0
常驻浏览器泄漏事故,及它暴露出的 close() 根因 自 v1.36.0 以来六次提交,六条,覆盖浏览器资源、API 契约与规划。 主线是一次生产事故与两层修复。v1.36.0 上线的下单常驻浏览器在生产里泄漏 Chromium: 每次建立成功后 5–6 分钟被判死,而 close() 收不掉进程。18 小时泄漏 5 套,容器内存 1.14 → 1.73 GiB(上限 2 GiB),随后 Holland2Stay 熔断、Xior 渲染器每轮卡死 600 秒。 它没能加快下单,反而拖垮了两个抓取源。 第一层是关掉它——开关放 RUNTIME_KEYS 而不是 TUNING_KEYS,因为只有前者能在不重新 部署的情况下关闭;一个救火用的开关,如果关它本身要走一次部署,它在最需要的时候就 是没用的。 第二层是根因:close() 对着一根已经断掉的通道调用,既不报错也不生效,紧接着却把 profile 槽位锁放了,于是下一次开浏览器拿到同一个目录、删掉还活着那个实例的单实例 锁,两个 Chromium 同开一个 profile。这条链子自我维持,且不属于常驻浏览器——它属于 所有 BrowserFetcher 使用者,抓取侧只是重建频率低得多而一直没暴露。 另有一次 API 文档全量核对:查出四处漂移,无一会使既有测试变红。以及 GET /listings 的 sort,连带把「默认顺序」和「id 兜底」写进契约——分页此前建在一个从未被承诺的 顺序上。
v1.36.0
下单不再在房源翻牌那一刻现过 Cloudflare 自 v1.35.0 以来二十二次提交,十九条,覆盖自动预订、容量与会话、客户端仓库拆分、 抓取平台、配置一致性与 App Store 发布。 主线是自动预订:过 CF 挑战属于浏览器(中位 16.5s),登录属于用户(~1.5s),而 此前每次抢房都在房源翻牌那一瞬间从零现过一次挑战。留存日志里快速通道触发 4 次、 prewarmed=no 4 次、成功 0 次。现在常驻一个已过挑战的浏览器,只借给本轮优先级最高 的那个用户,其余维持原行为。 本批多数条目共享同一种缺陷形状:判据成立,但它无法与故障区分。8 线程的 gunicorn 在零错误日志下让全站打不开;只查子串的链接测试对换仓库完全无感;Plaza 的 「未登记城市」WARNING 会被修复动作本身关掉;注册表加了城市而订阅串没跟上时,抓取 不发生而警告已消失。逐条的修复方式统一为:先构造一个复现原缺陷的变异,确认判据 变红,再提交。
v1.34.0
缺陷清理:二十一处修复,零新功能 横跨主循环、存储、抓取、预订、通知与 Web 六层。会造成静默数据损坏或静默漏推的 十一处,外部可触发的四处——全部不报错。 三种共同形状:「认不出」被当成一个确定的答案;爆炸半径没有边界;同一段逻辑写两遍 只改一处。 其中四处的测试原本是绿的,因为它们把 bug 钉成了期望行为。 3982 → 4062 条测试,每处修复都做过变异验证。
v1.33.0
接入 Plaza(影子期) 第七个平台,也是第一个非自营运营商的来源——多家机构把房源挂在同一套 Zig/Hexia 系统上,一个匿名 POST 就覆盖十个荷兰城市。 接它的理由是分配机制:荷兰住宅 49 条里 31 条是当场成交,站点自己的确认框写着 「definitief boeken…geen andere aanbieding meer krijgt」——点下去房子就是你的, 代价是放弃其它全部 offer。另 18 条是「Snelle reageerder」,明写不设等候名单。 两类都奖励速度。 上线走影子模式:照常抓取入库、参与收敛与统计,不发任何用户渠道通知。 顺带把仪表盘的覆盖范围横幅按平台分组,并标出影子来源——分组之后才看出十七个 城市里有十一个只由影子 source 覆盖,横幅却在承诺一个不会兑现的推送。