Skip to content

update1#56

Open
felipersd8 wants to merge 56 commits into
evolution-foundation:mainfrom
felipersd8:main
Open

update1#56
felipersd8 wants to merge 56 commits into
evolution-foundation:mainfrom
felipersd8:main

Conversation

@felipersd8
Copy link
Copy Markdown

Description

Related Issue

Closes #(issue_number)

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Performance improvement

Testing

  • Manual testing completed
  • Functionality verified in development environment
  • No breaking changes introduced

Screenshots (if applicable)

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have tested my changes thoroughly
  • Any dependent changes have been merged and published

Additional Notes

github-actions Bot and others added 30 commits March 25, 2026 16:15
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.
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.
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @felipersd8, your pull request is larger than the review limit of 150000 diff characters

walterdiazesa and others added 3 commits May 8, 2026 20:50
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).
@dpaes
Copy link
Copy Markdown

dpaes commented May 13, 2026

what is the purpose of this PR? didnt understand @felipersd8

@felipersd8
Copy link
Copy Markdown
Author

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.

lucas-eduardo and others added 5 commits May 22, 2026 17:57
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>
@felipersd8
Copy link
Copy Markdown
Author

ok

felipersd8 added 16 commits May 23, 2026 15:05
# 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants