feat: Add Stripe payment integration and subscription management

- Add Stripe.net SDK for payment processing
- Implement StripeService with checkout sessions, customer portal, webhooks
- Implement SubscriptionService for quota management
- Add quota enforcement to CVCheckService
- Create Pricing, Billing, Settings pages
- Add checkout success/cancel pages
- Update Check and Dashboard with usage indicators
- Add ResetMonthlyUsageJob for billing cycle resets
- Add database migration for subscription fields

Plan tiers: Free (3 checks), Professional £49/mo (30), Enterprise £199/mo (unlimited)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-21 12:03:24 +00:00
parent 6f384f8d09
commit 28d7d41b25
27 changed files with 2427 additions and 1 deletions

View File

@@ -0,0 +1,69 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TrueCV.Infrastructure.Data.Migrations
{
/// <inheritdoc />
public partial class AddStripeSubscriptionFields : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "CurrentPeriodEnd",
table: "AspNetUsers",
type: "datetime2",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "StripeSubscriptionId",
table: "AspNetUsers",
type: "nvarchar(256)",
maxLength: 256,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "SubscriptionStatus",
table: "AspNetUsers",
type: "nvarchar(32)",
maxLength: 32,
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Users_StripeCustomerId",
table: "AspNetUsers",
column: "StripeCustomerId");
migrationBuilder.CreateIndex(
name: "IX_Users_StripeSubscriptionId",
table: "AspNetUsers",
column: "StripeSubscriptionId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_Users_StripeCustomerId",
table: "AspNetUsers");
migrationBuilder.DropIndex(
name: "IX_Users_StripeSubscriptionId",
table: "AspNetUsers");
migrationBuilder.DropColumn(
name: "CurrentPeriodEnd",
table: "AspNetUsers");
migrationBuilder.DropColumn(
name: "StripeSubscriptionId",
table: "AspNetUsers");
migrationBuilder.DropColumn(
name: "SubscriptionStatus",
table: "AspNetUsers");
}
}
}