Migration Strategy
Overview
The migration strategy covers three distinct scenarios: migrating existing clients from the Cash360 Membership module to the new platform, importing data from competing products, and onboarding entirely new clients. All three scenarios must work reliably with a 4-person team, which means automation is not optional -- it is the only way to scale onboarding beyond one client at a time.
Cash360 Data Migration
Entity Mapping
The following table defines the field-level mapping between Cash360 entities and the new Membership data model. This mapping drives the automated migration tool.
MbLogin to User
| Cash360 Field | Membership Field | Transformation |
|---|---|---|
id |
externalId (metadata) |
Store as reference for cross-linking |
email |
email |
Direct copy |
password |
passwordHash |
Direct copy (bcrypt, compatible) |
status_cd |
statusCd |
Map: ACTIVE->ACTIVE, LOCKED->LOCKED |
is_verified |
emailVerified |
Direct copy |
created_date |
createdAt |
Direct copy |
| (new) | roleCd |
Default: MEMBER (admins mapped separately from McUser) |
| (new) | failedLoginAttempts |
Default: 0 |
| (new) | locale |
Default from entity settings |
MbConsumer to Member
| Cash360 Field | Membership Field | Transformation |
|---|---|---|
id |
externalId (metadata) |
Store as reference |
first_name |
firstName |
Direct copy |
last_name |
lastName |
Direct copy |
gender_cd |
gender |
Map: M->MALE, F->FEMALE, D->DIVERSE |
birthday |
dateOfBirth |
Direct copy |
email |
email |
Direct copy |
phone |
phone |
Direct copy |
street + house_number |
street |
Concatenate with space |
zip |
zip |
Direct copy |
city |
city |
Direct copy |
country_cd |
countryCode |
Map to ISO 3166-1 alpha-2 |
emergency_contact_name |
emergencyContactName |
Direct copy |
emergency_contact_phone |
emergencyContactPhone |
Direct copy |
id_responsible_person |
idResponsiblePerson |
Map via member reference table |
custom_attributes (JSONB) |
customAttributes (JSONB) |
Direct copy (compatible schema) |
id_mc_entity |
idEntity |
Map via entity reference table |
CsrConsumer (Backend Enrichment)
The CsrConsumer entity in Cash360 contains additional backend data that supplements the member profile:
| Cash360 Field | Membership Field | Transformation |
|---|---|---|
consumer_number |
memberNumber |
Direct copy |
type_cd |
typeCd |
Map: PERSON->PERSON, ORGANIZATION->COMPANY |
status_cd |
statusCd |
Map: ACTIVE->ACTIVE, INACTIVE->INACTIVE |
archived |
statusCd |
If archived=true -> LEFT |
custom_attributes |
customAttributes |
Merge with MbConsumer custom attributes |
CsrContractPreDefined to MembershipTemplate
| Cash360 Field | Membership Field | Transformation |
|---|---|---|
name |
name |
Direct copy |
description |
description |
Direct copy |
price |
price |
Convert to DECIMAL(19,4) |
billing_interval |
billingIntervalMonths |
Map: MONTHLY->1, QUARTERLY->3, ANNUAL->12 |
minimum_term |
minimumTermMonths |
Direct copy |
notice_period |
noticePeriodMonths |
Direct copy |
auto_renew |
autoRenew |
Direct copy |
vat_rate |
vatRate |
Direct copy |
status_cd |
statusCd |
Map: ACTIVE->ACTIVE, ARCHIVED->ARCHIVED |
| (new) | typeCd |
Default: SUBSCRIPTION |
| (new) | visibleOnHomepage |
Default: true (for active templates) |
CsrContract2Product to Contract
| Cash360 Field | Membership Field | Transformation |
|---|---|---|
id_csr_consumer |
idMember |
Map via member reference table |
id_pp_product_snapshot |
idMembershipTemplate |
Map via template reference table |
start_date |
startDate |
Direct copy |
end_date |
endDate |
Direct copy |
status_cd |
statusCd |
Map: ACTIVE->ACTIVE, CANCELLED->CANCELLED |
price |
price |
Convert to DECIMAL(19,4) |
billing_interval |
billingIntervalMonths |
Same as template mapping |
| (calculated) | nextBillingDate |
Calculate from start date + billing history |
CsrBankAccount to BankAccount
| Cash360 Field | Membership Field | Transformation |
|---|---|---|
id_csr_consumer |
idMember |
Map via member reference table |
iban |
iban |
Direct copy (validate checksum) |
bic |
bic |
Direct copy |
account_owner |
accountHolder |
Direct copy |
mandate_reference |
mandateReference |
Direct copy |
mandate_sign_date |
mandateSignDate |
Direct copy |
is_default |
isDefault |
Direct copy |
status_cd |
statusCd |
Map: ACTIVE->ACTIVE |
| (new) | mandateTypeCd |
Default: CORE |
PmTransaction to Transaction (Historical)
| Cash360 Field | Membership Field | Transformation |
|---|---|---|
id |
externalTransactionId |
Store Cash360 ID as external reference |
id_csr_consumer |
idMember |
Map via member reference table |
amount |
amount |
Convert to DECIMAL(19,4) |
transaction_date |
createdAt |
Direct copy |
status_cd |
statusCd |
Map: PROCESSED->PROCESSED, FAILED->FAILED |
type_cd |
typeCd |
Map: CHARGE->MEMBERSHIP_FEE, REFUND->REFUND |
description |
description |
Direct copy |
McEntity to Entity
| Cash360 Field | Membership Field | Transformation |
|---|---|---|
name |
name |
Direct copy |
id_parent_mc_entity |
idParentEntity |
Map via entity reference table |
street |
address |
Direct copy |
zip |
zip |
Direct copy |
city |
city |
Direct copy |
country_cd |
countryCode |
Map to ISO 3166-1 alpha-2 |
phone |
phone |
Direct copy |
email |
email |
Direct copy |
status_cd |
statusCd |
Map: ACTIVE->ACTIVE |
| (new) | typeCd |
Inferred from context (CLUB, STUDIO) |
| (new) | timezone |
Default: Europe/Berlin |
| (new) | currencyCode |
Default: EUR |
McUser to User (Admin Roles)
| Cash360 Field | Membership Field | Transformation |
|---|---|---|
email |
email |
Direct copy |
password |
passwordHash |
Direct copy (bcrypt compatible) |
first_name + last_name |
(user profile) | Stored in separate admin profile |
role_cd |
roleCd |
Map: ADMIN->ADMIN, SUPER_ADMIN->SYSTEM_ADMIN |
id_mc_entity |
idEntity |
Direct copy |
status_cd |
statusCd |
Map: ACTIVE->ACTIVE |
Migration Tool Architecture
The migration tool is a standalone Spring Boot application that reads from Cash360's database (read-only) and writes to the Membership database:
Migration Execution Process
Step 1 -- Pre-migration analysis: - Connect to Cash360 database (read-only) - Count records per entity type - Identify data quality issues (missing required fields, orphaned records, encoding problems) - Generate pre-migration report
Step 2 -- Entity migration (order matters): 1. Entities (McEntity) -- must exist before anything else (tenant context) 2. Users (McUser) -- admin users, no member link yet 3. Members (MbConsumer + CsrConsumer merge) -- personal profiles 4. User-Member links (MbLogin -> User, link to Member) 5. Membership templates (CsrContractPreDefined) 6. Contracts (CsrContract2Product) 7. Bank accounts (CsrBankAccount) 8. Transaction history (PmTransaction)
Step 3 -- Post-migration validation: - Count check: source records vs. migrated records per type - Referential integrity: all FKs resolve - Sample validation: spot-check 10 random members with all linked data - Financial consistency: sum of transactions in Cash360 matches sum in Membership
Step 4 -- Migration report: - Total records migrated per type - Records skipped (with reasons) - Data quality issues encountered - Duration and performance metrics
Transaction History Migration
Transaction history is critical for continuity: members and admins need to see past payments even after migration.
Strategy
- Active transactions (PENDING, SUBMITTED): Remain in Cash360 for processing. The new system creates a read-only reference. Once processed, the status update propagates to Membership via the normal webhook/polling mechanism.
- Historical transactions (PROCESSED, FAILED, CANCELLED): Migrated as read-only records. The
externalTransactionIdfield links back to Cash360 for audit purposes. - Ongoing transactions post-migration: New transactions are created in Membership and submitted to Cash360 via API. The transition date is recorded per entity.
Financial Reconciliation
Before and after migration, the following totals must match:
| Metric | Cash360 | Membership | Tolerance |
|---|---|---|---|
| Total members with active contracts | COUNT | COUNT | 0 |
| Total transaction amount (all time) | SUM | SUM | 0.01 (rounding) |
| Open balance per member | Per-member SUM | Per-member SUM | 0.01 |
| Active SEPA mandates | COUNT | COUNT | 0 |
Bank Account and SEPA Mandate Migration
SEPA mandates are legally binding documents. Migration must preserve:
- Mandate reference: Exact same reference number (mandate references are communicated to banks and cannot change)
- Mandate sign date: Original signature date (required in SEPA XML)
- Mandate type: CORE or B2B (determines processing rules)
After migration, the mandate is re-registered with Cash360 using the new Membership entity's context but the same reference number. This ensures continuity of direct debit collections without requiring members to sign new mandates.
Data Import Tooling
CSV Import System
For clubs that are not coming from Cash360 but from spreadsheets or competing products:
Import Modes
| Mode | Behavior | Use Case |
|---|---|---|
| New Only | Insert records that do not exist (match by email/member number). Skip existing. | Initial import |
| New + Update | Insert new records and update existing ones with data from CSV. | Periodic sync from federation |
| Update Only | Only update existing records. Skip rows that do not match any existing record. | Bulk data correction |
Supported Source Formats
| Format | Detection | Notes |
|---|---|---|
| CSV (comma) | Automatic | Most common |
| CSV (semicolon) | Automatic | Common in German Excel exports |
| TSV (tab) | Automatic | Federation data exports |
| UTF-8 | Automatic | Default assumption |
| ISO-8859-1 | Automatic fallback | Legacy German systems |
| Windows-1252 | Automatic fallback | Older Windows exports |
Mapping Template Library
Pre-built mapping templates for common source systems:
| Source System | Template | Fields Mapped |
|---|---|---|
| easyVerein | import-easyverein.json |
Member name, address, email, phone, membership type |
| ClubDesk | import-clubdesk.json |
Member name, address, membership, bank account |
| MEINVEREIN | import-meinverein.json |
Member data, contribution, bank details |
| SportMember | import-sportmember.json |
Member, team, payment |
| Generic (German) | import-generic-de.json |
Vorname, Nachname, Strasse, PLZ, Ort, Email, IBAN |
| Generic (English) | import-generic-en.json |
First Name, Last Name, Address, ZIP, City, Email, IBAN |
Templates are JSON files defining column name patterns to entity field mappings, with optional value transformations (e.g., "m" -> "MALE", "w" -> "FEMALE" for German gender codes).
Phased Rollout Strategy
Phase 1 -- Controlled Soft Launch (Month 1-3)
| Aspect | Detail |
|---|---|
| Target | < 10 hand-selected clients |
| Selection criteria | Existing Cash360 customers, willing to provide feedback, < 500 members each |
| Onboarding | White-glove: migration run by development team, 1:1 video call for setup |
| Pricing | Free or heavily discounted during validation |
| Support | Direct Slack/Teams channel with development team |
| Feedback | Weekly check-in calls, in-app feedback widget |
| Exit criteria | 3+ clients actively using system for > 30 days, NPS > 30, < 5 critical bugs |
Phase 2 -- Market Entry (Month 4-6)
| Aspect | Detail |
|---|---|
| Target | 10-50 clients |
| Channel | Website with self-service registration, product landing page |
| Onboarding | Self-service setup wizard + documentation, CSV import tool available |
| Pricing | Published pricing tiers (Free/Starter/Professional) |
| Support | Email support, knowledge base, community forum |
| Marketing | Content marketing (blog posts, guides), SEO, social media |
| Exit criteria | 20+ paying clients, positive unit economics on Starter tier |
Phase 3 -- Growth (Month 7-12)
| Aspect | Detail |
|---|---|
| Target | 50-200 clients |
| Channel | Direct sales, partner network, trade shows (FIBO) |
| Onboarding | Self-service + optional paid onboarding packages |
| Pricing | Full pricing model including Enterprise tier |
| Support | Tiered support (email, phone for Professional+, dedicated for Enterprise) |
| Marketing | Google Ads, trade publications, referral program, case studies |
Parallel Operation Period
During migration, both systems run simultaneously for a configurable overlap period (recommended: 30 days):
During parallel operation: - New member registrations happen in Membership only - Billing continues in Cash360 until cutover date - Both systems are accessible (old links redirect with notice) - An incremental sync job runs nightly to catch any new Cash360 data
Rollback Strategy
If migration fails or the new system has critical issues:
| Scenario | Rollback Action | Data Loss |
|---|---|---|
| Pre-cutover issues | Abandon migration, stay on Cash360 | None (Cash360 was never modified) |
| Post-cutover, < 7 days | Re-enable Cash360, sync new data back | Minimal (only new registrations need manual transfer) |
| Post-cutover, > 7 days | Forward-fix in Membership | Not applicable (rollback too risky) |
Key principle: Cash360 is never modified during migration. The migration tool only reads from Cash360. This means rollback to Cash360 is always possible by simply switching DNS back.
Team Constraints and Automation
With a 4-person team (PM, Frontend dev, Backend dev, QA), manual onboarding does not scale. Every migration step must be automated:
| Task | Manual Time | Automated Time |
|---|---|---|
| Pre-migration analysis | 4 hours | 5 minutes (automated report) |
| Data migration | 2 days | 30 minutes (migration tool) |
| Post-migration validation | 4 hours | 15 minutes (automated checks) |
| Member communication | 2 hours | 5 minutes (template-based bulk email) |
| Staff training | 2 hours | Self-service (video + docs) |
Target: Onboard a new client (from initial contact to fully operational) in < 1 week of calendar time with < 4 hours of team effort.