update1#56
Conversation
Add centralized swagger models in pkg/core/swagger_models.go to provide consistent API response structures. Update all handler Swagger annotations to reference these core models instead of generic gin.H responses. This improves API documentation clarity and ensures consistent response formats across all endpoints. Additionally, refactor version initialization in main.go to use a function and add WebSocket endpoint documentation.
…ntext info, and message versioning
Create the configured bucket when missing, matching fix/create-bucket-if-no-exist-minio. Add unit tests (fake client) and optional integration test behind -tags=integration. Made-with: Cursor
- Gate schedulePresenceUpdates goroutine behind AlwaysOnline flag (previously ran unconditionally for every instance) - Refactor to extract handlePresenceTick as a pure, testable function - Add PresenceSender interface to decouple from whatsmeow.Client - Start presence goroutine dynamically when AlwaysOnline is toggled ON via the advanced-settings API without requiring reconnect - Remove processPresenceUpdates (random unavailable/available cycle) - Add unit tests covering all 4 tick scenarios
WhatsApp now uses LID (Linked ID) format for participant and owner JIDs in groups. The previous implementation compared group.OwnerJID.User and participant.JID.User against the client phone number, but both fields are now LID values (e.g. 216857898393848@lid) rather than phone numbers, causing the endpoint to always return an empty array. Fix uses group.OwnerPN.User (phone-number JID of the owner, always populated alongside the LID-based OwnerJID) and participant.PhoneNumber.User (phone-number JID per participant) for the comparison. Also extends the logic to include groups where the user is admin but not the creator. Removes the TODO comment from the route since the endpoint now works. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- handlePresenceTick: transient DB/network errors no longer kill the goroutine permanently; only ErrInstanceNotFound (record gone) triggers shouldStop=true so AlwaysOnline survives temporary backend issues - instance_repository: add ErrInstanceNotFound sentinel and wrap gorm.ErrRecordNotFound so callers can distinguish not-found from transient failures without importing gorm directly - schedulePresenceUpdates: accepts context.Context so callers can wire a cancellable/service-level context; adds ctx.Done() select case as an additional shutdown path alongside killChannel - test mocks: unimplemented repository methods now panic instead of silently returning zero values, making accidental usage detectable; added TestHandlePresenceTick_TransientRepoError to cover the new retry-on-transient-error behavior Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Pre-allocate myGroups slice with len(resp) capacity to avoid repeated allocations when the user participates in many groups - Guard all JID.User comparisons with myUser != "" to avoid false positives when the client's own JID is unexpectedly zero-valued; extract ownerPhone/ownerJID locals to reduce repeated field access Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The /manager dashboard previously showed only a static placeholder
("Dashboard content will be implemented here..."). This replaces it
with a standalone HTML page that fetches live data from the API and
displays real metrics:
- Total instances count
- Connected instances count and percentage
- Disconnected instances count
- Server health status (GET /server/ok)
- AlwaysOnline count
- Instance table with name, status badge, phone number, client and
AlwaysOnline indicator
- Auto-refresh every 30 seconds with manual refresh button
Implementation uses a standalone HTML file (Tailwind CDN + vanilla JS
fetch) served at GET /manager, keeping the existing compiled bundle
intact for all other routes (/manager/instances, /manager/login, etc.).
Changes:
- manager/dashboard/index.html: new self-contained dashboard page
- pkg/routes/routes.go: serve dashboard/index.html for GET /manager
(exact), keep dist/index.html for GET /manager/*any (wildcard)
- Dockerfile: copy manager/dashboard/ into the final image
- .gitignore: exclude manager build artifacts from version control
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces innerHTML interpolation of server-supplied fields (name, clientName, jid) with DOM createElement/textContent to eliminate potential XSS. Also detects a missing or empty API key before making any requests and renders an actionable message explaining how to set it, instead of showing a generic fetch error.
Removes the '// TODO: not working' markers from the six chat endpoints (pin, unpin, archive, unarchive, mute, unmute). Investigation confirmed the implementation is correct: the endpoints work on fully-established sessions that have synced WhatsApp app state keys. The markers were likely added after testing on a fresh session where keys had not yet been distributed by the WhatsApp server. Also fixes the hardcoded 1-hour mute duration: the BodyStruct now accepts an optional `duration` field (seconds). Sending 0 or omitting the field mutes the chat indefinitely, matching WhatsApp's own behaviour.
Reject negative duration values with a 400-level validation error. Document that duration=0 maps to 'mute forever' (BuildMute treats 0 as a zero time.Duration, which causes BuildMuteAbs to set the WhatsApp sentinel timestamp of -1). Clamp duration to a maximum of 1 year (31536000 seconds) to avoid unreasonably large timestamps being sent to the WhatsApp API.
Adds GET /metrics serving standard Prometheus text format. No authentication required — follows the Prometheus convention of protecting the endpoint at the network/ingress level. Metrics exposed: evolution_instances_total total registered instances (gauge) evolution_instances_connected connected instances (gauge) evolution_instances_disconnected disconnected instances (gauge) evolution_http_requests_total HTTP requests by method/path/status (counter) evolution_http_request_duration_seconds HTTP latency by method/path (histogram) evolution_build_info always 1, version label carries the value (gauge) evolution_uptime_seconds seconds since server start (gauge) Instance gauges use a custom Collector that queries the database on each scrape, so values are always current without event hooks. HTTP path labels use Gin registered route patterns (e.g. /instance/:instanceId) to keep cardinality bounded regardless of distinct IDs in the path. New dependency: github.com/prometheus/client_golang v1.20.5
…volution-foundation#20 GET /instance/status was calling ensureClientConnected, which returns an error when the WhatsApp client exists but is not connected (e.g. after the user manually removes the device from their phone). This caused the endpoint to return HTTP 400 until the container was restarted, making it impossible for clients to detect the disconnected state without restarting the server. Status is a read-only query: it should report the current state, not require an active connection to do so. The fix reads clientPointer directly and returns Connected=false/LoggedIn=false when the client is nil or disconnected, without attempting reconnection. Fixes evolution-foundation#20
The Pair function was calling PairPhone directly without checking if the client was initialized, and was silently swallowing errors from PairPhone. This caused two problems: 1. If the client was nil or disconnected, PairPhone returned an error but the function ignored it and returned HTTP 200 with an empty PairingCode field, misleading the caller into thinking it succeeded. 2. The client was never started before PairPhone was called. WhatsApp requires the client to be connected to the WA websocket (waiting for auth) before a pairing code can be generated. Fix: - Start the instance automatically if no active connection exists, mirroring the QR code flow - Wait 3 seconds for the WA websocket connection to establish and the initial QR generation to begin (required by whatsmeow before PairPhone can be called) - Reject early if the instance is already authenticated - Return PairPhone errors to the caller instead of swallowing them, so the handler correctly responds with HTTP 500 and an actionable error message Fixes evolution-foundation#21
…rousel) - Add SendPix function with full WhatsApp payment protocol support (AdditionalNodes biz/bot nodes, DeviceListMetadataVersion, NativeFlowMessage) - Add /send/pix route and SendPix handler with input validation - Rewrite SendButton: DocumentWithCaptionMessage wrapper + MessageSecret + AdditionalNodes biz nodes; supports reply, URL, call, copy and review_and_pay - Rewrite SendList: DocumentWithCaptionMessage wrapper + MessageSecret + AdditionalNodes (product_list v=2 biz nodes) - Fix SendCarousel: add MessageSecret (32 bytes), set HSCROLL_CARDS card type, add MessageParamsJSON+MessageVersion on card buttons, use json.Marshal instead of fmt.Sprintf, remove forced empty ContextInfo that broke iOS rendering, pass Quoted message, simplify image upload (remove thumbnail generation) - Fix SendMessage central: add AdditionalNodes support in sendExtra, add ButtonsMessage and ListMessage wrapped cases in DocumentWithCaptionMessage, fix InteractiveMessage handling (skip empty ContextInfo on direct carousel) - Remove unused image/jpeg import
… from @paluan-batista - Move GinMiddleware registration to after CORS so OPTIONS requests aborted by CORS policy are not recorded as application metrics - Add 30s TTL cache to instanceCollector.Collect to avoid a DB query on every Prometheus scrape, reducing load spikes at scale - Improve mute duration error message to explicitly say "mute duration" so the caller understands why the request was rejected Thanks @paluan-batista for the thorough review!
… from @paluan-batista - Move GinMiddleware registration to after CORS so OPTIONS requests aborted by CORS policy are not recorded as application metrics - Add 30s TTL cache to instanceCollector.Collect to avoid a DB query on every Prometheus scrape, reducing load spikes at scale - Improve mute duration error message to explicitly say "mute duration" so the caller understands why the request was rejected Thanks @paluan-batista for the thorough review!
Adds a new POST /message/markplayed endpoint that sends a 'played' receipt (whatsmeow types.ReceiptTypePlayed), making the microphone icon turn blue on the sender's WhatsApp for audio messages. Mirrors the existing /message/markread structure (handler -> service -> route + JID validation middleware). 'read' and 'played' are distinct receipts in the WhatsApp protocol and can be sent independently.
There was a problem hiding this comment.
Sorry @felipersd8, your pull request is larger than the review limit of 150000 diff characters
Three whatsmeow events were silently dropped by the dispatcher
("Unhandled event" log) because the central switch in
pkg/whatsmeow/service/whatsmeow.go had no case for them, even though
the underlying go.mau.fi/whatsmeow library emits them:
- *events.Picture (types/events/events.go) — fires when any user's
profile picture or any group's photo changes. Carries JID, Author,
Timestamp, Remove, PictureID. Useful for keeping CRM avatar caches
in sync without polling /chat/fetchProfilePictureUrl per contact.
- *events.UserAbout (types/events/events.go) — fires when any user's
"about" / status text changes. Carries JID, Status, Timestamp.
- *events.BusinessName (types/events/appstate.go) — fires lazily on
inbound messages whose verified business name differs from the
cached one. Carries JID, OldBusinessName, NewBusinessName.
Changes:
1. pkg/whatsmeow/service/whatsmeow.go — added three new cases to the
myEventHandler dispatch switch, mirroring the minimal style of the
existing *events.Contact / *events.PushName handlers (set doWebhook
and postMap["event"]; the raw event is already attached at line 850
via postMap["data"] = rawEvt).
2. pkg/whatsmeow/service/whatsmeow.go (CallWebhook) — added three new
case branches on eventType so consumers can subscribe to PICTURE /
USER_ABOUT / BUSINESS_NAME independently. Following the existing
per-category split (e.g. MESSAGE vs SEND_MESSAGE vs READ_RECEIPT)
rather than folding into CONTACT.
3. pkg/internal/event_types/event_types.go — added the three new
subscription category constants to the const block, AllEventTypes
slice, and validEventTypes map so IsEventType accepts them.
The change is purely additive: existing subscribers keep receiving
exactly what they did before. Consumers wanting the new events must
opt in by including PICTURE / USER_ABOUT / BUSINESS_NAME in their
subscribe list (or use ALL).
No new dependencies, no behavior changes to existing events. Build
verified with `go build ./...` against the pinned whatsmeow-lib
submodule (0923702fb3fac8525241f15331b92116485d69eb).
|
what is the purpose of this PR? didnt understand @felipersd8 |
@dpaes this PR establishes the technical foundation for our new scalable infrastructure. The main goal is to sync and migrate to the Go version (v0.7.1), which is critical for scaling from the current 100-150 instance limit (Waha/Node) to 800+ instances with minimal resource overhead. Key highlights of this update: Core v0.7.1 Sync: Integration of the latest performance and stability improvements from the main engine. Railway Deployment Fix: Adjusted the whatsmeow-lib cloning process to ensure seamless builds on Railway, enabling us to leverage their private networking for RabbitMQ. Edge-Ready Architecture: Prepares the structure to offload heavy processing to Edge Functions via message queues, keeping the main application lightweight and resilient. |
Add POST /group/settings endpoint to allow updating WhatsApp group settings via the REST API. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tingsStruct Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fall back to PORT env var (injected by Railway) when SERVER_PORT is not set, with final fallback to 8080. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Railway does not initialize git submodules on clone. Replace COPY of the empty submodule dir with a direct git clone at the pinned commit. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
ok |
# Conflicts: # LICENSE # NOTICE # README.md # TRADEMARKS.md # evolution-go # pkg/core/c0.go
# Conflicts: # .gitignore # pkg/sendMessage/service/send_service.go
# Conflicts: # docs/docs.go # docs/swagger.json # docs/swagger.yaml # pkg/message/handler/message_handler.go # pkg/poll/handler/poll_handler.go # pkg/sendMessage/handler/send_handler.go # pkg/sendMessage/service/send_service.go
# Conflicts: # .gitignore # Dockerfile
Description
Related Issue
Closes #(issue_number)
Type of Change
Testing
Screenshots (if applicable)
Checklist
Additional Notes