feat(subscriptions): implement subscription quota enforcement
- Apply QuotaGuard + @RequireQuota to listing creation and analytics endpoints - Add QuotaExceeded domain event emitted when quota is exceeded - Create ListingCreatedUsageHandler to auto-meter usage on listing creation - Create QuotaExceededListener to send email notifications on quota exceeded - Add maxAnalyticsQueries and maxMediaUploads fields to Plan model - Add quota.exceeded email notification template - Define quota limits per plan tier in seed data - Add 15 unit tests covering guard, event handler, listener, and event Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
import { QuotaExceededEvent } from '../events/quota-exceeded.event';
|
||||
|
||||
describe('QuotaExceededEvent', () => {
|
||||
it('creates event with correct properties', () => {
|
||||
const event = new QuotaExceededEvent('user-1', 'listings_created', 3, 3);
|
||||
|
||||
expect(event.eventName).toBe('quota.exceeded');
|
||||
expect(event.aggregateId).toBe('user-1');
|
||||
expect(event.metric).toBe('listings_created');
|
||||
expect(event.limit).toBe(3);
|
||||
expect(event.used).toBe(3);
|
||||
expect(event.occurredAt).toBeInstanceOf(Date);
|
||||
});
|
||||
|
||||
it('creates event for analytics metric', () => {
|
||||
const event = new QuotaExceededEvent('user-2', 'analytics_queries', 0, 0);
|
||||
|
||||
expect(event.metric).toBe('analytics_queries');
|
||||
expect(event.limit).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import { type DomainEvent } from '@modules/shared/domain/domain-event';
|
||||
|
||||
export class QuotaExceededEvent implements DomainEvent {
|
||||
readonly eventName = 'quota.exceeded';
|
||||
readonly occurredAt = new Date();
|
||||
|
||||
constructor(
|
||||
public readonly aggregateId: string, // userId
|
||||
public readonly metric: string,
|
||||
public readonly limit: number,
|
||||
public readonly used: number,
|
||||
) {}
|
||||
}
|
||||
Reference in New Issue
Block a user