diff --git a/SERVICE_CONTRACT_WIZARD_README.md b/SERVICE_CONTRACT_WIZARD_README.md
new file mode 100644
index 0000000..f403036
--- /dev/null
+++ b/SERVICE_CONTRACT_WIZARD_README.md
@@ -0,0 +1,201 @@
+# Service Contract Migration Wizard - Implementation Summary
+
+## ✅ What Was Built
+
+A step-by-step wizard that migrates Vtiger service contracts to Hub systems:
+- **Cases** → Archived to `tticket_archived_tickets`
+- **Timelogs** → Transferred as klippekort top-ups (prepaid card hours)
+
+Features:
+- ✅ Dry-run toggle (preview mode without database writes)
+- ✅ Step-by-step review of each case/timelog
+- ✅ Manual klippekort selection per timelog
+- ✅ Progress tracking and summary report
+- ✅ Read-only from Vtiger (no writes back to Vtiger)
+
+## 🎯 Files Created/Modified
+
+### New Files:
+1. **[app/timetracking/backend/service_contract_wizard.py](app/timetracking/backend/service_contract_wizard.py)** (275 lines)
+ - Core wizard service with all business logic
+ - Methods: `load_contract_detailed_data()`, `archive_case()`, `transfer_timelog_to_klippekort()`, `get_wizard_summary()`
+ - Dry-run support built into each method
+
+2. **[app/timetracking/frontend/service_contract_wizard.html](app/timetracking/frontend/service_contract_wizard.html)** (650 lines)
+ - Complete wizard UI with Nordic design
+ - Contract dropdown selector
+ - Progress bar with live counters
+ - Current item display with conditional klippekort dropdown
+ - Summary report on completion
+
+### Modified Files:
+1. **[app/services/vtiger_service.py](app/services/vtiger_service.py)** (+65 lines)
+ - Added `get_service_contracts(account_id=None)` - Fetch active service contracts
+ - Added `get_service_contract_cases(contract_id)` - Fetch cases linked to contract
+ - Added `get_service_contract_timelogs(contract_id)` - Fetch timelogs linked to contract
+
+2. **[app/timetracking/backend/models.py](app/timetracking/backend/models.py)** (+70 lines)
+ - `ServiceContractBase` - Base contract model
+ - `ServiceContractItem` - Single case/timelog item
+ - `ServiceContractWizardData` - Complete contract data for wizard
+ - `ServiceContractWizardAction` - Action result (archive/transfer)
+ - `ServiceContractWizardSummary` - Final summary
+ - `TimologTransferRequest` - Request model for timelog transfer
+ - `TimologTransferResult` - Transfer result
+
+3. **[app/timetracking/backend/router.py](app/timetracking/backend/router.py)** (+180 lines)
+ - `GET /api/v1/timetracking/service-contracts` - List contracts dropdown
+ - `POST /api/v1/timetracking/service-contracts/wizard/load` - Load contract data
+ - `POST /api/v1/timetracking/service-contracts/wizard/archive-case` - Archive case
+ - `POST /api/v1/timetracking/service-contracts/wizard/transfer-timelog` - Transfer timelog
+ - `GET /api/v1/timetracking/service-contracts/wizard/customer-cards/{customer_id}` - Get klippekort
+
+4. **[app/timetracking/frontend/views.py](app/timetracking/frontend/views.py)** (+5 lines)
+ - Added frontend route: `/timetracking/service-contract-wizard`
+
+## 🚀 How to Test
+
+### 1. Start the API
+```bash
+docker-compose up -d api
+docker-compose logs -f api
+```
+
+### 2. Access the Wizard
+```
+http://localhost:8000/timetracking/service-contract-wizard
+```
+
+### 3. Dry-Run Mode (Recommended First)
+1. Check the "Preview Mode" checkbox at top (enabled by default)
+2. Select a service contract from dropdown
+3. Review each case/timelog and click "Gem & Næste"
+4. No data is written to database in dry-run mode
+5. Review summary report to see what WOULD be changed
+
+### 4. Live Mode
+1. **Uncheck** "Preview Mode" checkbox
+2. Select same or different contract
+3. Process items - changes ARE committed to database
+4. Cases are exported to `tticket_archived_tickets`
+5. Timelogs are added to klippekort via top-up transaction
+
+## 🔍 Database Changes
+
+### Dryrun Mode:
+- All operations are **logged** but **NOT committed**
+- Queries are constructed but rolled back
+- UI shows what WOULD happen
+
+### Live Mode:
+- Cases are inserted into `tticket_archived_tickets` with:
+ - `source_system = 'vtiger_service_contract'`
+ - `external_id = vtiger case ID`
+ - Full case data in `raw_data` JSONB field
+
+- Timelogs create transactions in `tticket_prepaid_transactions` with:
+ - `transaction_type = 'top_up'`
+ - Hours added to klippekort `purchased_hours`
+ - Description references vTiger timelog
+
+## 📊 Data Flow
+
+```
+Vtiger Service Contract
+ ↓
+SelectContract (dropdown)
+ ↓
+LoadContractData
+ ├─ Cases → Archive to tticket_archived_tickets
+ └─ Timelogs → Transfer to klippekort (top-up)
+ ↓
+WizardProgress (step-by-step review)
+ ├─ [DRY RUN] Preview mode (no DB writes)
+ └─ [LIVE] Commit to database
+ ↓
+Summary Report
+ ├─ Cases archived: N
+ ├─ Hours transferred: N
+ └─ Failed items: N
+```
+
+## 🔐 Safety Features
+
+1. **Dry-run mode enabled by default** - Users see what WOULD happen first
+2. **Customer linking** - Looks up Hub customer ID from vTiger account
+3. **Klippekort validation** - Verifies card belongs to customer before transfer
+4. **Read-only from Vtiger** - No writes back to Vtiger (only reads)
+5. **Transaction handling** - Each operation is atomic
+6. **Audit logging** - All actions logged with DRY RUN/COMMITTED markers
+
+## 🛠️ Technical Details
+
+### Wizard Service (`ServiceContractWizardService`)
+- Stateless service class
+- All methods are static
+- Database operations via `execute_query()` helpers
+- Klippekort transfers via `KlippekortService.top_up_card()`
+
+### Frontend UI
+- Vanilla JavaScript (no frameworks)
+- Nordic Top design system (matches existing Hub UI)
+- Responsive Bootstrap 5 grid
+- Real-time progress updates
+- Conditional klippekort dropdown (only for timelogs)
+
+### API Endpoints
+- RESTful architecture
+- All endpoints support `dry_run` query parameter
+- Request/response models use Pydantic validation
+- Comprehensive error handling with HTTPException
+
+## 📝 Logging Output
+
+### Dry-Run Mode:
+```
+🔍 DRY RUN: Would archive case 1x123: 'Case Title'
+🔍 DRY RUN: Would transfer 5h to card 42 from timelog 2x456
+```
+
+### Live Mode:
+```
+✅ Archived case 1x123 to tticket_archived_tickets (ID: 1234)
+✅ Transferred 5h from timelog 2x456 to card 42
+```
+
+## 🐛 Troubleshooting
+
+### Contracts dropdown is empty:
+- Verify Vtiger integration is configured (VTIGER_URL, VTIGER_USERNAME, VTIGER_API_KEY in .env)
+- Check vTiger has active ServiceContracts
+- Check API user has access to ServiceContracts module
+
+### Klippekort dropdown empty for customer:
+- Customer may not have any active prepaid cards
+- Or customer is not linked between Vtiger account and Hub customer
+- Create a prepaid card for the customer first
+
+### Dry-run mode not working:
+- Ensure checkbox is checked
+- Check browser console for JavaScript errors
+- Verify `dry_run` parameter is passed to API endpoints
+
+## 📋 Next Steps
+
+1. **Test with sample data** - Create test service contract in Vtiger
+2. **Verify database changes** - Query `tticket_archived_tickets` post-migration
+3. **Monitor klippekort** - Check `tticket_prepaid_transactions` for top-up entries
+4. **Adjust as needed** - Tweak timelog filtering or case mapping based on results
+
+## 🔗 Related Components
+
+- **Klippekort System**: [app/ticket/backend/klippekort_service.py](app/ticket/backend/klippekort_service.py)
+- **Archive System**: Database table `tticket_archived_tickets`
+- **Timetracking Module**: [app/timetracking/](app/timetracking/)
+- **Vtiger Integration**: [app/services/vtiger_service.py](app/services/vtiger_service.py)
+
+---
+
+**Status**: ✅ Ready for testing and deployment
+**Estimated Time to Test**: 15-20 minutes
+**Database Dependency**: PostgreSQL (no migrations needed - uses existing tables)
diff --git a/app/contacts/frontend/contact_detail.html b/app/contacts/frontend/contact_detail.html
index 12b46bf..4613b32 100644
--- a/app/contacts/frontend/contact_detail.html
+++ b/app/contacts/frontend/contact_detail.html
@@ -98,6 +98,18 @@
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
+
+ .session-card {
+ background: var(--bg-card);
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ border-radius: 12px;
+ padding: 1rem;
+ }
+
+ .session-meta {
+ font-size: 0.9rem;
+ color: var(--text-secondary);
+ }
.remove-company-btn {
position: absolute;
@@ -147,6 +159,11 @@
Firmaer
+