Psnuser -
CREATE TABLE psnuser ( id UUID PRIMARY KEY, account_type ENUM('master', 'sub'), master_id UUID REFERENCES psnuser(id) NULL, monthly_spend_limit_cents INT DEFAULT 0, CHECK ( (account_type = 'master' AND master_id IS NULL) OR (account_type = 'sub' AND master_id IS NOT NULL) ) ); Note: In production, this is denormalized into a graph database (Neo4j or AWS Neptune) to avoid recursive joins. To guarantee the "PlayStation Experience," the psnuser service must expose specific Service Level Indicators (SLIs):
private List<PSNUser> getCachedFriendsList(String userId) // Return stale cache + emit degraded metric psnuser
# Pseudo-implementation of entitlement check def user_has_license(account_uuid, game_id): # L1: Redis cache (TTL 30s) if redis.sismember(f"entitlements:account_uuid", game_id): return True # L2: DynamoDB with conditional check result = dynamodb.get_item(Key='uuid': account_uuid, ConsistentRead=True) # Update cache asynchronously async_update_cache(account_uuid, result['entitlements']) return game_id in result['entitlements'] The psnuser service is the Security Token Service (STS) for all PSN APIs. The critical insight is the scope-based fragmentation of the user object. 5.1 OAuth Scopes as ACLs | Scope | Grants Access To | Risk Level | | :--- | :--- | :--- | | psn:profile.read | Online ID, Avatar URL | Low | | psn:friends.write | Add/remove friends | Medium | | psn:entitlements.read | List owned games | Medium (Privacy) | | psn:wallet.purchase | Charge stored value | Critical | 5.2 The Refresh Token Anti-Pattern Third-party applications (e.g., Discord, Trophy tracking sites) request long-lived refresh tokens for psnuser . If an attacker obtains a refresh token with wallet.purchase scope, they can drain the wallet. CREATE TABLE psnuser ( id UUID PRIMARY KEY,
| SLI | Target (SLO) | Instrumentation | | :--- | :--- | :--- | | | < 200 ms | Prometheus histogram on token validation | | Entitlement consistency | 99.99% (no false negatives) | Audit log of license_granted vs license_denied | | Online ID uniqueness | 100% | Database unique constraint violation metric | | GDPR deletion latency | < 30 days (regulatory) | Queue depth of psnuser_deletion topic | 8. Failure Scenarios & Mitigations 8.1 Cascading Failure via Social Graph If the psnuser service is slow, any service that displays friend lists (e.g., "What are my friends playing?") will also fail. The mitigation is circuit breaking : Failure Scenarios & Mitigations 8
message PSNUser UUID account_uuid = 1; // Immutable, partition key string online_id = 2; // Mutable, unique secondary index AccountFlags flags = 3; // Bitmask: adult, mfa_enabled, sub_account map<Region, Wallet> wallets = 4; // Multi-currency support repeated Entitlement entitlements = 5; // Game licenses, PS+ status SocialGraph social = 6; // Friends, blocks, following (bidirectional) PrivacySettings privacy = 7; // Telemetry opt-out, presence visibility
| Sub-domain | Storage Technology | Consistency Model | | :--- | :--- | :--- | | | CockroachDB (Global, Strong) | Serializable | | Profile & Social | Cassandra + Redis | Eventual (Read-your-writes) | | Entitlements/Licenses | AWS DynamoDB (GSI over-specified) | Strong (for purchases) | | Telemetry/Trophies | Apache Kafka + S3 Data Lake | At-least-once |
// Hystrix pattern @HystrixCommand(fallbackMethod = "getCachedFriendsList") public List<PSNUser> getFriends(String userId) return psnUserService.fetchBatch(userId.getFriendIds());