Skip to content

Commit 86447ce

Browse files
AchoArnoldCopilot
andauthored
feat: add bulk messages history table with status counts (#898)
* feat: add bulk messages history table with status counts - Add GET /v1/bulk-messages endpoint that returns the last 10 bulk message batches for the authenticated user - Add optimized SQL query using GROUP BY and FILTER to aggregate status counts (scheduled, pending, sent, delivered, failed) from millions of messages - Add Vuetify data table on /bulk-messages page showing history - Add View action that navigates to /search-messages with the bulk message ID pre-filled as a query parameter - Update search-messages page to read ?query= URL param and auto-fill + auto-search on page load Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor: use StartWithLogger in GetBulkMessages Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat: add error notification for bulk messages history fetch Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Generate swagger docs and models * fix: address PR review comments - Fix double-search CAPTCHA conflict by adding initialLoadComplete guard to prevent the options watcher from firing before mounted completes - Fix nil slice serializing as null by using make() for empty slice init - Regenerate swagger docs to match actual type names Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor: use v-simple-table for bulk message history Replace v-data-table with v-simple-table to match the pattern used in the settings page. Added a short description paragraph explaining what the table shows. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: handle phone numbers without + prefix and fix CSV SendTime parsing - Add + prefix normalization in validateMessages before phonenumbers.Parse - Change SendTime from *time.Time to string (SendTimeRaw) for CSV unmarshaling - Add GetSendTime() method that parses multiple date formats gracefully - Empty SendTime fields no longer cause 'Cannot read contents' errors - Support RFC3339, YYYY-MM-DDTHH:MM:SS, YYYY-MM-DD HH:MM:SS, YYYY-MM-DD formats Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat: add expired count to bulk messages history table Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * revert: remove + prefix normalization in phone number validation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: increase search query max length from 20 to 50 characters Allows searching by bulk message IDs (e.g. bulk-8dcc3d68-57bd-4913-a5ff-52c107ffc0c9) which are 41 characters long. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test: add bulk SMS integration tests for CSV and Excel upload - TestBulkSMS_CSV: uploads CSV with 1 message, fires SENT event, verifies history - TestBulkSMS_Excel: uploads Excel with 2 messages, fires DELIVERED on one, verifies mixed status counts - Add shared helpers: uploadBulkFile, fetchBulkMessages, searchMessages, findBulkEntry - Add excelize/v2 dependency for Excel file creation in tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: use correct query params for message index endpoint in integration tests The searchMessages helper was using 'owners' (plural) param and missing 'contact', but the GET /v1/messages endpoint requires 'owner' (singular) and 'contact' fields. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: correct expected status in TestBulkSMS_Excel assertion Message 2 transitions to 'scheduled' after waitForFCMPush, not 'pending'. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore: remove old heartbeats index drop code The old indexes (owner_1_timestamp_-1, user_id_1) have already been dropped in production, so this migration code is no longer needed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent d85234a commit 86447ce

23 files changed

Lines changed: 7325 additions & 5977 deletions

api/docs/docs.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,44 @@ const docTemplate = `{
144144
}
145145
},
146146
"/bulk-messages": {
147+
"get": {
148+
"security": [
149+
{
150+
"ApiKeyAuth": []
151+
}
152+
],
153+
"description": "Fetches the last 10 bulk message order summaries for the authenticated user showing counts per status.",
154+
"consumes": [
155+
"application/json"
156+
],
157+
"produces": [
158+
"application/json"
159+
],
160+
"tags": [
161+
"BulkSMS"
162+
],
163+
"summary": "List bulk message orders",
164+
"responses": {
165+
"200": {
166+
"description": "OK",
167+
"schema": {
168+
"$ref": "#/definitions/responses.BulkMessagesResponse"
169+
}
170+
},
171+
"401": {
172+
"description": "Unauthorized",
173+
"schema": {
174+
"$ref": "#/definitions/responses.Unauthorized"
175+
}
176+
},
177+
"500": {
178+
"description": "Internal Server Error",
179+
"schema": {
180+
"$ref": "#/definitions/responses.InternalServerError"
181+
}
182+
}
183+
}
184+
},
147185
"post": {
148186
"security": [
149187
{
@@ -1759,6 +1797,12 @@ const docTemplate = `{
17591797
"$ref": "#/definitions/responses.Unauthorized"
17601798
}
17611799
},
1800+
"402": {
1801+
"description": "Payment Required",
1802+
"schema": {
1803+
"$ref": "#/definitions/responses.PaymentRequired"
1804+
}
1805+
},
17621806
"422": {
17631807
"description": "Unprocessable Entity",
17641808
"schema": {
@@ -3299,6 +3343,53 @@ const docTemplate = `{
32993343
}
33003344
}
33013345
},
3346+
"entities.BulkMessage": {
3347+
"type": "object",
3348+
"required": [
3349+
"created_at",
3350+
"delivered_count",
3351+
"failed_count",
3352+
"pending_count",
3353+
"request_id",
3354+
"scheduled_count",
3355+
"sent_count",
3356+
"total"
3357+
],
3358+
"properties": {
3359+
"created_at": {
3360+
"type": "string",
3361+
"example": "2022-06-05T14:26:02.302718+03:00"
3362+
},
3363+
"delivered_count": {
3364+
"type": "integer",
3365+
"example": 25
3366+
},
3367+
"failed_count": {
3368+
"type": "integer",
3369+
"example": 5
3370+
},
3371+
"pending_count": {
3372+
"type": "integer",
3373+
"example": 30
3374+
},
3375+
"request_id": {
3376+
"type": "string",
3377+
"example": "bulk-32343a19-da5e-4b1b-a767-3298a73703cb"
3378+
},
3379+
"scheduled_count": {
3380+
"type": "integer",
3381+
"example": 50
3382+
},
3383+
"sent_count": {
3384+
"type": "integer",
3385+
"example": 40
3386+
},
3387+
"total": {
3388+
"type": "integer",
3389+
"example": 150
3390+
}
3391+
}
3392+
},
33023393
"entities.Discord": {
33033394
"type": "object",
33043395
"required": [
@@ -4599,6 +4690,30 @@ const docTemplate = `{
45994690
}
46004691
}
46014692
},
4693+
"responses.BulkMessagesResponse": {
4694+
"type": "object",
4695+
"required": [
4696+
"data",
4697+
"message",
4698+
"status"
4699+
],
4700+
"properties": {
4701+
"data": {
4702+
"type": "array",
4703+
"items": {
4704+
"$ref": "#/definitions/entities.BulkMessage"
4705+
}
4706+
},
4707+
"message": {
4708+
"type": "string",
4709+
"example": "Request handled successfully"
4710+
},
4711+
"status": {
4712+
"type": "string",
4713+
"example": "success"
4714+
}
4715+
}
4716+
},
46024717
"responses.DiscordResponse": {
46034718
"type": "object",
46044719
"required": [

0 commit comments

Comments
 (0)