Skip to content

feat: handle inprogress flows on version updates#706

Open
sricharan-varanasi wants to merge 12 commits intodevfrom
feat/store-applet-version-in-progress
Open

feat: handle inprogress flows on version updates#706
sricharan-varanasi wants to merge 12 commits intodevfrom
feat/store-applet-version-in-progress

Conversation

@sricharan-varanasi
Copy link
Contributor

  • Tests for the changes have been added
  • Related documentation has been added / updated
  • OSS packages added to Curious open source credit page

📝 Description

🔗 Jira Ticket M2-10357

Enables cross-device flow resume when the applet version has changed since the flow was started. Previously, if a user started a flow on Device A at version 1.0.0 and the applet was updated to 2.0.0 before they resumed on Device B, the resume would fail because the activity items couldn't be fetched for the original version.

Changes include:

  • Store applet version in GroupProgress when starting/syncing entities
  • Pass stored version to activity fetch endpoint (?version=) so items are fetched from the correct historical version
  • Use flowActivityIds from server CompletedEntity for flow navigation instead of current applet definition (handles deleted/reordered activities)
  • Store flowName from server for deleted flows that no longer exist in current version
  • Sync version field from CompletedEntityDTO into local progress
  • Show deleted flows in activity groups UI with a warning badge
  • Alert user when restarting a deleted flow (it will start as a new flow on current version)
  • Handle deleted flows in survey submission and navigation (skip welcome screen, use stored metadata)
  • Hide restart button for flows that no longer exist in the current applet version

✏️ Notes

  • Requires backend PR: cross-device-flow-resume-versions branch on mindlogger-backend-refactor
  • Backend adds version, flowActivityIds, and flowName fields to the completions endpoint response
  • Backend adds ?version= query param to GET /activities/{id} for fetching historical activity items
  • The flowActivityIds field is only populated for in-progress flows, not completed ones

…ions

Track the applet version at the time a flow/activity session starts in GroupProgress state. On resume, the stored version is sent with the
answer payload instead of the latest version, preventing 400 errors
when the applet is updated mid-session.On restart, the stored version is updated to the current applet version
so the new session uses the latest schema.

Changes:
- Add appletVersion to FlowProgress and ActivityProgress types
- Store appletVersion in activityStarted/flowStarted reducers
- Update appletVersion in activityRestarted/flowRestarted reducers
- Pass appletVersion through useEntityStart and useStartSurvey hooks
- Prefer groupProgress.appletVersion in answer construction
Add version field to CompletedEntityDTO so the client receives the
per-entity applet version from the backend. When syncing in-progress
flows from the server, pass entity.version as appletVersion into
GroupProgress so cross-device resume preserves the original version.
Store flow metadata in GroupProgress:
- Add flowActivityIds and flowName to FlowProgress type
- Add flowActivityIds and flowName to FlowStartedPayload and FlowRestartedPayload
- Store flow metadata in flowStarted and flowRestarted reducers
- Pass flow.activityIds and flow.name through useEntityStart and useStartSurvey

Fix useEntitiesSync for deleted flows:
- Fall back to stored flowActivityIds/flowName from local GroupProgress when
  flow is missing from current applet version during cross-device sync
- Preserve flowActivityIds and flowName in saveGroupProgress

Render deleted flows in UI:
- Add isDeletedFlow flag to EventEntity and ActivityListItem types
- Create synthetic ActivityFlow entity from stored metadata in
  ActivityGroupsBuildManager when flow not found in current applet
- Handle deleted flows gracefully in ListItemsFactory (use flow name
  instead of throwing when activity not found)
- Add isRestartDisabled prop to ActivityCardRestartResume
- Hide restart button when isRestartDisabled is true (resume only)
- Pass isDeletedFlow from activityListItem as isRestartDisabled in ActivityCard
- activity.service.ts: accept optional version params in getById
- activityProxy.service.ts: forward version option to ActivityService
- useActivityByIdQuery: add version to params and query key
- useSurveyDataQuery: accept activityVersion prop and pass to query
- Survey/ui: read storedAppletVersion from GroupProgress and pass it
When a flow's activity list changes between versions, use the stored
flowActivityIds from GroupProgress instead of the live flow's activityIds. This ensures resume follows the original flow structure.

- useEntityComplete: prefer stored flowActivityIds for next activity lookup
- AnswersConstructService: use stored IDs in isSurveyCompleted()
- ScreenManager: use stored IDs for auto-completion timer
- Add flowName to CompletedEntityDTO to match backend response
- Create synthetic AlwaysAvailable events for deleted flows whose
  schedule events no longer exist in the current applet version
- Prefer server-provided flowName, then local stored name, then
  current flow version name
- Guard against overwriting local completed state with server
  in-progress state (server may not have processed final submission)
- Update test fixture with flowName field
@aws-amplify-us-east-1
Copy link

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-706.dek0ppt2nc92n.amplifyapp.com

@sricharan-varanasi sricharan-varanasi force-pushed the feat/store-applet-version-in-progress branch from ff909ee to a6c2ae9 Compare March 2, 2026 16:44
Copy link
Contributor

@divbzero divbzero left a comment

Choose a reason for hiding this comment

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

A few minor comments but code looks good overall!

context.flow?.activityIds,
context.flow?.name,
targetSubjectId,
groupProgress,
Copy link
Contributor

Choose a reason for hiding this comment

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

Could probably break up groupProgress into specific properties for the dependencies array, similar to what you did with context:

    ...
    groupProgress?.startAt,
    groupProgress?.endAt,    
    groupProgress?.appletVersion,
    ...

eventId,
targetSubjectId,
});
const storedFlowActivityIds = (entityProgress as Record<string, unknown> | null)
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor: s/Record<string, unknown>/FlowProgress/ would probably allow us to remove as string[] | undefined in the next line.

if (!activity) {
// For deleted flows, the activity may not exist in the current applet version
if (activityEvent.isDeletedFlow) {
item.activityId = '';
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of '' would we want to use the following?

        item.activityId = progressRecord.currentActivityRecord;

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.

2 participants