google-chat-notifications-service
internalA backend microservice that centralizes operational alerting by receiving signed webhooks from multiple internal and third-party systems (deployment, error monitoring, database, and ERP platforms) and relaying them as formatted notification cards into Google Chat spaces. Also acts as a Google Chat app, responding to slash commands and space events.
TypeScriptNode.jsExpressGoogle Chat APIZodJSON Web Tokens (JWT/JWKS)AWS ECRAWS EC2
Containerized Deployment - AWS (ECR + EC2)
- Docker image built from the Node.js app and pushed to Amazon ECR for versioned image storage
- Deployed and run on an EC2 instance pulling the image from ECR, with a fixed timezone for consistent log/event timestamps
- Compiles TypeScript to a production dist/ bundle inside the image and runs the compiled server on container start
- Exposes a single HTTP port on the instance for all inbound traffic
External Systems (Webhook Sources)
- Deployment platform sends build/deploy event webhooks
- Error monitoring platform sends issue/alert webhooks
- Database platform sends alert webhooks
- ERP system (custom module) sends business record alerts (e.g. new leads, order events)
Express API Layer
- Exposes per-provider webhook routes scoped to a target chat space, e.g. /v1/webhook/:space/{provider}
- Applies Helmet security headers, CORS, and a locked-down robots.txt
- Captures the raw request body during JSON parsing so signatures can be verified against the exact bytes received
- Returns a JSON status/uptime endpoint and a rendered HTML status page for health checks
Authentication & Request Verification
- Each provider webhook is verified before reaching business logic, rejecting unverified requests with 403
- Deployment webhook payloads are verified via signed JWT with issuer validation
- Monitoring, database, and ERP webhooks are verified via per-provider HMAC signatures (SHA-1/SHA-256) using shared secrets
- Inbound Google Chat app events are verified using Google-issued JWTs validated against Google’s public JWKS endpoint and the configured Cloud project number
Payload Validation
- ERP alert payloads are validated with a schema enforcing required fields (record type, ID, event type, title, severity) before processing
- Invalid payloads are rejected with 400 before any external call is made
Google Chat Integration
- Uses a Google Cloud service account with app-level OAuth credentials to authenticate as the Chat app
- Formats each provider event into a provider-specific Google Chat card and posts it to the target space via the Chat API
- Supports interactive slash commands (e.g. echoing the triggering event, returning service uptime)
Notification Delivery
- Successful deliveries return 200; failures to reach Google Chat return 502 so upstream systems can detect delivery issues
- Notification routing target is derived from a URL path parameter, keeping space selection decoupled from the payload itself
- # Why per-provider signature verification instead of a shared secret?
- Each upstream system (deployment platform, monitoring, database, ERP) uses its own native signing scheme (JWT vs. HMAC, SHA-1 vs. SHA-256, hex vs. base64). Verifying against the raw captured request body with provider-specific config prevents forged notifications and keeps each integration independently rotatable without affecting the others.
- # Why a stateless relay with no database?
- The service only transforms and forwards event data; it does not need to persist notification history or state, which keeps the deployment simple, reduces attack surface, and avoids managing a data store for what is essentially a fire-and-forget integration layer.
- # Why validate ERP payloads with a schema before building chat cards?
- Business system alerts have the most variable and highest-stakes payloads (record data, severity, links). Schema validation fails fast with clear error detail, preventing malformed or unexpected data from silently producing broken notification cards.
- # Why authenticate Google Chat app events separately from webhook events?
- Inbound webhooks and inbound Chat app events have different trust boundaries and identity providers, so the service verifies Chat events against Google’s own JWKS-issued tokens and project number rather than reusing the shared-secret scheme used for third-party webhooks.
- # Why route notifications by space ID in the URL rather than the payload?
- Keeping the destination as a path parameter (rather than trusting a space field in the request body) ensures the routing decision is controlled by the service configuration/URL registered with each upstream system, reducing the risk of a compromised or misconfigured payload redirecting alerts to the wrong space.