Replace the legacy DSM-dir 'docker compose up -d --build' flow in AGENTS.md,
COMPOSE-SETUP.md, DOCUMENTATION.md, README.md with the current deploy:
sync build context to /volume1/docker/portainer/compose/240/, rebuild image
if code changed, then PUT /api/stacks/240 (compose + env array, never echo
masked *** values). Legacy dir marked as such; live tg IP note synced.
Same tick previously fired every due watch back-to-back (burst of N requests,
worst right after a restart when all watches are due at once). Now each watch
URL fetch is followed by a pause of FETCH_GAP_SECONDS (float, default 1, env
tunable; 0 disables) on both success and failure paths.
Also thread kw_fk_col into load_ignored_keywords() inside
send_pending_notifications() so the physical-FK lookup (445040a) actually takes
effect instead of silently falling back to the watch Link column.
Previously load_ignored_keywords() relied on the 'watch' Link column's
expanded shape ({'Id': N, ...}), which NocoDB does not guarantee. Now:
- _ensure_keyword_watch_link() discovers the physical FK column title
(e.g. nc_xxx___Settings_id, uidt=ForeignKey) from the table meta and
returns it from bootstrap()
- load_ignored_keywords() prefers reading the FK column (pure numeric Id
in the records API), falling back to the watch object only if absent
- kw_fk_col is threaded bootstrap -> main -> run_tick ->
send_pending_notifications -> load_ignored_keywords
Same one-Settings-fetch-per-cycle design, no N+1.
The search_url Lookup column is redundant: the watch Link -> Settings row
already defines the association. Remove handling for the column:
- _ensure_keyword_watch_link() no longer creates a Lookup; deletes any
legacy search_url (URL or Lookup type) on bootstrap
- load_ignored_keywords(kw_tid, settings_tid) resolves Settings.url via
the watch link, one Settings fetch per cycle (no N+1)
- send_pending_notifications passes settings_tid through
- Add COMPOSE-SETUP.md: detail documentation for the compose stack
(topology, compose block-by-block, Dockerfile, healthcheck, deploy paths,
troubleshooting); referenced from README + DOCUMENTATION.md
Replace the hand-copied search_url (URL type) with a proper relation:
- watch: LinkToAnotherRecord (belongs-to, many keywords -> one Settings row),
picked from a dropdown in the UI so a wrong URL can't silently disable a keyword
- search_url: Lookup column that auto-fills Settings.url through the link
_ensure_keyword_watch_link() builds both columns idempotently on bootstrap and
upgrades a legacy URL-typed search_url to Link+Lookup. load_ignored_keywords()
now normalises Lookup values (string or array).
Silence Telegram alerts for listings whose title contains a keyword
configured for that watch, matched case-insensitively as a substring.
- New IgnoredKeywords table: search_url (watch key) + keyword (one per row)
- load_ignored_keywords() returns {search_url: {lowercase keywords}}, reloaded
every notification cycle so UI edits apply immediately
- title_matches_keyword() does the case-insensitive substring check
- send_pending_notifications() now also pulls search_url on pending records;
skip_notify=true + notified=true on a hit (still archived, no Telegram)
- Docs updated: AGENTS.md, README.md, DOCUMENTATION.md
New Listings.skip_notify checkbox and IgnoredSellers table (seller_name).\nPending listings whose seller_name matches the ignore list are marked\nskip_notify=true + notified=true and never sent to Telegram. List reloads\nevery notification cycle so UI add/remove takes effect immediately.