Event-Driven Flows

Overview

The User Service participates in the FloatMe event architecture both as a consumer and a producer. It consumes events from two inbound Kinesis streams and produces events on one outbound stream via DynamoDB Streams.

event architecture
Direction Stream Lambda Purpose

Inbound

prod-payments

prod-user-service-payment-worker

Bans users when a chargeback is detected

Inbound

prod-subscriptions

prod-user-service-subscriptions

Updates membership and tags when subscriptions are paused or resumed

Outbound

prod-user-service-users

prod-user-service-kinesis-feeder

Publishes user and membership change events to downstream consumers


Payment Worker

Trigger

Kinesis stream: prod-payments (published by the Payment Service)

Events Handled

Payment Status Action

CHARGED_BACK

Calls POST /{user_id}/user/ban on the user-service API to ban the user

(any other status)

Logged and ignored

Flow

Kinesis record received (prod-payments)
     │
     ▼
Unmarshal event envelope
Decode payload → Payment object
     │
     ▼
payment.Status == "CHARGED_BACK"? ──No──► Skip (log and continue)
     │ Yes
     ▼
EnableChargebackBan flag enabled? ──No──► Skip (feature flag)
     │ Yes
     ▼
Ban user via user-service API
  POST /{user_id}/user/ban
  reason: "user banned from user-service for returned payment"
     │
     ▼
Log: "user banned"
The chargeback ban is controlled by a feature flag (EnableChargebackBan). When disabled, CHARGED_BACK events are received and logged but no action is taken.

Error Handling

Each Kinesis record is processed independently. On unmarshal or processing error, the sequence number is returned as a batch item failure, which causes that record to be retried.


Subscription Worker

Trigger

Kinesis stream: prod-subscriptions (published by the Subscription Service)

Records in a batch are processed concurrently. If any record fails, the entire batch is failed and retried.

Events Handled

Event (updated_event) Action

pause-skipped

Billing cycle was skipped because the subscription is paused. Updates membership status to SUB_PAUSED and tag to SUB_PAUSED.

pause-resume

Subscription has resumed after a pause. Creates new membership record in good standing and archives the pause tag.

(any other event)

Logged as a warning and ignored

pause-skipped Flow

Fired when the Subscription Service skips a billing collection because the membership is paused.

Subscription event: pause-skipped
     │
     ▼
Get user tags
     │
     ▼
MEMBERSHIP_PAUSE_STATUS tag == "SUB_PENDING_PAUSE"?
     │ Yes
     ▼
Upsert tag: MEMBERSHIP_PAUSE_STATUS = "SUB_PAUSED" (active)
     │
     ▼
Get current membership
     │
     ▼
membership.Status != "SUB_PAUSED"?
     │ Yes
     ▼
Write new membership record
  status: SUB_PAUSED
  event_type: PAUSE_COLLECTION_SKIPPED
The event_type on the DynamoDB write is intentionally set to PAUSE_COLLECTION_SKIPPED (rather than a standard feeder event type) to prevent the Kinesis Feeder from triggering downstream automation in the Subscription Service.

pause-resume Flow

Fired when the Subscription Service resumes a paused subscription (e.g. after the pause duration expires).

Subscription event: pause-resume
     │
     ▼
Look up user (to get email for notification)
Get current membership
     │
     ▼
Write new membership record
  status: (empty — good standing)
  event_type: SUB_RESUMED
  pause_date: cleared
  pause_duration_months: cleared
  (tier and term carried forward from previous record)
     │
     ▼
Archive MEMBERSHIP_PAUSE_STATUS tag
  value: SUB_RESUMED
  archived: true
     │
     ▼
Send unpause notification via Segment
  event: "user-membership-unpause"
  fields: email, unpause_date
     │
     ▼
Emit metric: user.membership.unpaused

Kinesis Feeder (Outbound Events)

Trigger

DynamoDB Streams on prod-user-service-users. The feeder is triggered on every write to the primary DynamoDB table.

Behaviour

The feeder reads the db_type attribute from the DynamoDB stream record’s new image to determine the entity type, then publishes a corresponding event to the prod-user-service-users Kinesis stream. Records with unknown or missing db_type values (e.g. tags, consent agreements) are silently skipped.

Event Types Produced

db_type Event type Payload

USER

Value of event_type attribute on the DynamoDB record (e.g. USER_CREATED, USER_ACTIVE, USER_UPDATED)

Full user object at time of write

MEMBERSHIP

Value of event_type attribute on the DynamoDB record (e.g. MEMBERSHIP_UPGRADE, REACTIVATE, CANCEL)

Full membership object at time of write

(all others)

(skipped)

Flow

DynamoDB Stream record received (prod-user-service-users)
     │
     ▼
Read db_type from new image
     │
     ├── "USER" ──► Unmarshal User → build event with event_type from record
     ├── "MEMBERSHIP" ──► Unmarshal Membership → build event with event_type from record
     └── other / missing ──► Skip (log debug, continue)
     │
     ▼
Create Kinesis PutRecord input
  partition key: user_id
  stream: prod-user-service-users (env: USR_KINESIS_STREAM_USERS)
     │
     ▼
Publish to Kinesis
  └── Error: logged, processing continues to next record
The feeder processes all records in a batch sequentially. Errors on individual records are logged but do not stop processing of subsequent records. The Lambda does not report batch item failures — a feeder error results in logging only.

Outbound Stream

The prod-user-service-users Kinesis stream is consumed by downstream FloatMe services. The event type field corresponds directly to the event_type written to DynamoDB at the time of the operation, making it possible to filter for specific lifecycle events (e.g. only MEMBERSHIP_UPGRADE events) without parsing the full payload.