| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 |
- // Package routing is the recipient resolution + delivery enqueue step.
- // M1: broadcast mode — every alert to a company goes to every active
- // fcm_token of every active individual in that company. M2 replaces
- // this with the rules engine from SPEC §6 (subscriptions, opt-in,
- // quiet hours, routing rules, …).
- //
- // The interface is small: ResolveTokens returns the set of
- // (individual_id, fcm_token, locale) tuples that should receive
- // the alert. deliverd-fcm is the only consumer in M1.
- package routing
- import (
- "context"
- "fmt"
- "git3.techno-world.net/lrosales/broad-announce/internal/postgres"
- )
- // Target is one device to deliver to.
- type Target struct {
- IndividualID string
- FCMToken string
- Locale string
- }
- // Resolver looks up recipients for a (company, alert) pair.
- type Resolver struct {
- pool *postgres.Pool
- }
- // New constructs a Resolver.
- func New(pool *postgres.Pool) *Resolver { return &Resolver{pool: pool} }
- // ResolveTokens returns every active FCM token for every active
- // individual in the given company. This is the M1 broadcast path.
- // M2 swaps this for the rules engine.
- //
- // One DB round-trip via a single join. Add a per-company limit
- // here if a malicious company can ever register 1M tokens.
- func (r *Resolver) ResolveTokens(ctx context.Context, companyID string) ([]Target, error) {
- rows, err := r.pool.Query(ctx, `
- SELECT i.id, t.token, COALESCE(t.locale, i.locale, 'en')
- FROM individuals i
- JOIN fcm_tokens t ON t.individual_id = i.id
- WHERE i.company_id = $1
- AND i.status = 'active'
- AND t.status = 'active'
- ORDER BY i.id, t.id
- `, companyID)
- if err != nil {
- return nil, fmt.Errorf("resolve tokens: %w", err)
- }
- defer rows.Close()
- var out []Target
- for rows.Next() {
- var t Target
- if err := rows.Scan(&t.IndividualID, &t.FCMToken, &t.Locale); err != nil {
- return nil, err
- }
- out = append(out, t)
- }
- return out, rows.Err()
- }
|