Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save debojyoti/286e13be3618d6f19c561ff959aa9d1e to your computer and use it in GitHub Desktop.

Select an option

Save debojyoti/286e13be3618d6f19c561ff959aa9d1e to your computer and use it in GitHub Desktop.

Row Grain

One row per submission (as specified by client).


CSV Columns — Client Requirements

1. Submission_ID

Client says: For each submission, get the submission id.

Source: Submission.id

Status: No issues.


2. Submission_Timestamp

Client says: For each submission, get the createdAt (e.g. 2026-02-20T18:47:12.544Z).

Source: Submission.createdAt

Status: No issues.


3. Appt_Scheduled_TimeStamp

Client says: For each submission, get the appointment id → go to Appointment table → get the slotId → go to AppointmentSlot table → get date + startTime → combine them.

Source: SubmissionAppointment.slotIdAppointmentSlot.date + AppointmentSlot.startTime

Implementation: Combine date (AWSDate, e.g. 2026-03-15) and startTime (AWSTime, e.g. 14:00:00.000Z) into a single timestamp string. All appointment times are in America/New_York in the existing codebase.

ISSUE — Multiple appointments per submission: A submission can have more than one appointment (e.g. a canceled first appointment and a rebooked second one). The client said "for each submission" (one row) but did not specify which appointment to use when there are multiple.

Recommendation: Use the latest appointment by bookedAt. Or alternatively use the latest non-CANCELED appointment. Needs client confirmation.


4. Reminder_Construct (HAPA)

Client says: For each submission, get submissionId → go to UserMessageVariant table → get variantTrack → go to AppointmentMessageVariantTemplate table → get mrt.

Source: UserMessageVariant.variantTrackAppointmentMessageVariantTemplate.mrt

Implementation:

  1. Query UserMessageVariant by submissionId (GSI: BySubmissionId)
  2. Get the variantTrack value
  3. Query AppointmentMessageVariantTemplate by variantTrack (GSI: ByVariantTrack)
  4. Return the mrt field

NOTE: The AppointmentMessageVariantTemplate table has multiple rows per variantTrack (one per messageType: confirmation, reminder_24hr, reminder_1hr). The mrt value should be the same across all message types for a given track. We will use any row for that track (e.g. the confirmation row).

Status: No issues. This resolves the earlier HAPA terminology question — mrt is the correct field.


5. Reminder_Variant_ID

Client says: For each submission, get submissionId → go to UserMessageVariant table → get variantTrack. That is the Reminder_Variant_ID.

Source: UserMessageVariant.variantTrack

Status: No issues. Confirmed this is the track number (e.g. 1, 2, 3, 4), not a template row id.


6. Reminder_ID

Client says: (left blank)

Status: Client did not define this column. We will leave it blank in the export for now, or omit it entirely. Needs client decision on whether to keep or drop this column.


7. Reminder_Sent_Timestamp

Client says: Appt_Scheduled_TimeStamp - 1 hr

Source: Calculated: subtract 1 hour from the appointment slot date+time.

Implementation: Take the combined AppointmentSlot.date + AppointmentSlot.startTime, subtract 1 hour.

ISSUE — This is a calculated estimate, not the actual send time. The system schedules reminders via EventBridge Scheduler (SendSMSAppt in mha-lambda-backend). The actual scheduling logic is:

  • If appointment is > 24hr away: schedules a 24hr and a 1hr reminder
  • If appointment is 1hr–24hr away: schedules only a 1hr reminder
  • If appointment is < 1hr away: no reminders are scheduled

So slot_time - 1hr may not match reality:

  • If the appointment was booked < 1hr before the slot, no 1hr reminder was sent
  • If the appointment was canceled before the reminder fired, it was never sent
  • The actual send time may vary slightly from the scheduled time

The client appears to accept this as a calculated approximation. No actual reminder send log exists in the database today.


8. Attended_Appointment (1/0)

Client says: Using the submission id, go to Appointment table, get the status. If the status is Assessment Completed, then 1, otherwise 0.

ISSUE — Assessment Completed is a Submission status, NOT an Appointment status.

The system has two separate status fields:

Field Possible values
Appointment.status (enum) SCHEDULED, COMPLETED, CANCELED, NO_SHOW
Submission.Status (string) Submitted, Active Engagement, Do Not Contact, Assessment Completed, Assessment InProcess, Assessment Scheduled, Accepted Referral, Attended Intake, Closed, Archive

Assessment Completed does not exist as an Appointment status. The client likely means one of:

Option A: Check Appointment.status === 'COMPLETED' — this is when staff marks the appointment itself as completed in the admin portal.

Option B: Check Submission.Status === 'Assessment Completed' — this is a broader submission-level status that may be set independently of the appointment status.

Recommendation: Clarify with client. Option A (Appointment.status === 'COMPLETED') is the most direct indicator that the appointment was attended. Option B is a downstream workflow status that staff sets manually and may not always align with appointment attendance.


9. Attendance_Timestamp

Client says: Using the submission id, go to Appointment table, get updatedAt. That is the Attendance_Timestamp.

Source: Appointment.updatedAt

NOTE — Fragility risk: updatedAt is automatically updated on any edit to the Appointment record, not just when marking attendance. If a staff member edits the notes field or changes status multiple times, updatedAt will reflect the last edit, not the attendance moment.

The client has explicitly chosen this field, so we will use it. There is no attendanceAt field in the current schema.

Implementation: Return Appointment.updatedAt when Attended_Appointment = 1, otherwise blank.


10. Status_Change_Post_Appt_Scheduled (0/1)

Client says: Check if there is any status change after status Assessment Scheduled.

Source: SubmissionStatusHistory

Implementation:

  1. Query SubmissionStatusHistory by submissionId (GSI: BySubmissionId), sorted by changedAt
  2. Find the row where newStatus = 'Assessment Scheduled'
  3. Check if any SubmissionStatusHistory rows exist with changedAt after that row's changedAt
  4. If yes → 1, if no → 0

NOTE: The status Assessment Scheduled is set automatically by the system when an appointment is booked (in appointments.service.js). This column checks whether anything changed AFTER that automatic status was set.

Status: No issues. Logic is clear.


11. Post_Appt_Status (list status)

Client says: Get all the status changes after status Assessment Completed, colon-separated string.

ISSUE — Did the client mean "after Assessment Scheduled" instead of "after Assessment Completed"?

The typical submission status flow is:

Submitted → Active Engagement → Assessment Scheduled → Assessment InProcess → Assessment Completed → Accepted Referral → Attended Intake → ...

If we collect statuses after Assessment Completed, we would only capture very late-stage transitions (e.g. Accepted Referral, Attended Intake). This seems unlikely to be what the client wants, especially since:

  • The previous column (Status_Change_Post_Appt_Scheduled) checks changes after Assessment Scheduled
  • The column name says "Post Appt Status" — i.e. after the appointment was scheduled, not after it was completed

Possibility 1 — Client meant "after Assessment Scheduled": Collect all newStatus values from SubmissionStatusHistory where changedAt is after the Assessment Scheduled row. This would show the full journey: Assessment InProcess, Assessment Completed, Accepted Referral, etc.

Possibility 2 — Client actually wants "after Assessment Completed": Collect only statuses that happen after Assessment Completed. This would show just Accepted Referral, Attended Intake, etc.

Recommendation: Clarify with client. "After Assessment Scheduled" makes more sense given the column name and the context of the previous column.

Implementation (once clarified):

  1. Query SubmissionStatusHistory by submissionId, sorted ascending by changedAt
  2. Find the anchor row (where newStatus = the clarified status)
  3. Collect all subsequent newStatus values
  4. Join with : separator

Summary of Issues Requiring Client Clarification

# Issue Question
1 Multiple appointments per submission When a submission has more than one appointment, which appointment should we use? Latest by bookedAt? Latest non-canceled? All of them?
2 Attended_Appointment — wrong status field Assessment Completed is a Submission status. The Appointment table uses COMPLETED. Should we check Appointment.status = 'COMPLETED' or Submission.Status = 'Assessment Completed'?
3 Reminder_ID — undefined This column was left blank. Should we omit it from the export, or does the client have a definition?
4 Post_Appt_Status — "after Assessment Completed" or "after Assessment Scheduled"? Collecting statuses after Assessment Completed only shows very late-stage changes. Did the client mean after Assessment Scheduled?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment