-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Overview
Implement anonymous subscription tracking using hashed record IDs to count Feed popularity while preserving user privacy.
Design
FeedSubscription records use SHA256-hashed record IDs to ensure:
- Same user + same feed = same record ID (deduplication across devices)
- Hash includes feedRecordName so subscriptions can't be correlated across feeds
- One-way hash prevents reversing to identify users
See .claude/FEED_SUBSCRIPTION_DESIGN.md for complete design specification.
Implementation Tasks
1. CelestraKit: FeedSubscription Model
File: Packages/CelestraKit/Sources/CelestraKit/Models/FeedSubscription.swift
import Foundation
public struct FeedSubscription: Sendable, Hashable, Codable {
public let recordName: String
public let feedRecordName: String
public init(recordName: String, feedRecordName: String) {
self.recordName = recordName
self.feedRecordName = feedRecordName
}
}2. CelestraKit: CloudKit Conversion Extension
File: Packages/CelestraKit/Sources/CelestraKit/Extensions/FeedSubscription+MistKit.swift
import MistKit
extension FeedSubscription: CloudKitConvertible {
public func toFieldsDict() -> [String: FieldValue] {
return [
"feedRecordName": .string(feedRecordName)
]
}
public init(from record: RecordInfo) throws {
guard case .string(let feedRecordName) = record.fields["feedRecordName"],
!feedRecordName.isEmpty else {
throw CloudKitConversionError.missingRequiredField(
fieldName: "feedRecordName",
recordType: "FeedSubscription"
)
}
self.init(
recordName: record.recordName,
feedRecordName: feedRecordName
)
}
}3. CelestraKit: Subscription Service
File: Packages/CelestraKit/Sources/CelestraKit/Services/SubscriptionService.swift
Core functionality for managing subscriptions with SHA256-hashed record IDs.
4. CelestraCloudKit: Server-Side Aggregation
Add querySubscriptionCount(for:) and updateSubscriberCounts() methods to CloudKitService extension.
5. CLI: Update Subscriber Counts Command
New command: celestra-cloud update-subscriber-counts
6. GitHub Actions: Scheduled Aggregation
Daily cron job to update subscriber counts in production.
Testing Checklist
Unit Tests
- FeedSubscription model serialization/deserialization
- CloudKit conversion (toFieldsDict, init from RecordInfo)
- Record ID hashing produces deterministic results
- Same user + same feed = same hash
- Different users + same feed = different hashes
- Same user + different feeds = different hashes
Integration Tests
- Subscribe to feed creates FeedSubscription record
- Subscribe is idempotent (multiple calls don't error)
- Unsubscribe deletes FeedSubscription record
- isSubscribed returns correct state
- subscribeIfPossible handles not authenticated gracefully
- Server counts subscriptions correctly
- Server updates Feed.subscriberCount field
Privacy Verification
- Record IDs are hashed (not raw user IDs)
- Cannot correlate subscriptions across different feeds
- Cannot reverse hash to identify users
- No personally identifiable information stored
References
- Design:
.claude/FEED_SUBSCRIPTION_DESIGN.md - Schema:
schema.ckdb:96-114