# Multi-Tenancy Deployment Guide ## Pre-Deployment Checklist - [ ] Code review completed - [ ] All tests passing - [ ] Database backup created - [ ] Rollback plan prepared - [ ] Downtime window scheduled (if needed) ## Deployment Steps ### Step 1: Backup Database ```bash # SQL Server backup example BACKUP DATABASE PowderCoatingDb TO DISK = 'C:\Backups\PowderCoatingDb_PreMultiTenancy.bak' WITH FORMAT, COMPRESSION; ``` ### Step 2: Build Solution ```bash cd Y:\PCC\PowderCoatingApp dotnet build ``` Ensure no build errors. ### Step 3: Review Migration Check the migration file to understand what will happen: ```bash # View the migration cat src/PowderCoating.Infrastructure/Migrations/20260205220415_AddMultiTenancy.cs ``` The migration will: - Create `Companies` table - Add `CompanyId` columns to all entities - Add `CompanyRole` to `AspNetUsers` - Create foreign keys and indexes ### Step 4: Apply Migration ```bash cd src/PowderCoating.Web dotnet ef database update --project ../PowderCoating.Infrastructure ``` **Expected output:** ``` Applying migration '20260205220415_AddMultiTenancy'. Done. ``` ### Step 5: Run Seed Data The seed data will run automatically on application startup and will: - Create default "Demo Company" - Create SuperAdmin user - Create CompanyAdmin user - Create Manager user Start the application: ```bash dotnet run --project src/PowderCoating.Web ``` Watch the logs for: ``` Company 'Demo Company' created User 'superadmin@powdercoating.com' created User 'admin@demo.com' created User 'manager@demo.com' created ``` ### Step 6: Verify Migration Success Connect to the database and verify: ```sql -- Check Companies table exists SELECT * FROM Companies; -- Check CompanyId added to entities SELECT TOP 5 Id, CompanyId FROM Customers; SELECT TOP 5 Id, CompanyId FROM Jobs; -- Check ApplicationUser has CompanyId SELECT TOP 5 Id, Email, CompanyId, CompanyRole FROM AspNetUsers; -- Verify foreign keys SELECT fk.name AS ForeignKeyName, OBJECT_NAME(fk.parent_object_id) AS TableName, COL_NAME(fkc.parent_object_id, fkc.parent_column_id) AS ColumnName, OBJECT_NAME (fk.referenced_object_id) AS ReferencedTableName FROM sys.foreign_keys AS fk INNER JOIN sys.foreign_key_columns AS fkc ON fk.object_id = fkc.constraint_object_id WHERE OBJECT_NAME(fk.referenced_object_id) = 'Companies'; ``` ### Step 7: Test Login Test each user account: 1. **SuperAdmin Login** - URL: https://localhost:5001/Identity/Account/Login - Email: superadmin@powdercoating.com - Password: SuperAdmin123! - Should see: "Companies" menu in Platform Management 2. **Company Admin Login** - URL: https://localhost:5001/Identity/Account/Login - Email: admin@demo.com - Password: CompanyAdmin123! - Should see: "Manage Users" menu in Company Settings - Should see: "Demo Company" badge in header 3. **Manager Login** - URL: https://localhost:5001/Identity/Account/Login - Email: manager@demo.com - Password: Manager123! - Should see: "Demo Company" badge in header - Should NOT see: "Manage Users" menu ### Step 8: Verify Data Isolation 1. As **SuperAdmin**, create a second company: - Navigate to Companies → Create New Company - Company Name: "Test Company" - Create admin user for Test Company 2. Login as **Test Company Admin** - Verify you only see Test Company data - Create a test customer 3. Login as **Demo Company Admin** - Verify you CANNOT see Test Company customer - Verify you only see Demo Company data 4. Login as **SuperAdmin** - Navigate to Customers - Should see customers from BOTH companies ## Post-Deployment Verification ### Functional Tests - [ ] SuperAdmin can create new companies - [ ] SuperAdmin can see all companies' data - [ ] Company Admin can create users in their company - [ ] Company Admin cannot see other companies' data - [ ] Users can only see data from their own company - [ ] New entities automatically get CompanyId assigned - [ ] Query filters work correctly ### Performance Tests - [ ] Page load times are acceptable - [ ] No N+1 query issues - [ ] Indexes are being used (check query plans) ### Security Tests - [ ] Cannot access other company's data by changing IDs in URL - [ ] Authorization policies enforce correctly - [ ] Query filters cannot be bypassed by regular users ## Troubleshooting ### Issue: Migration Fails **Error: Foreign key constraint conflicts** This means existing data has CompanyId=0 which doesn't exist. **Solution:** ```sql -- Check if default company exists SELECT * FROM Companies WHERE Id = 1; -- If no company exists, seed data didn't run -- Run application to trigger seed, OR manually: INSERT INTO Companies (CompanyName, CompanyCode, PrimaryContactName, PrimaryContactEmail, IsActive, SubscriptionStartDate, CreatedAt, CompanyId) VALUES ('Demo Company', 'DEMO', 'Admin', 'admin@demo.com', 1, GETUTCDATE(), GETUTCDATE(), 0); -- Update CompanyId to self-reference UPDATE Companies SET CompanyId = Id WHERE Id = 1; -- Update existing data UPDATE Customers SET CompanyId = 1 WHERE CompanyId = 0; UPDATE Jobs SET CompanyId = 1 WHERE CompanyId = 0; -- ... repeat for all entities ``` ### Issue: Users Can't Login **Error: "Unable to determine your company"** This means the user's CompanyId is not set or CompanyId claim is missing. **Solution:** ```sql -- Check user's CompanyId SELECT Id, Email, CompanyId FROM AspNetUsers WHERE Email = 'user@example.com'; -- Update if needed UPDATE AspNetUsers SET CompanyId = 1 WHERE CompanyId = 0 OR CompanyId IS NULL; ``` Then ensure user re-logs in to get fresh claims. ### Issue: Seeing Other Company's Data This means query filters aren't working. **Check:** 1. Is `ITenantContext` registered in DI? 2. Is `ApplicationDbContext` receiving `IHttpContextAccessor` and `IServiceProvider`? 3. Are query filters being applied in `OnModelCreating`? 4. Is the user authenticated and has CompanyId claim? ## Rollback Procedure If critical issues occur: ```bash # Rollback migration cd src/PowderCoating.Web dotnet ef database update 20260205163837_InitialCreate --project ../PowderCoating.Infrastructure # Restore database backup RESTORE DATABASE PowderCoatingDb FROM DISK = 'C:\Backups\PowderCoatingDb_PreMultiTenancy.bak' WITH REPLACE; # Revert code changes git revert ``` ## Support Contacts - Lead Developer: [Your Name] - Database Admin: [DBA Name] - DevOps: [DevOps Contact] ## Post-Deployment Tasks - [ ] Monitor application logs for errors - [ ] Monitor database performance - [ ] Update documentation - [ ] Train users on new multi-tenancy features - [ ] Schedule follow-up review (1 week)