Commit Graph
65 Commits
Author SHA1 Message Date
QiuSW 22a024be64 fix(#64): bound purchase spec selection retries 2026-08-22 09:07:13 +08:00
QiuSW 0e3be46c4c feat(#62): extend AI matching timeout 2026-08-21 17:23:02 +08:00
QiuSW 6181d97f39 feat(#62): add AI specification matching settings 2026-08-21 17:04:49 +08:00
QiuSW 5a94f4f8b4 docs(#61): record safe purchase spec entry 2026-08-21 16:09:47 +08:00
QiuSW aebe80f305 fix(#61): use safe purchase spec entry 2026-08-21 16:08:57 +08:00
QiuSW 36b11ece5d fix(#60): stabilize per-color price capture 2026-08-21 15:29:03 +08:00
QiuSW 37db89ce92 docs(#59): record Samsung device verification 2026-08-21 15:15:01 +08:00
QiuSW 2977edcd53 fix(#59): avoid PDD review page spec misclick 2026-08-21 15:04:06 +08:00
QiuSW 01d852011a feat(#58): batch retry failed purchase tasks 2026-08-21 14:20:40 +08:00
QiuSW 6a0dfed757 feat(#36): add guarded Android live purchase 2026-08-21 11:06:26 +08:00
QiuSW 7e4f404265 feat(#44): create purchase tasks from SYB products 2026-08-21 10:17:31 +08:00
QiuSW 09083c8e18 docs: record acceptance of #35 #55 #56 2026-08-21 09:44:34 +08:00
QiuSW 35dd3e0be5 docs(#35): clarify unknown-order guard 2026-08-20 23:56:50 +08:00
QiuSW c0c88bb43f feat(#35): add purchase task admin UI 2026-08-20 23:54:17 +08:00
QiuSW 182ef3940a feat(#55): add purchase admin query APIs 2026-08-20 23:31:23 +08:00
QiuSW e5b8d48856 docs(#54): record user acceptance 2026-08-20 23:22:48 +08:00
QiuSW dae9cb6aed docs(#42): record user acceptance 2026-08-20 23:14:16 +08:00
QiuSW b0f33bf679 fix(#54): unify device state across task domains 2026-08-20 22:53:15 +08:00
QiuSW 997f4e7463 docs(#53): record user acceptance 2026-08-20 18:04:40 +08:00
QiuSW afeb2723ea fix(#53): parameterize purchase rule actions 2026-08-20 17:53:10 +08:00
QiuSW dfa425ba5f docs(#34): record user acceptance 2026-08-20 17:31:30 +08:00
QiuSW 65ae41fd6f feat(#34): implement purchase task state machine 2026-08-20 17:22:52 +08:00
QiuSW 978f42806a feat(#33): define purchase task data and API contract 2026-08-20 16:49:43 +08:00
QiuSW 32edb91a31 fix(#52): expose SYB preflight failure stages 2026-08-20 16:09:28 +08:00
QiuSW badb78fa68 feat(#50): run SYB imports asynchronously 2026-08-20 15:24:50 +08:00
QiuSW 6c7a7298e3 feat(#49): complete SYB shop management 2026-08-20 11:54:11 +08:00
QiuSWandClaude Opus 5 e6f533b71e fix(#48): add the missing version-local migration for syb_session
Adding SYBSession to migrations.Migrate was not enough. Schema reaches an
existing database only through a version-local file; with the previous
version already recorded in sys_migration, Migrate never re-ran and the
table simply never appeared. The unit tests build a fresh database every
time, so they stayed green while the real database was missing a table —
which surfaced as "Error 1146: Table 'goauto.syb_session' doesn't exist"
on the first import attempt.

server/.gitignore was hiding these files. go-admin ignores version-local
because it is where generated local migrations land, but every GoAuto
migration belongs in version control; the existing ones had been forced
in with `git add -f`. Un-ignoring *.go there also recovers four migrations
that were never committed at all — 1786700000000 through 1786700300000,
covering the base schema, device registration, heartbeat and collection
execution. A fresh clone could not have built a working database.

Guard the class of mistake rather than just this instance:

  - migrations.VerifyTables checks every model's table after migrating and
    names what is missing along with the fix.
  - The migrate command runs it, so the failure lands at migrate time
    instead of at the first request that needs the table.
  - initDB no longer discards migrateModel's error. Upstream had
    `_ = migrateModel()` followed by an unconditional "初始化成功", so a
    failed migration reported success and the launcher believed it.

Also records the two-step rule in Common-Changes: a new model needs both
the model registration and a new version file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 10:10:11 +08:00
QiuSWandClaude Opus 5 c86e98d0cb feat(#48): make one config work for both development and deployment
The repo already layered file defaults under environment overrides, on
both the backend (settings.yml < GOAUTO_*) and the frontend
(.env.production < process.env). What was missing was a translator for
production: config.yaml only ever existed for the PowerShell launchers,
so a packaged binary read none of it and had no database credentials
either — SYB was inheriting an existing gap, not creating one.

The server now reads config.yaml itself, between settings.yml and the
environment. Lookup is GOAUTO_CONFIG, then ./config.yaml, then beside the
executable, so a packaged binary works wherever it is started. An absent
file is not an error: containers supply everything through the
environment. Scalars are read by YAML type and coerced, so an unquoted
all-digit password cannot take startup down over a quoting detail.

This removed the need for a Read-SybConfig in PowerShell: the launcher
just hands over the path it already knows, rather than reimplementing a
YAML parser.

The server also serves the built frontend when dist is present, which is
what .env.production's empty VUE_APP_BASE_API already assumes. The
history fallback is restricted to non-API GETs, and is not installed at
all without dist, so development 404s stay 404s.

Precedence is mutation-tested: applying the local file after the
environment instead of before makes the layering test fail.

Not verified: the PowerShell change and any Windows deployment — both
need a run on the Windows side.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 09:28:45 +08:00
QiuSWandClaude Opus 5 7edb4e7b9f feat(#48): add SYB sync orchestration, import endpoint and page entry
Stage 2. Completes the path from the SYB API to the archive.

sybimport.Sync pages a date range day by day and folds each detail line
through the existing idempotent ApplyDetail. The paging loop is driven by
listTotal, never by the list response's own total, which live data
confirmed is the page's row count rather than the filtered total. A day
whose completeness cannot be proven — a short page, a total that drifted
while paging, a detail response missing an order — stops the run instead
of reporting a partial import as a whole one. Rows already written stay:
they are idempotent on (order_code, detail_id), so a re-run overwrites.

sybimport.Connect reuses the cached session and only discards it when SYB
explicitly says it is invalid. Caching the numeric user id alongside the
cookies is required, not incidental: session validation calls
/am/user/get?id=, and a wrong id comes back as a business error rather
than a logout, so cookies alone can never be revalidated.

The import endpoint is single-flight and detached from the request
context, so closing the tab cannot abandon a half-finished range. It
reads only; no SYB write endpoint is reachable from GoAuto.

The page swaps its "no import entry" warning for a date-range dialog that
warns when the span is wide — a single week held over 7000 orders — and
reports partial progress when a run fails midway.

Verified: go build, go vet, go test ./... all pass. The drift check was
mutation-tested. Not verified: the MySQL migration for syb_session, and
any browser walkthrough.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 16:56:00 +08:00
QiuSWandClaude Opus 5 a31c4776c4 feat(#48): port SYB ERP client, session store and config (Stage 1)
Port the SYB ERP HTTP client from the upstream cmautobuy project. The
package is stdlib-only (no DB, no gin), so client.go, columns.go, ocr.go
and their httptest suites carry over almost verbatim; only the package
name and doc references changed.

Add on top of the port:
  - models.SYBSession + gorm SessionStore, so a restart does not force a
    fresh captcha. Cookies are credential-equivalent and carry json:"-".
    Expired sessions read as absent because SYB has no rolling renewal.
  - config.Extend.SYB. Non-secret settings live in settings.yml;
    username and password come only from GOAUTO_SYB_* environment
    variables, so no credential lands in a tracked file.
  - docs/12-syb-erp-interface.md, the ported interface contract.

The guard tests were mutation-checked: reverting json:"-" and renaming a
settings.yml key each make their test fail.

No import endpoint yet — that needs real credentials and live network
verification, which is Stage 2 of #48.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 16:30:35 +08:00
QiuSWandClaude Opus 5 b4861f5073 docs(#48): scope OCR prohibition to Agent side, allow SYB login captcha OCR
The blanket "no OCR/VLM" rule was written for Android Agent collection.
Server-side SYB ERP login is a different domain and needs captcha OCR to
run unattended. Scope the prohibition to the Agent side and record the
SYB carve-out, including that captcha images leave the project.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 16:17:16 +08:00
QiuSWandClaude Opus 5 f53e6ba05b docs(#41): sync architecture, business rules and API contract for syb import
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 15:11:03 +08:00
QiuSWandClaude Opus 5 03f44a0dd2 docs(#40): sync architecture, business rules and API contract for shopee product
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 13:45:35 +08:00
QiuSWandClaude Opus 5 0d623d8e7b docs(#47): unify harness command references
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 09:23:02 +08:00
QiuSWandClaude Opus 5 f8d0011057 docs(#47): mirror harness command entry changes
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 09:20:32 +08:00
QiuSWandClaude Opus 5 b3430637d8 docs(#47): upgrade DevHarness baseline to bfdf648
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 09:19:38 +08:00
QiuSWandClaude Opus 5 80434ecb56 docs(#40,#41): record stage A prototype acceptance
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 08:53:52 +08:00
QiuSWandClaude Opus 5 acaa6c090b docs(#41): unify SYB terminology in issue and delivery index
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 17:51:36 +08:00
QiuSWandClaude Opus 5 953ce55e3f docs(#40,#41): rename 货运宝 to SYB in display terms
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 17:45:03 +08:00
QiuSWandClaude Opus 5 faecd90d2b docs(#46): revise spec matching rules for AI matching
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:47:38 +08:00
QiuSWandClaude Opus 5 b314109ce8 docs(#41): mirror stage A prototype status
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 14:18:42 +08:00
QiuSWandClaude Opus 5 8dbac5ddf6 docs(#40): record stage A prototype acceptance
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 11:43:59 +08:00
QiuSWandClaude Opus 5 38dbaed05b docs(#40): add stage A shopee product prototype
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 09:48:43 +08:00
QiuSWandClaude Opus 5 23464ecd50 docs(#32): record procurement prototype acceptance
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 09:30:01 +08:00
QiuSWandClaude Opus 5 a3ef9cbcb4 docs(#40,#41): mirror stage A prototype gate
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 09:29:11 +08:00
QiuSW 3718ce8dc6 docs: record issue 45 acceptance mirror 2026-08-18 08:49:26 +08:00
QiuSW ceecb5855e feat(#45): add batch collection task creation 2026-08-17 17:17:20 +08:00
QiuSW f6bada9f86 docs(#31): archive accepted product module 2026-08-17 17:02:41 +08:00
QiuSW da7c02cbeb docs(#26): archive accepted traversal fix 2026-08-17 16:57:57 +08:00
QiuSW a7a453633e feat(#31): implement PDD product archive module 2026-08-17 16:04:18 +08:00