Files
RealCV/DEPLOYMENT-GUIDE.md

448 lines
12 KiB
Markdown
Raw Normal View History

# TrueCV Production Deployment Guide
A low-budget guide to launching TrueCV as a professional, secure offering.
---
## Budget Summary
| Component | Monthly Cost | Notes |
|-----------|-------------|-------|
| Azure App Service (B1) | ~£10 | 1.75GB RAM, custom domain, SSL |
| Azure SQL (Basic) | ~£4 | 2GB, 5 DTUs - upgrade as needed |
| Azure Blob Storage | ~£1 | Pay per GB stored |
| Domain name | ~£10/year | .com or .co.uk |
| **Total** | **~£15-20/month** | Scales with usage |
Alternative: A single £5-10/month VPS (Hetzner, DigitalOcean) can run everything if you're comfortable with Linux administration.
---
## Phase 1: Pre-Launch Checklist
### 1.1 Stripe Setup (Required for Payments)
1. Create a Stripe account at [stripe.com](https://stripe.com)
2. Complete business verification (required for live payments)
3. Create two Products in Stripe Dashboard:
- **Professional**: £49/month recurring
- **Enterprise**: £199/month recurring
4. Copy the Price IDs (start with `price_`) to your config
5. Configure the Customer Portal:
- Dashboard → Settings → Billing → Customer Portal
- Enable: Update payment methods, Cancel subscriptions, View invoices
6. Set up webhook endpoint (after deployment):
- Dashboard → Developers → Webhooks → Add endpoint
- URL: `https://yourdomain.com/api/stripe/webhook`
- Events: `checkout.session.completed`, `customer.subscription.updated`, `customer.subscription.deleted`, `invoice.payment_failed`
7. Copy the webhook signing secret to your config
### 1.2 External API Keys
| Service | Purpose | How to Get |
|---------|---------|-----------|
| Companies House | Company verification | [developer.company-information.service.gov.uk](https://developer.company-information.service.gov.uk) - Free |
| Anthropic (Claude) | CV parsing & analysis | [console.anthropic.com](https://console.anthropic.com) - Pay per use |
### 1.3 Domain & Email
1. Register a domain (Cloudflare, Namecheap, or similar)
2. Set up a professional email:
- Budget option: Zoho Mail free tier (5 users)
- Better option: Google Workspace (£5/user/month)
3. Configure SPF, DKIM, DMARC records for email deliverability
---
## Phase 2: Infrastructure Setup
### Option A: Azure (Recommended for .NET)
#### App Service + Azure SQL
```bash
# Install Azure CLI, then:
az login
# Create resource group
az group create --name truecv-prod --location uksouth
# Create App Service plan (B1 = ~£10/month)
az appservice plan create \
--name truecv-plan \
--resource-group truecv-prod \
--sku B1 \
--is-linux
# Create web app
az webapp create \
--name truecv-app \
--resource-group truecv-prod \
--plan truecv-plan \
--runtime "DOTNETCORE:8.0"
# Create SQL Server
az sql server create \
--name truecv-sql \
--resource-group truecv-prod \
--location uksouth \
--admin-user truecvadmin \
--admin-password <STRONG_PASSWORD>
# Create database (Basic = ~£4/month)
az sql db create \
--name truecv-db \
--server truecv-sql \
--resource-group truecv-prod \
--service-objective Basic
# Create storage account for CV files
az storage account create \
--name truecvstorage \
--resource-group truecv-prod \
--location uksouth \
--sku Standard_LRS
```
#### Environment Variables (App Service Configuration)
Set these in Azure Portal → App Service → Configuration → Application settings:
```
ConnectionStrings__DefaultConnection=Server=truecv-sql.database.windows.net;Database=truecv-db;User Id=truecvadmin;Password=<PASSWORD>;Encrypt=True;
ConnectionStrings__HangfireConnection=<SAME_AS_ABOVE>
Stripe__SecretKey=sk_live_xxx
Stripe__PublishableKey=pk_live_xxx
Stripe__WebhookSecret=whsec_xxx
Stripe__PriceIds__Professional=price_xxx
Stripe__PriceIds__Enterprise=price_xxx
Anthropic__ApiKey=sk-ant-xxx
CompaniesHouse__ApiKey=xxx
AzureBlob__ConnectionString=<FROM_STORAGE_ACCOUNT>
AzureBlob__ContainerName=cvfiles
```
### Option B: VPS (Budget Alternative)
A £5-10/month VPS from Hetzner, DigitalOcean, or Vultr can run everything:
1. Ubuntu 22.04 LTS
2. Install Docker and Docker Compose
3. Use the existing `docker-compose.yml` with modifications:
```yaml
# docker-compose.prod.yml
version: '3.8'
services:
web:
build: .
ports:
- "5000:8080"
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ConnectionStrings__DefaultConnection=Server=db;Database=TrueCV;User Id=sa;Password=${DB_PASSWORD};TrustServerCertificate=True
depends_on:
- db
restart: always
db:
image: mcr.microsoft.com/mssql/server:2022-latest
environment:
- ACCEPT_EULA=Y
- SA_PASSWORD=${DB_PASSWORD}
volumes:
- sqldata:/var/opt/mssql
restart: always
caddy: # Reverse proxy with automatic HTTPS
image: caddy:2
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
restart: always
volumes:
sqldata:
caddy_data:
```
```
# Caddyfile
yourdomain.com {
reverse_proxy web:5000
}
```
---
## Phase 3: Security Hardening
### 3.1 Application Security (Critical)
#### Secrets Management
- **Never** commit secrets to git
- Use Azure Key Vault or environment variables
- Rotate API keys quarterly
#### HTTPS Enforcement
Already configured in `Program.cs`:
```csharp
app.UseHsts();
app.UseHttpsRedirection();
```
#### Content Security Policy
Add to `Program.cs`:
```csharp
app.Use(async (context, next) =>
{
context.Response.Headers.Append("X-Content-Type-Options", "nosniff");
context.Response.Headers.Append("X-Frame-Options", "DENY");
context.Response.Headers.Append("X-XSS-Protection", "1; mode=block");
context.Response.Headers.Append("Referrer-Policy", "strict-origin-when-cross-origin");
context.Response.Headers.Append("Permissions-Policy", "camera=(), microphone=(), geolocation=()");
await next();
});
```
#### Rate Limiting
Add to `Program.cs`:
```csharp
builder.Services.AddRateLimiter(options =>
{
options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(context =>
RateLimitPartition.GetFixedWindowLimiter(
partitionKey: context.User.Identity?.Name ?? context.Request.Headers.Host.ToString(),
factory: _ => new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = 100,
Window = TimeSpan.FromMinutes(1)
}));
});
// In middleware pipeline
app.UseRateLimiter();
```
### 3.2 Database Security
1. **Use strong passwords** (20+ characters, random)
2. **Enable Azure SQL firewall** - allow only App Service IP
3. **Enable Transparent Data Encryption** (on by default in Azure)
4. **Regular backups** - Azure does this automatically (7-day retention on Basic tier)
### 3.3 File Storage Security
CV files contain sensitive data:
1. **Private container** - never allow public blob access
2. **SAS tokens** - generate time-limited URLs for downloads
3. **Encryption at rest** - enabled by default in Azure Storage
4. **Consider encryption at application level** for extra protection
### 3.4 Authentication Security
Already using ASP.NET Identity with good defaults. Verify these settings:
```csharp
// In Program.cs - identity configuration
builder.Services.Configure<IdentityOptions>(options =>
{
options.Password.RequiredLength = 12;
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireUppercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);
options.Lockout.MaxFailedAccessAttempts = 5;
});
```
### 3.5 Stripe Webhook Security
Already implemented - verify signature on every webhook:
```csharp
// In StripeService.cs - this is critical
stripeEvent = EventUtility.ConstructEvent(json, signature, _settings.WebhookSecret);
```
---
## Phase 4: Compliance & Legal
### 4.1 GDPR Compliance (Required for UK/EU)
1. **Privacy Policy** - create and link in footer
- What data you collect (CVs, email, payment info)
- How long you retain it
- User rights (access, deletion, portability)
- Third parties (Stripe, Anthropic, Companies House)
2. **Cookie Consent** - add banner for analytics cookies
3. **Data Retention Policy**:
- CVs: Delete after 30 days or on user request
- Accounts: Retain while active, delete 90 days after closure
- Payment data: Stripe handles this (PCI compliant)
4. **Right to Deletion** - implement account deletion feature
5. **Data Processing Agreement** - required if you have business customers
### 4.2 Terms of Service
Cover:
- Service description and limitations
- Acceptable use policy
- Payment terms and refund policy
- Liability limitations
- Dispute resolution
### 4.3 PCI Compliance
Stripe Checkout handles card data - you never touch it. This puts you in **PCI SAQ-A** (simplest level):
- Use only Stripe Checkout or Elements
- Serve pages over HTTPS
- Don't store card numbers
---
## Phase 5: Monitoring & Operations
### 5.1 Application Monitoring
#### Free Option: Application Insights (Azure)
```csharp
// In Program.cs
builder.Services.AddApplicationInsightsTelemetry();
```
#### Budget Option: Seq + Serilog
```csharp
// Already using Serilog - add Seq sink
Log.Logger = new LoggerConfiguration()
.WriteTo.Seq("http://localhost:5341") // Self-hosted Seq
.CreateLogger();
```
### 5.2 Uptime Monitoring
Free options:
- [UptimeRobot](https://uptimerobot.com) - 50 free monitors
- [Freshping](https://freshping.io) - 50 free monitors
Set up alerts for:
- Homepage availability
- API health endpoint
- Webhook endpoint
### 5.3 Error Tracking
Add a health check endpoint:
```csharp
// In Program.cs
app.MapGet("/health", () => Results.Ok(new { status = "healthy", timestamp = DateTime.UtcNow }));
```
### 5.4 Backup Strategy
| Component | Backup Method | Frequency |
|-----------|--------------|-----------|
| Database | Azure automated backups | Continuous (7-day retention) |
| CV files | Azure Blob redundancy (LRS) | Automatic |
| Config | Git repository | On change |
For VPS: Set up daily database dumps to offsite storage.
---
## Phase 6: Launch Checklist
### Pre-Launch (1 week before)
- [ ] All environment variables configured
- [ ] Database migrations applied
- [ ] Stripe products created and tested
- [ ] Webhook endpoint configured and tested
- [ ] SSL certificate active
- [ ] Privacy Policy and Terms published
- [ ] Test complete user journey (signup → payment → CV check)
- [ ] Test subscription cancellation flow
- [ ] Error pages customised (404, 500)
### Launch Day
- [ ] Switch Stripe to live mode (change API keys)
- [ ] Verify webhook is receiving live events
- [ ] Monitor error logs closely
- [ ] Test a real payment (refund yourself)
### Post-Launch (First Week)
- [ ] Monitor for errors daily
- [ ] Check Stripe dashboard for failed payments
- [ ] Respond to support queries within 24 hours
- [ ] Gather user feedback
---
## Phase 7: Scaling (When Needed)
Start small and scale based on actual usage:
| Trigger | Action | Cost Impact |
|---------|--------|-------------|
| Response time > 2s | Upgrade App Service to B2/B3 | +£10-30/month |
| Database DTU > 80% | Upgrade to Standard S0 | +£15/month |
| Storage > 5GB | Already pay-per-use | Minimal |
| > 1000 users | Add Redis for caching | +£15/month |
---
## Quick Reference: Configuration Files
### appsettings.Production.json
```json
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "yourdomain.com;www.yourdomain.com"
}
```
Sensitive values should be in environment variables, not this file.
---
## Support & Resources
- [Azure App Service Docs](https://learn.microsoft.com/en-us/azure/app-service/)
- [Stripe Documentation](https://stripe.com/docs)
- [ASP.NET Core Security](https://learn.microsoft.com/en-us/aspnet/core/security/)
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
---
## Estimated Time to Launch
| Phase | Effort |
|-------|--------|
| Stripe setup | 1-2 hours |
| Infrastructure | 2-4 hours |
| Security hardening | 2-3 hours |
| Legal pages | 2-4 hours (use templates) |
| Testing | 2-4 hours |
| **Total** | **1-2 days** |
---
*Document version: 1.0 | Last updated: January 2026*