feat: send email notifications for missed messages

- New cron job in cluster
- Handle presence and other concerns
- Toggle in app to disable email notifications
- Handles other edge cases such as cooldown period
- Simple html email with simple message

Closes #117
This commit is contained in:
talksik
2026-04-09 14:15:34 -07:00
parent 6fe5af8d8d
commit 51c4c6c822
25 changed files with 725 additions and 29 deletions
+27
View File
@@ -3,6 +3,7 @@ package human
import (
"context"
"errors"
"time"
"github.com/flowy-live/llink/internal/utils"
"github.com/jackc/pgx/v5/pgxpool"
@@ -16,6 +17,12 @@ type Service interface {
GetByEmail(ctx context.Context, email string) (*Human, error)
// GetByID returns ErrNotFound if no human found
GetByID(ctx context.Context, id string) (*Human, error)
// ListAll returns all humans
ListAll(ctx context.Context) ([]*Human, error)
// UpdateEmailNotificationsEnabled toggles email notification preference
UpdateEmailNotificationsEnabled(ctx context.Context, id string, enabled bool) error
// UpdateLastEmailNotificationSentAt records when the last notification email was sent
UpdateLastEmailNotificationSentAt(ctx context.Context, id string, t time.Time) error
}
type serviceImpl struct {
@@ -62,3 +69,23 @@ func (s *serviceImpl) GetByID(ctx context.Context, id string) (*Human, error) {
}
return h, err
}
func (s *serviceImpl) ListAll(ctx context.Context) ([]*Human, error) {
return s.repo.listAll(ctx)
}
func (s *serviceImpl) UpdateEmailNotificationsEnabled(ctx context.Context, id string, enabled bool) error {
err := s.repo.updateEmailNotificationsEnabled(ctx, id, enabled)
if errors.Is(err, errNotFound) {
return ErrNotFound
}
return err
}
func (s *serviceImpl) UpdateLastEmailNotificationSentAt(ctx context.Context, id string, t time.Time) error {
err := s.repo.updateLastEmailNotificationSentAt(ctx, id, t)
if errors.Is(err, errNotFound) {
return ErrNotFound
}
return err
}