tourze/wechat-work-msg-audit-bundle
A Symfony bundle that integrates WeChat Work (企业微信) message auditing into your app, auto-registering services and configuration for tourze/wechat-work-msg-audit so you can log, inspect, and review inbound and outbound enterprise WeChat messages with minimal setup.
This is the initial 0.0.1 release of tourze/wechat-work-msg-audit-bundle, targeting WeCom (企业微信) 会话内容存档 / message audit — pulling chat records via the official finance SDK, decrypting them, and retaining them for compliance. Treat 0.0.1 as an alpha: usable for a spike, not for production without pinning.
Minimum steps:
composer require tourze/wechat-work-msg-audit-bundle:0.0.1 — pin the exact version; there is no stability promise yet.corpid / secret.libWeWorkFinanceSdk), which typically needs a .so on the box and a PHP extension or FFI binding. Check composer.json ext-* / require entries and the Dockerfile/CI setup in the repo before assuming it is pure PHP.README.md, src/ (service and client classes), DependencyInjection/Configuration.php (the authoritative list of config keys — the README usually lags), and tests/ for a working call sequence.First use case to prove out: pull one page of messages starting from a known seq and persist the decrypted result. If you can round-trip a single chatdata call — request → decrypt → row in the database — the rest of the package is mostly plumbing around that loop.
Cursor-driven pull loop. The API is seq-based: you ask for messages after a sequence number and get back a batch plus the next seq. Persist the cursor (corp_id, seq, updated_at) in its own table, update it in the same transaction that writes the messages, and never derive it from MAX(id) of your message table. This is the single most important design decision in the whole integration.
Raw-then-normalize. Store the raw decrypted JSON blob alongside the parsed columns. WeCom message schemas vary by msgtype and the vendor adds types over time; a json column plus a normalizer you can re-run lets you backfill parsing without re-pulling (and re-pulling may not be possible once the archive window rolls).
Queue the decrypt-and-persist step. Do the HTTP/SDK fetch in a scheduled command, then dispatch a job per batch (or per message) for parsing, media download, and indexing. Keeps the cron short and makes retries granular. Use WithoutOverlapping on the scheduler entry and a distinct queue so a slow media fetch doesn't block the puller.
Idempotency by msgid. Batches can overlap after a failed run. Unique index on msgid and insertOrIgnore/upsert — do not rely on the cursor alone.
Media is a separate problem. image, file, voice, video messages reference sdkfileid, and those expire. If you need the bytes, fetch and store them at ingest time (object storage), not lazily on read. Text-only archiving is a legitimate simpler scope — decide explicitly.
Multi-corp. Even if you have one corp today, key config and cursors by corp_id from day one. Retrofitting multi-tenancy into a seq cursor is painful.
Testing. Wrap the client behind an interface you own; feed recorded chatdata fixtures (encrypted and decrypted pairs) into your normalizer tests. Never let CI touch the live audit API.
Bundle suffix and DependencyInjection/ layout mean the service wiring is Symfony's. In Laravel you will either use the underlying client classes standalone with manual container bindings, or add tourze/symfony-bundle-bridge-style glue. Budget time for this; the README won't mention Laravel at all.0.0.1 with a one-line changelog means zero migration safety. No BC promise, no documented config schema. Pin the version, and diff Configuration.php by hand on every bump..so. Alpine/musl, ARM, and serverless runtimes are common failure points — verify on your actual target image, not your dev Mac..env as one quoted line if you can avoid it. Use a file path + a secrets manager, read-only mount, and never log it. Decryption failures typically surface as an opaque SDK error code, not a helpful exception.seq semantics are easy to get wrong. It's per-corp and monotonic; the value returned in the response is the next cursor to request. Off-by-one here silently skips messages, and there is no "replay from the beginning" if your retention window has passed. Log the requested and returned seq on every call.0.0.1, prefer decorating the package's service over modifying it — forks of a 0.0.x bundle are a maintenance trap.How can I help you explore Laravel packages today?