Reminders: no way to view or cancel pending reminders (Slack-style "Later" view) #19

Open
opened 2026-08-04 16:18:43 +00:00 by mohlec · 1 comment
Owner

Problem

There is no way for a user to see the reminders they have already set. Once you pick a time from Remind -> 30 mins / 1 hour / ..., the reminder is stored but becomes invisible - you cannot list, review, or cancel it.

Slack solves this with its "Later" view (sidebar section listing saved/reminded items with In progress / Archived / Completed tabs).

Why this matters

Users set a reminder, get no lasting confirmation, and have no way to verify it exists. Combined with the 5s-delayed confirmation (see the hairpin-NAT issue in slash-deploy), it reads as "the feature did nothing" - which is how this was originally reported.

Current state (verified 2026-08-04)

The backend works correctly end-to-end - reminders are stored in the postreminders table and delivered on time as a DM from system-bot (observed live: a reminder due 14:59:39 was delivered at 15:00:00).

What does not exist:

Server / API - only one route is registered:

  • POST /api/v4/users/{user_id}/posts/{post_id}/reminder (server/channels/api4/post.go:44)
  • There is no GET endpoint to list a user's reminders, and no DELETE to cancel one.

Webapp - only two components exist:

  • components/dot_menu/post_reminder_submenu.tsx (the "Remind" submenu)
  • components/post_reminder_custom_time_picker_modal/ (custom time picker)

There is no list/view component of any kind.

Storage note: GetPostReminders() returns reminders and deletes them in the same call (see app/post.go CheckPostReminders, and the MM-45595 comment). Any "Later" view would need to account for this - delivered reminders leave no record, so a Completed/Archived tab would need a schema change or a separate audit trail.

Scope of work

This is a genuine feature build in the fork, not a config toggle:

  1. Server: add GET /users/{user_id}/reminders (list pending) and DELETE .../reminder (cancel). Store layer already has postreminders; needs a non-destructive read.
  2. Webapp: a list view - RHS panel or sidebar entry - showing pending reminders with the target time and a link to the source post, plus a cancel action.
  3. Optional: "Completed" history, which requires retaining delivered reminders (schema change).

Suggested phasing

  • Phase 1 (high value, low cost): GET endpoint + simple RHS list with cancel. Solves the "did my reminder save?" problem.
  • Phase 2: history/archive tabs, if wanted.

Upstream consideration

Upstream Mattermost has no such view either, so this is net-new fork divergence - it will need carrying across upstream merges (track in DIVERGENCE.md). Worth considering whether to propose it upstream instead.

Reported by user 2026-08-04. Related: hairpin-NAT/link-preview delay issue in slash-deploy.

## Problem There is no way for a user to see the reminders they have already set. Once you pick a time from **Remind -> 30 mins / 1 hour / ...**, the reminder is stored but becomes invisible - you cannot list, review, or cancel it. Slack solves this with its **"Later"** view (sidebar section listing saved/reminded items with In progress / Archived / Completed tabs). ## Why this matters Users set a reminder, get no lasting confirmation, and have no way to verify it exists. Combined with the 5s-delayed confirmation (see the hairpin-NAT issue in slash-deploy), it reads as "the feature did nothing" - which is how this was originally reported. ## Current state (verified 2026-08-04) The backend works correctly end-to-end - reminders are stored in the `postreminders` table and delivered on time as a DM from `system-bot` (observed live: a reminder due 14:59:39 was delivered at 15:00:00). What does **not** exist: **Server / API** - only one route is registered: - `POST /api/v4/users/{user_id}/posts/{post_id}/reminder` (`server/channels/api4/post.go:44`) - There is **no GET endpoint** to list a user's reminders, and **no DELETE** to cancel one. **Webapp** - only two components exist: - `components/dot_menu/post_reminder_submenu.tsx` (the "Remind" submenu) - `components/post_reminder_custom_time_picker_modal/` (custom time picker) There is no list/view component of any kind. **Storage note:** `GetPostReminders()` returns reminders *and deletes them in the same call* (see `app/post.go` `CheckPostReminders`, and the MM-45595 comment). Any "Later" view would need to account for this - delivered reminders leave no record, so a Completed/Archived tab would need a schema change or a separate audit trail. ## Scope of work This is a genuine feature build in the fork, not a config toggle: 1. **Server:** add `GET /users/{user_id}/reminders` (list pending) and `DELETE .../reminder` (cancel). Store layer already has `postreminders`; needs a non-destructive read. 2. **Webapp:** a list view - RHS panel or sidebar entry - showing pending reminders with the target time and a link to the source post, plus a cancel action. 3. Optional: "Completed" history, which requires retaining delivered reminders (schema change). ## Suggested phasing - **Phase 1 (high value, low cost):** GET endpoint + simple RHS list with cancel. Solves the "did my reminder save?" problem. - **Phase 2:** history/archive tabs, if wanted. ## Upstream consideration Upstream Mattermost has no such view either, so this is net-new fork divergence - it will need carrying across upstream merges (track in `DIVERGENCE.md`). Worth considering whether to propose it upstream instead. Reported by user 2026-08-04. Related: hairpin-NAT/link-preview delay issue in `slash-deploy`.
Author
Owner

Design is done and merged as docs, no code yet. Keeping this open until the
feature ships.

Approach: a separate plugin (slash-reminders-plugin), not a change to this
repo. Zero commits here. The mobile entry point costs one call site in the
existing shared plugin-launcher helper in slash-mobile; nothing else in either
fork.

Scope: reminders only — not a merged Slack-style "Later" list. Saved messages
already work and stay where they are. Adds what's missing today: a list view with
time remaining, edit / reschedule / snooze / complete / archive, and standalone
reminders with their own text and no attached message.

The finding that shaped it: GetPostReminders is a single
DELETE ... RETURNING PostId, UserId, so core destroys the row when it fires and
discards TargetTime in the process. That means a read-only view over
PostReminders cannot support a "completed" list at all — the row is gone at the
exact moment it becomes actionable. Snooze fails from the other direction, since
rescheduling needs the row changed or core still fires at the old time.

So the plugin drains rows out of PostReminders into its own table and takes
ownership of scheduling, rather than mirroring. The post menus in both clients stay
untouched and remain the primary way reminders get created — the plugin consumes
what they write. If the plugin is ever disabled, rows simply accumulate and core
fires them exactly as it does today.

Two side effects worth recording: reminders become more punctual (per-minute
firing vs core's 5-minute boundaries), and reminders set less than ~90 seconds out
are deliberately left to core, so they won't appear in the list.

Full PRD, task breakdown and two ADRs are in slash-deploy/docs (private).

Design is done and merged as docs, no code yet. Keeping this open until the feature ships. **Approach:** a separate plugin (`slash-reminders-plugin`), not a change to this repo. Zero commits here. The mobile entry point costs one call site in the existing shared plugin-launcher helper in `slash-mobile`; nothing else in either fork. **Scope:** reminders only — not a merged Slack-style "Later" list. Saved messages already work and stay where they are. Adds what's missing today: a list view with time remaining, edit / reschedule / snooze / complete / archive, and standalone reminders with their own text and no attached message. **The finding that shaped it:** `GetPostReminders` is a single `DELETE ... RETURNING PostId, UserId`, so core destroys the row when it fires and discards `TargetTime` in the process. That means a read-only view over `PostReminders` cannot support a "completed" list at all — the row is gone at the exact moment it becomes actionable. Snooze fails from the other direction, since rescheduling needs the row changed or core still fires at the old time. So the plugin drains rows out of `PostReminders` into its own table and takes ownership of scheduling, rather than mirroring. The post menus in both clients stay untouched and remain the primary way reminders get created — the plugin consumes what they write. If the plugin is ever disabled, rows simply accumulate and core fires them exactly as it does today. Two side effects worth recording: reminders become more punctual (per-minute firing vs core's 5-minute boundaries), and reminders set less than ~90 seconds out are deliberately left to core, so they won't appear in the list. Full PRD, task breakdown and two ADRs are in `slash-deploy/docs` (private).
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
slash/slash-server#19
No description provided.