Commit Graph

40 Commits

Author SHA1 Message Date
vasyansk fcbe438f32 Merge feat/crud-and-rich-log: CRUD deletes/edit + detailed event log
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-02 09:23:14 +07:00
vasyansk b88f88c1a3 feat: delete task/account, edit endpoint, richer event log
- store: DeleteAccount, DeleteTask, UpdateEndpoint (+ cascade/update tests)
- httpapi: DELETE /tasks/{id}, DELETE /tasks/{id}/accounts/{accountId},
  PUT /endpoints/{id}; delete guarded with 409 while task running
- orchestrator: enrich WS events with login/host/port/error (test + run + errors)
- web: delete buttons (task, account) with confirm, endpoint edit form,
  human-readable event log (source/dest, host:port, error text)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-02 09:23:14 +07:00
vasyansk 9019511d6f Merge feat/csv-example-download: downloadable CSV example link
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-02 09:09:08 +07:00
vasyansk 647ea0dbbd feat(web): replace CSV columns caption with downloadable example.csv link
Generates a 3-row sample CSV client-side (Blob) so users see the exact
src_login,src_pass,dst_login,dst_pass layout instead of a plain caption.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-02 09:09:08 +07:00
vasyansk 53276c41f0 Update docker-compose.yml 2026-07-02 09:04:45 +07:00
vasyansk 2a2fd7ad64 Merge fix/empty-list-null: empty lists return [] not null
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-02 09:04:33 +07:00
vasyansk 7eff28053a fix(api): return empty arrays not null for empty lists (frontend null.length crash)
Root cause: store List* methods used 'var out []T' which stays nil on empty
result sets and serializes to JSON null; the SPA then crashed on .length/.map
(e.g. endpoints.length on the Tasks page right after deploy). Return []T{}
at the source; coerce null->[] on the frontend load sites as defense-in-depth.
Regression test asserts List* are non-nil when empty.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-02 09:04:33 +07:00
vasyansk d87a8c57ad Merge feat/imap-copier-mvp: imap-copier MVP
IMAP-to-IMAP mail migration tool: Go backend (streaming, non-destructive,
idempotent copy), React realtime UI, Postgres, Docker+Caddy. Full-stack E2E
proved idempotency; final review Critical (double-run race) fixed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-01 19:39:28 +07:00
vasyansk 8af7b11791 fix(orchestrator): recover from panics in run goroutines to avoid process crash and stuck 'running' task
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-01 19:36:40 +07:00
vasyansk 2429c786e4 fix(orchestrator): prevent concurrent double-run duplicating messages; reflect errors in status 2026-07-01 19:32:04 +07:00
vasyansk 1373aa0a77 feat(deploy): docker image, caddy, compose, e2e script
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-01 19:16:38 +07:00
vasyansk 38005c0618 fix(api): add snake_case json tags to Endpoint/Task/request bodies for frontend contract
Go's encoding/json does not bridge snake_case <-> PascalCase field names,
so store.Endpoint, store.Task and the anonymous request bodies in
accounts.go/auth.go were silently decoding empty/zero values from the
frontend's snake_case JSON contract (tls_mode, role_label,
src_endpoint_id, dst_endpoint_id, src_login/pass, dst_login/pass).
Adds explicit json tags; DB layer is unaffected since pgx binds by
positional params, not struct-tag reflection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-01 19:04:46 +07:00
vasyansk 1a451f9dbb feat(web): React SPA with realtime task detail over WebSocket
Vite + React 19 + TS console-style operator UI: hash-routed Login,
Endpoints, Tasks, and TaskDetail (realtime accounts table over /ws,
Run gated on all accounts testing ok on both sides).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-01 19:01:05 +07:00
vasyansk 4c57848c35 fix(httpapi): detect ws client disconnect via CloseRead to prevent subscriber leak
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-01 18:47:54 +07:00
vasyansk 9ec6acd414 feat(httpapi): websocket, router, embed static, main entrypoint 2026-07-01 18:37:48 +07:00
vasyansk 0bd4ba37e3 fix(httpapi): fail CSV import on encryption error instead of storing empty passwords 2026-07-01 18:33:09 +07:00
vasyansk bb83bbd989 feat(httpapi): REST resources for endpoints/tasks/accounts/csv/run 2026-07-01 18:27:11 +07:00
vasyansk 839febb83a fix(httpapi): bind session token to current AuthUser; add negative auth tests
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-01 18:24:35 +07:00
vasyansk cae124931d feat(httpapi): env-based login and session auth middleware 2026-07-01 18:19:57 +07:00
vasyansk f9f01b981b fix(csvimport): report accurate physical line numbers via FieldPos; add blank-line + zero-row tests 2026-07-01 18:17:54 +07:00
vasyansk 7fe8896f4b feat(csvimport): validated CSV account parser 2026-07-01 18:12:57 +07:00
vasyansk 2def11a870 fix(orchestrator): reuse src connection to list folders instead of extra TestLogin 2026-07-01 18:10:52 +07:00
vasyansk 8c871d9d26 feat(orchestrator): worker pool run + account testing gate 2026-07-01 18:04:44 +07:00
vasyansk ec8835538b feat(wshub): per-task event hub with non-blocking publish 2026-07-01 17:59:43 +07:00
vasyansk a54ec1d148 fix(imapx): preserve source internal date on APPEND 2026-07-01 17:57:12 +07:00
vasyansk 06c0598b80 feat(imapx): streaming per-folder copy with dedup, idempotent 2026-07-01 17:39:43 +07:00
vasyansk 79f5c5b93a fix(imapx): honor context in Connect with bounded dial retry 2026-07-01 17:28:10 +07:00
vasyansk 0451b79c64 feat(imapx): connect, endpoint test, login test with folder listing 2026-07-01 17:20:03 +07:00
vasyansk 37cb8ba076 feat(imapx): message dedup key (Message-ID + header fallback) 2026-07-01 17:03:18 +07:00
vasyansk 67a2367baa feat(store): tasks, accounts, runs, dedup journal 2026-07-01 16:58:33 +07:00
vasyansk 0cf9de38c4 fix(store): close pool on failed Ping; add ListEndpoints test 2026-07-01 16:55:24 +07:00
vasyansk 420358b558 feat(store): pgx pool and endpoints CRUD 2026-07-01 16:50:45 +07:00
vasyansk edda3dc21f feat(db): initial schema migration 2026-07-01 16:42:39 +07:00
vasyansk 0b9d31bd15 feat(crypto): HMAC signed session tokens 2026-07-01 16:37:56 +07:00
vasyansk 06d601482c fix(crypto): enforce 32-byte key for AES-256 2026-07-01 16:36:19 +07:00
vasyansk 8d4a605b9f feat(crypto): AES-256-GCM password encryption 2026-07-01 16:33:13 +07:00
vasyansk 0dfe39565e fix(config): pin go directive to 1.22 for build portability 2026-07-01 16:31:11 +07:00
vasyansk 0d42eb2db0 feat(config): env-based configuration with validation 2026-07-01 16:27:31 +07:00
vasyansk 353f1e9dd3 docs: implementation plan for imap-copier
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-01 16:23:40 +07:00
vasyansk 0e7736f613 docs: design spec for imap-copier
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-01 16:16:14 +07:00