Skip to content

Commit 93d8ac9

Browse files
AchoArnoldCopilot
andcommitted
docs: link to existing feature pages instead of re-explaining scheduling and send rate
Link to https://docs.httpsms.com/features/scheduling-sms-messages and https://docs.httpsms.com/features/control-sms-send-rate instead of repeating their explanations. Add detailed MessageSendSchedule (send windows) section since it's the only new feature without its own docs page. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 1840217 commit 93d8ac9

3 files changed

Lines changed: 82 additions & 6 deletions

File tree

docs/superpowers/plans/2026-05-03-scheduling-send-refactor.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44
55
**Goal:** Allow users to send SMS at an exact time (bypassing scheduling) when `SendAt` is specified, and replace the 1-second bulk hack with rate-based dispatch delays.
66

7-
**Architecture:** Add a transient `ExactSendTime` flag flowing through the event system. When true, bypass rate-limit and schedule window logic in notification scheduling. For bulk sends without explicit time, compute dispatch delay from `MessagesPerMinute` per-phone instead of hardcoded 1s.
7+
**Related docs:**
8+
9+
- [Scheduling SMS Messages](https://docs.httpsms.com/features/scheduling-sms-messages) — the existing `SendAt`/`SendTime` feature
10+
- [Control SMS Send Rate](https://docs.httpsms.com/features/control-sms-send-rate) — the existing `MessagesPerMinute` rate-limiting feature
11+
12+
**Architecture:** Add a transient `ExactSendTime` flag flowing through the event system. When true, bypass [rate-limit](https://docs.httpsms.com/features/control-sms-send-rate) and schedule window logic in notification scheduling. For bulk sends without explicit time, compute dispatch delay from `MessagesPerMinute` per-phone instead of hardcoded 1s.
813

914
**Tech Stack:** Go, Fiber, GORM, CockroachDB, Google Cloud Tasks (CloudEvents)
1015

docs/superpowers/specs/2026-05-03-entitlement-service-design.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Problem
44

5-
The send schedule feature (and future features) need usage limits based on the user's subscription plan. Free users should be limited to 1 send schedule; paid users get unlimited. The system must be:
5+
The [MessageSendSchedule](./2026-05-03-scheduling-send-refactor-design.md#messagesendschedule-send-windows--new-feature) feature (and future features) need usage limits based on the user's subscription plan. Free users should be limited to 1 send schedule; paid users get unlimited. The system must be:
66

77
- **Scalable**: Easy to add new entity limits without architectural changes
88
- **Configurable**: Disabled by default for self-hosted deployments, enabled via env var for cloud

docs/superpowers/specs/2026-05-03-scheduling-send-refactor-design.md

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
# Scheduling Send Refactor Design
22

3+
## Related Documentation
4+
5+
- [Scheduling SMS Messages](https://docs.httpsms.com/features/scheduling-sms-messages) — existing `SendAt`/`SendTime` scheduling feature
6+
- [Control SMS Send Rate](https://docs.httpsms.com/features/control-sms-send-rate) — existing `MessagesPerMinute` rate-limiting feature
7+
38
## Problem Statement
49

510
The current SMS scheduling logic has two issues:
611

7-
1. **No way to send at an exact time without scheduling interference.** When a user specifies a `SendTime`/`SendAt`, the system still applies rate-limiting and schedule window logic, which may shift the actual send time.
12+
1. **No way to send at an exact time without scheduling interference.** When a user specifies a `SendTime`/`SendAt` (see [Scheduling SMS Messages](https://docs.httpsms.com/features/scheduling-sms-messages)), the system still applies rate-limiting and schedule window logic, which may shift the actual send time.
813

914
2. **Bulk message contention.** When bulk messages (API or CSV) are sent, all events arrive at the Cloud Tasks queue near-simultaneously, causing DB serialization conflicts in `PhoneNotificationRepository.Schedule()` (which uses `SELECT ... ORDER BY scheduled_at DESC` in a transaction). The current workaround is a hardcoded 1-second spacing hack.
1015

1116
## Proposed Solution
1217

1318
### Core Principle
1419

15-
- **Explicit `SendTime`** = send at exactly that time, bypass all scheduling logic.
16-
- **No `SendTime`** = apply full scheduling logic (rate-limit + schedule windows), with rate-based Cloud Task dispatch delay to prevent DB contention.
20+
- **Explicit `SendTime`** = send at exactly that time, bypass all scheduling logic. See [Scheduling SMS Messages](https://docs.httpsms.com/features/scheduling-sms-messages) for how `SendAt` works.
21+
- **No `SendTime`** = apply full scheduling logic ([rate-limit](https://docs.httpsms.com/features/control-sms-send-rate) + schedule windows), with rate-based Cloud Task dispatch delay to prevent DB contention.
1722

1823
### Design
1924

@@ -111,7 +116,73 @@ User sends request
111116
### What Does NOT Change
112117

113118
- The `MessageSendSchedule` entity and its `ResolveScheduledAt()` logic
114-
- The `SendScheduleService` CRUD operations
119+
- The `MessageSendScheduleService` CRUD operations
115120
- The phone notification entity schema (no new DB columns)
116121
- The Android app behavior
117122
- The web frontend (models auto-generated from Swagger)
123+
124+
---
125+
126+
## MessageSendSchedule (Send Windows) — New Feature
127+
128+
This is the only scheduling mechanism that does **not** have a dedicated documentation page yet. Unlike [Scheduling SMS Messages](https://docs.httpsms.com/features/scheduling-sms-messages) (one-time `SendAt`) and [Control SMS Send Rate](https://docs.httpsms.com/features/control-sms-send-rate) (`MessagesPerMinute` throttling), MessageSendSchedule defines **recurring availability windows** that control when a phone is allowed to send outgoing SMS messages.
129+
130+
### Concept
131+
132+
A `MessageSendSchedule` is a named set of time windows (per day of week) that define when the phone can send. Messages arriving outside those windows are delayed until the next available window opens.
133+
134+
### Entity
135+
136+
```go
137+
type MessageSendSchedule struct {
138+
ID uuid.UUID
139+
UserID UserID
140+
Name string // e.g. "Business Hours"
141+
Timezone string // IANA timezone e.g. "Europe/Tallinn"
142+
IsActive bool
143+
Windows []MessageSendScheduleWindow // per-day availability slots
144+
CreatedAt time.Time
145+
UpdatedAt time.Time
146+
}
147+
148+
type MessageSendScheduleWindow struct {
149+
DayOfWeek int // 0=Sunday, 6=Saturday
150+
StartMinute int // minutes from midnight (e.g. 540 = 9:00)
151+
EndMinute int // minutes from midnight (e.g. 1020 = 17:00)
152+
}
153+
```
154+
155+
### How It Works
156+
157+
1. A user creates a schedule via `POST /v1/send-schedules` with a name, timezone, and one or more windows.
158+
2. The schedule is linked to a phone via a `ScheduleID` field on the phone entity.
159+
3. When a message is queued (without an explicit `SendAt`), the `PhoneNotificationRepository.Schedule()` method calls `MessageSendSchedule.ResolveScheduledAt(now)` to find the next allowed send time.
160+
4. If the current time falls within a window, the message sends immediately. If not, it's delayed to the start of the next available window.
161+
162+
### API Endpoints
163+
164+
| Method | Endpoint | Description |
165+
| ------ | --------------------------------- | --------------------------- |
166+
| GET | `/v1/send-schedules` | List all user schedules |
167+
| POST | `/v1/send-schedules` | Create a new schedule |
168+
| PUT | `/v1/send-schedules/{scheduleID}` | Update an existing schedule |
169+
| DELETE | `/v1/send-schedules/{scheduleID}` | Delete a schedule |
170+
171+
### Validation Rules
172+
173+
- `name`: required, 2–100 characters
174+
- `timezone`: required, valid IANA timezone
175+
- `windows[].day_of_week`: 0–6
176+
- `windows[].start_minute`: 0–1439
177+
- `windows[].end_minute`: 1–1440, must be greater than `start_minute`
178+
- Max 6 windows per day
179+
- No overlapping windows on the same day
180+
181+
### Entitlement
182+
183+
Free users are limited to 1 schedule. Paid users get unlimited schedules. Enforced via `EntitlementService.Check()` in the handler before creation.
184+
185+
### Interaction with Other Scheduling Features
186+
187+
- **[Scheduling SMS Messages](https://docs.httpsms.com/features/scheduling-sms-messages)** (`SendAt`): When provided, bypasses send windows entirely (exact send time).
188+
- **[Control SMS Send Rate](https://docs.httpsms.com/features/control-sms-send-rate)** (`MessagesPerMinute`): Applied independently — rate-limiting still applies within allowed windows. Both constraints compose: the message must be within a window AND respect the rate limit.

0 commit comments

Comments
 (0)