Files
Munich-news/docs/SUBSCRIBER_STATUS.md
2025-11-11 17:40:29 +01:00

5.7 KiB

Subscriber Status System

Overview

The newsletter system tracks subscribers with a status field that determines whether they receive newsletters.

Status Field

Database Schema

{
  _id: ObjectId("..."),
  email: "user@example.com",
  subscribed_at: ISODate("2025-11-11T15:50:29.478Z"),
  status: "active"  // or "inactive"
}

Status Values

Status Description Receives Newsletters
active Subscribed and active Yes
inactive Unsubscribed No

How It Works

Subscription Flow

User subscribes
    ↓
POST /api/subscribe
    ↓
Create subscriber with status: 'active'
    ↓
User receives newsletters

Unsubscription Flow

User unsubscribes
    ↓
POST /api/unsubscribe
    ↓
Update subscriber status: 'inactive'
    ↓
User stops receiving newsletters

Re-subscription Flow

Previously unsubscribed user subscribes again
    ↓
POST /api/subscribe
    ↓
Update status: 'active' + new subscribed_at date
    ↓
User receives newsletters again

API Endpoints

Subscribe

curl -X POST http://localhost:5001/api/subscribe \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com"}'

Creates subscriber with:

Unsubscribe

curl -X POST http://localhost:5001/api/unsubscribe \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com"}'

Updates subscriber:

  • status: "inactive"

Newsletter Sending

Who Receives Newsletters

Only subscribers with status: 'active' receive newsletters.

Sender Service Query:

subscribers_collection.find({'status': 'active'})

Admin API Query:

subscribers_collection.count_documents({'status': 'active'})

Testing

# Check active subscriber count
curl http://localhost:5001/api/admin/stats | jq '.subscribers'

# Output:
# {
#   "total": 10,
#   "active": 8
# }

Database Operations

Add Active Subscriber

db.subscribers.insertOne({
  email: "user@example.com",
  subscribed_at: new Date(),
  status: "active"
})

Deactivate Subscriber

db.subscribers.updateOne(
  { email: "user@example.com" },
  { $set: { status: "inactive" } }
)

Reactivate Subscriber

db.subscribers.updateOne(
  { email: "user@example.com" },
  { $set: { 
    status: "active",
    subscribed_at: new Date()
  }}
)

Query Active Subscribers

db.subscribers.find({ status: "active" })

Count Active Subscribers

db.subscribers.countDocuments({ status: "active" })

Common Issues

Issue: Stats show 0 active subscribers but subscribers exist

Cause: Old bug where stats checked {active: true} instead of {status: 'active'}

Solution: Fixed in latest version. Stats now correctly query {status: 'active'}

Verify:

# Check database directly
docker-compose exec mongodb mongosh munich_news -u admin -p changeme \
  --authenticationDatabase admin \
  --eval "db.subscribers.find({status: 'active'}).count()"

# Check via API
curl http://localhost:5001/api/admin/stats | jq '.subscribers.active'

Issue: Newsletter not sending to subscribers

Possible causes:

  1. Subscribers have status: 'inactive'
  2. No subscribers in database
  3. Email configuration issue

Debug:

# Check subscriber status
docker-compose exec mongodb mongosh munich_news -u admin -p changeme \
  --authenticationDatabase admin \
  --eval "db.subscribers.find().pretty()"

# Check active count
curl http://localhost:5001/api/admin/stats | jq '.subscribers'

# Try sending
curl -X POST http://localhost:5001/api/admin/send-newsletter \
  -H "Content-Type: application/json"

Migration Notes

If you have old subscribers without status field

Run this migration:

// Set all subscribers without status to 'active'
db.subscribers.updateMany(
  { status: { $exists: false } },
  { $set: { status: "active" } }
)

If you have subscribers with active: true/false field

Run this migration:

// Convert old 'active' field to 'status' field
db.subscribers.updateMany(
  { active: true },
  { $set: { status: "active" }, $unset: { active: "" } }
)

db.subscribers.updateMany(
  { active: false },
  { $set: { status: "inactive" }, $unset: { active: "" } }
)

Best Practices

1. Always Check Status

When querying subscribers for sending:

# ✅ Correct
subscribers_collection.find({'status': 'active'})

# ❌ Wrong
subscribers_collection.find({})  # Includes inactive

2. Soft Delete

Never delete subscribers - just set status to 'inactive':

# ✅ Correct - preserves history
subscribers_collection.update_one(
    {'email': email},
    {'$set': {'status': 'inactive'}}
)

# ❌ Wrong - loses data
subscribers_collection.delete_one({'email': email})

3. Track Subscription History

Consider adding fields:

{
  email: "user@example.com",
  status: "active",
  subscribed_at: ISODate("2025-01-01"),
  unsubscribed_at: null,  // Set when status changes to inactive
  resubscribed_count: 0   // Increment on re-subscription
}

4. Validate Before Sending

# Check subscriber count before sending
count = subscribers_collection.count_documents({'status': 'active'})
if count == 0:
    return {'error': 'No active subscribers'}