Data Model

Overview

The Membership data model is designed from first principles, informed by the Cash360 entity structure but not constrained by it. The model supports multi-tenancy, extensibility via JSONB custom attributes, full audit trails, and a clean separation between authentication, member profiles, financial operations, and operational resources.

All entities carry an idEntity foreign key for tenant isolation. All timestamps use TIMESTAMP WITH TIME ZONE. All monetary values use DECIMAL(19,4) to avoid floating-point precision errors. Every entity includes @Version for optimistic locking (a lesson from the Cash360 audit where this was missing on all generated entities).


Core Entities

Organization / Entity

The tenant entity representing a sports club, fitness studio, or franchise group. Supports parent-child hierarchies for umbrella organizations and franchise networks.

Field Type Description
id BIGINT (PK) Primary key
idParentEntity BIGINT (FK, nullable) Parent organization for franchise/umbrella
name VARCHAR(255) Organization name
legalName VARCHAR(255) Legal entity name
typeCd VARCHAR(50) CLUB, STUDIO, FRANCHISE, UMBRELLA, MUNICIPAL
statusCd VARCHAR(50) ACTIVE, SUSPENDED, TERMINATED
address VARCHAR(500) Street address
zip VARCHAR(20) Postal code
city VARCHAR(100) City
countryCode VARCHAR(3) ISO 3166-1 alpha-2
phone VARCHAR(50) Contact phone
email VARCHAR(255) Contact email
website VARCHAR(500) Website URL
taxId VARCHAR(50) Tax identification number
timezone VARCHAR(50) IANA timezone (e.g., Europe/Berlin)
locale VARCHAR(10) Default locale (e.g., de-DE)
currencyCode VARCHAR(3) ISO 4217 (e.g., EUR)
logoUrl VARCHAR(500) Branding logo
primaryColor VARCHAR(7) Brand color (#hex)
customAttributes JSONB Extensible custom fields
settings JSONB Entity-level configuration (password policy, features, etc.)
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

User (Authentication)

Separated from the member profile following the Cash360 MbLogin / MbConsumer pattern. A User represents an authentication identity. One user can be linked to a member profile (consumer app) or exist as a standalone admin user.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idMember BIGINT (FK, nullable) Linked member profile (null for admin-only users)
email VARCHAR(255) Login email (unique per entity)
passwordHash VARCHAR(255) bcrypt hash
statusCd VARCHAR(50) ACTIVE, LOCKED, PENDING_VERIFICATION, DEACTIVATED
roleCd VARCHAR(50) MEMBER, TRAINER, ADMIN, GROUP_ADMIN, SYSTEM_ADMIN
emailVerified BOOLEAN Email verification status
verificationToken VARCHAR(255) Email verification token
verificationExpiry TIMESTAMPTZ Token expiry
passwordResetToken VARCHAR(255) Password reset token
passwordResetExpiry TIMESTAMPTZ Token expiry
refreshTokenHash VARCHAR(255) Hashed refresh token
failedLoginAttempts INTEGER Brute-force counter
lockedUntil TIMESTAMPTZ Account lockout expiry
lastLoginAt TIMESTAMPTZ Last successful login
mfaEnabled BOOLEAN Multi-factor authentication
mfaSecret VARCHAR(255) TOTP secret (encrypted)
locale VARCHAR(10) User's preferred locale
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

Member

The member profile containing personal data, address, and emergency contacts. Corresponds to MbConsumer / CsrConsumer in Cash360 but with a cleaner structure.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
memberNumber VARCHAR(50) Human-readable member number
typeCd VARCHAR(50) PERSON, COMPANY
statusCd VARCHAR(50) ACTIVE, INACTIVE, SUSPENDED, LEFT
salutation VARCHAR(20) Mr, Mrs, etc.
firstName VARCHAR(100) First name
lastName VARCHAR(100) Last name
companyName VARCHAR(255) Company name (if typeCd=COMPANY)
gender VARCHAR(20) MALE, FEMALE, DIVERSE, UNSPECIFIED
dateOfBirth DATE Birthday
email VARCHAR(255) Contact email
phone VARCHAR(50) Phone number
mobilePhone VARCHAR(50) Mobile phone
street VARCHAR(255) Street address
zip VARCHAR(20) Postal code
city VARCHAR(100) City
countryCode VARCHAR(3) ISO country code
photoUrl VARCHAR(500) Profile photo
notes TEXT Internal notes
emergencyContactName VARCHAR(200) Emergency contact full name
emergencyContactPhone VARCHAR(50) Emergency contact phone
emergencyContactRelation VARCHAR(50) Relationship (parent, spouse, etc.)
idResponsiblePerson BIGINT (FK, nullable) Parent/guardian for minors
isMinor BOOLEAN Auto-calculated from dateOfBirth
joinDate DATE Membership start date
exitDate DATE (nullable) Membership end date
exitReason VARCHAR(255) Reason for leaving
tags JSONB Flexible tagging (e.g., ["VIP", "competitor"])
customAttributes JSONB Extensible custom fields
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

MembershipTemplate

Defines available membership plans that members can purchase. Corresponds to CsrContractPreDefined in Cash360.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
name VARCHAR(255) Template name (e.g., "Adult Annual")
description TEXT Public description
typeCd VARCHAR(50) SUBSCRIPTION, PREPAID, TRIAL, DAY_PASS
statusCd VARCHAR(50) ACTIVE, ARCHIVED, DRAFT
price DECIMAL(19,4) Recurring price
currencyCode VARCHAR(3) EUR, CHF, etc.
billingIntervalMonths INTEGER 1=monthly, 3=quarterly, 12=annual
setupFee DECIMAL(19,4) One-time registration fee
minimumTermMonths INTEGER Minimum commitment period
noticePeriodMonths INTEGER Cancellation notice period
autoRenew BOOLEAN Auto-renewal after minimum term
renewalTermMonths INTEGER Renewal period length
vatRate DECIMAL(5,2) VAT percentage
vatIncluded BOOLEAN Price includes VAT
maxMembers INTEGER (nullable) Capacity limit
ageMinimum INTEGER (nullable) Minimum age
ageMaximum INTEGER (nullable) Maximum age
accessRules JSONB Which resources/times are included
sortOrder INTEGER Display order
visibleOnHomepage BOOLEAN Show on public pages
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

Contract

An active contract between a member and the organization, created from a MembershipTemplate. Corresponds to CsrContract2Product in Cash360.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idMember BIGINT (FK) Member
idMembershipTemplate BIGINT (FK) Source template (snapshot at time of purchase)
contractNumber VARCHAR(50) Human-readable contract number
statusCd VARCHAR(50) ACTIVE, CANCELLED, EXPIRED, SUSPENDED, PENDING
startDate DATE Contract start
endDate DATE (nullable) Contract end (null = open-ended with auto-renew)
cancellationDate DATE (nullable) When cancellation was requested
cancellationEffectiveDate DATE (nullable) When cancellation takes effect
cancellationReason VARCHAR(500) Reason for cancellation
price DECIMAL(19,4) Agreed price (copied from template at purchase)
currencyCode VARCHAR(3) Currency
billingIntervalMonths INTEGER Billing cycle
nextBillingDate DATE Next billing date
signatureData TEXT eIDAS-compliant signature (base64)
signedAt TIMESTAMPTZ Signature timestamp
customAttributes JSONB Contract-specific overrides
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

Product / Service

Offerings beyond memberships: courses, personal training sessions, merchandise, facility rentals. Corresponds to PpProduct in Cash360.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
name VARCHAR(255) Product name
description TEXT Description
categoryCd VARCHAR(50) COURSE, PERSONAL_TRAINING, MERCHANDISE, RENTAL, ADD_ON
typeCd VARCHAR(50) ONE_TIME, RECURRING, PER_SESSION
statusCd VARCHAR(50) ACTIVE, ARCHIVED, DRAFT
price DECIMAL(19,4) Price
currencyCode VARCHAR(3) Currency
vatRate DECIMAL(5,2) VAT percentage
vatIncluded BOOLEAN Price includes VAT
maxCapacity INTEGER (nullable) Capacity limit (for courses)
durationMinutes INTEGER (nullable) Session duration
sortOrder INTEGER Display order
imageUrl VARCHAR(500) Product image
customAttributes JSONB Extensible fields
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

Transaction

Payment records for billing, adjustments, and refunds. Generated by the billing engine and handed off to Cash360 for processing.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idMember BIGINT (FK) Member
idContract BIGINT (FK, nullable) Related contract
idProduct BIGINT (FK, nullable) Related product
externalTransactionId VARCHAR(255) Cash360 transaction ID
typeCd VARCHAR(50) MEMBERSHIP_FEE, SETUP_FEE, PRODUCT_PURCHASE, ADJUSTMENT, REFUND
statusCd VARCHAR(50) PENDING, SUBMITTED, PROCESSED, FAILED, CANCELLED
amount DECIMAL(19,4) Amount (positive=charge, negative=refund)
currencyCode VARCHAR(3) Currency
vatAmount DECIMAL(19,4) VAT portion
description VARCHAR(500) Human-readable description
billingPeriodStart DATE Billing period start
billingPeriodEnd DATE Billing period end
dueDate DATE Payment due date
paidDate DATE (nullable) When payment was received
paymentMethod VARCHAR(50) SEPA_DIRECT_DEBIT, BANK_TRANSFER, CASH, CARD
failureReason VARCHAR(500) Reason for failure (from Cash360 feedback)
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

BankAccount

Member bank accounts for SEPA direct debit. Corresponds to CsrBankAccount in Cash360.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idMember BIGINT (FK) Member
accountHolder VARCHAR(255) Account holder name
iban VARCHAR(34) IBAN (validated)
bic VARCHAR(11) BIC/SWIFT code
bankName VARCHAR(255) Bank name (auto-resolved from IBAN)
mandateReference VARCHAR(35) SEPA mandate reference
mandateSignDate DATE Mandate signature date
mandateTypeCd VARCHAR(20) CORE, B2B
isDefault BOOLEAN Default payment account
statusCd VARCHAR(50) ACTIVE, REVOKED, EXPIRED
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

Resource

Bookable resources: rooms, areas, equipment, and personnel. Derived from the Resource Management specification.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
name VARCHAR(255) Resource name
typeCd VARCHAR(50) ROOM, AREA, EQUIPMENT, PERSONNEL
statusCd VARCHAR(50) AVAILABLE, MAINTENANCE, OUT_OF_SERVICE
description TEXT Description
capacity INTEGER (nullable) Max capacity (for rooms/areas)
location VARCHAR(255) Physical location within facility
imageUrl VARCHAR(500) Photo
hourlyRate DECIMAL(19,4) (nullable) Rental cost per hour
equipmentDetails JSONB Equipment-specific: quantity, condition, serial numbers
personnelDetails JSONB Personnel-specific: qualifications, certifications, availability
hardwareIntegration JSONB IoT config: KNX addresses, MQTT topics, sensor IDs
maintenanceSchedule JSONB Recurring maintenance windows
customAttributes JSONB Extensible fields
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

ResourceBooking

Calendar-based booking of resources with conflict detection.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idResource BIGINT (FK) Booked resource
idBookedBy BIGINT (FK) User who created the booking
idEvent BIGINT (FK, nullable) Linked event
idCourse BIGINT (FK, nullable) Linked course
title VARCHAR(255) Booking title
startTime TIMESTAMPTZ Start time
endTime TIMESTAMPTZ End time
recurrenceRule VARCHAR(255) iCalendar RRULE (for recurring bookings)
statusCd VARCHAR(50) CONFIRMED, TENTATIVE, CANCELLED
notes TEXT Notes
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

Event

Tournaments, competitions, workshops, and social gatherings.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
name VARCHAR(255) Event name
typeCd VARCHAR(50) TOURNAMENT, WORKSHOP, SOCIAL, COMPETITION, CAMP
statusCd VARCHAR(50) DRAFT, PUBLISHED, ONGOING, COMPLETED, CANCELLED
description TEXT Event description
startDate TIMESTAMPTZ Start date/time
endDate TIMESTAMPTZ End date/time
location VARCHAR(500) Event location
maxParticipants INTEGER (nullable) Capacity
registrationDeadline TIMESTAMPTZ (nullable) Registration cutoff
entryFee DECIMAL(19,4) (nullable) Entry fee
currencyCode VARCHAR(3) Currency
imageUrl VARCHAR(500) Event image
details JSONB Event-type-specific data (brackets, schedules, sponsors)
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

Course

Recurring classes and training sessions with instructor assignment.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idInstructor BIGINT (FK) Trainer/instructor (references Member or User)
idResource BIGINT (FK, nullable) Assigned room/area
name VARCHAR(255) Course name
description TEXT Description
categoryCd VARCHAR(50) FITNESS, YOGA, MARTIAL_ARTS, DANCE, TEAM_SPORT, OTHER
statusCd VARCHAR(50) ACTIVE, PAUSED, ARCHIVED
maxParticipants INTEGER Capacity
durationMinutes INTEGER Session duration
recurrenceRule VARCHAR(255) iCalendar RRULE
startDate DATE Course start date
endDate DATE (nullable) Course end date
level VARCHAR(50) BEGINNER, INTERMEDIATE, ADVANCED, ALL_LEVELS
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

Communication

Messages, notifications, and template-based communication.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idSender BIGINT (FK) Sending user
channelCd VARCHAR(50) EMAIL, PUSH, SMS, IN_APP
typeCd VARCHAR(50) NOTIFICATION, REMINDER, MARKETING, SYSTEM
statusCd VARCHAR(50) DRAFT, QUEUED, SENT, FAILED, BOUNCED
subject VARCHAR(500) Message subject
body TEXT Message body (HTML for email, plain for push/SMS)
idTemplate BIGINT (FK, nullable) Source template
recipientFilter JSONB Audience filter criteria
scheduledAt TIMESTAMPTZ (nullable) Scheduled delivery time
sentAt TIMESTAMPTZ (nullable) Actual delivery time
metadata JSONB Delivery metadata (bounce info, open tracking)
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

Device

Check-in terminals, door controllers, and IoT devices.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
name VARCHAR(255) Device name
typeCd VARCHAR(50) CHECK_IN_TERMINAL, DOOR_LOCK, SENSOR, SHELLY, DISPLAY
statusCd VARCHAR(50) ONLINE, OFFLINE, MAINTENANCE
serialNumber VARCHAR(100) Hardware serial
location VARCHAR(255) Physical location
ipAddress VARCHAR(45) Network address
protocol VARCHAR(50) MQTT, KNX, BACNET, HTTP, NFC
configuration JSONB Device-specific config
lastHeartbeat TIMESTAMPTZ Last seen online
firmwareVersion VARCHAR(50) Firmware version
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

Document

Files attached to members, entities, or contracts (contracts, medical certificates, photos).

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idMember BIGINT (FK, nullable) Associated member
idContract BIGINT (FK, nullable) Associated contract
name VARCHAR(255) Document name
typeCd VARCHAR(50) CONTRACT, MEDICAL, PHOTO, INVOICE, RECEIPT, OTHER
mimeType VARCHAR(100) MIME type
fileSize BIGINT Size in bytes
storagePath VARCHAR(500) Object storage path
checksumSha256 VARCHAR(64) Integrity hash
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

DataImport

CSV import jobs with column mapping templates.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idUser BIGINT (FK) User who initiated import
name VARCHAR(255) Import job name
targetTypeCd VARCHAR(50) MEMBERS, SERVICES, TRANSACTIONS
modeCd VARCHAR(50) NEW_ONLY, NEW_AND_UPDATE, UPDATE_ONLY
statusCd VARCHAR(50) UPLOADED, MAPPING, VALIDATING, EXECUTING, COMPLETED, FAILED
fileName VARCHAR(255) Original file name
storagePath VARCHAR(500) Storage path of uploaded CSV
columnMapping JSONB Column mapping (CSV header -> entity field)
mappingTemplateId BIGINT (FK, nullable) Saved mapping template
totalRows INTEGER Total rows in file
processedRows INTEGER Rows processed so far
successRows INTEGER Successfully imported
errorRows INTEGER Rows with errors
errorLog JSONB Per-row error details
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

CheckIn

Access log recording member check-ins via QR code, NFC, or manual entry.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idMember BIGINT (FK) Member
idDevice BIGINT (FK, nullable) Device used for check-in
idResource BIGINT (FK, nullable) Resource accessed
methodCd VARCHAR(50) QR_CODE, NFC, MANUAL, BIOMETRIC
statusCd VARCHAR(50) GRANTED, DENIED, OVERRIDE
denialReason VARCHAR(255) Reason if denied (expired contract, suspended, etc.)
checkinTime TIMESTAMPTZ Check-in timestamp
checkoutTime TIMESTAMPTZ (nullable) Check-out timestamp
createdAt TIMESTAMPTZ Audit

Lead

Prospective member or B2B customer tracked through the sales pipeline. Used by both club-level sales (trial-to-member conversion) and vendor-level sales (customer acquisition).

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
source VARCHAR(50) WEBSITE, REFERRAL, WALK_IN, CAMPAIGN, IMPORT, PARTNER, EVENT
statusCd VARCHAR(50) NEW, CONTACTED, QUALIFIED, PROPOSAL, WON, LOST
firstName VARCHAR(100) First name
lastName VARCHAR(100) Last name
email VARCHAR(255) Contact email
phone VARCHAR(50) Contact phone
companyName VARCHAR(255) Company name (for B2B leads)
idAssignedTo BIGINT (FK, nullable) Assigned sales user
expectedValue DECIMAL(19,4) (nullable) Expected deal value
expectedCloseDate DATE (nullable) Expected conversion date
lostReason VARCHAR(500) (nullable) Reason for loss (if statusCd=LOST)
notes TEXT Internal notes
tags JSONB Flexible tagging
customAttributes JSONB Extensible custom fields
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

Deal

A sales opportunity linked to a lead, tracking expected value, probability, and pipeline stage through to closure.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idLead BIGINT (FK) Source lead
idMember BIGINT (FK, nullable) Linked member (after conversion)
name VARCHAR(255) Deal name
pipelineStageCd VARCHAR(50) Configurable per entity (e.g., INITIAL, DEMO, TRIAL, NEGOTIATION, CLOSED)
value DECIMAL(19,4) Deal value
currencyCode VARCHAR(3) ISO 4217
probabilityPercent INTEGER Win probability (0-100)
expectedCloseDate DATE Expected close date
statusCd VARCHAR(50) OPEN, WON, LOST
lostReason VARCHAR(500) (nullable) Reason for loss
notes TEXT Internal notes
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

Activity

Sales and support activity log entry tracking interactions with leads, deals, or members.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idLead BIGINT (FK, nullable) Related lead
idDeal BIGINT (FK, nullable) Related deal
idMember BIGINT (FK, nullable) Related member
idUser BIGINT (FK) User who performed the activity
typeCd VARCHAR(50) CALL, EMAIL, MEETING, NOTE, TASK, DEMO, FOLLOW_UP
subject VARCHAR(500) Activity subject/title
description TEXT Detailed description
activityDate TIMESTAMPTZ When the activity occurred
durationMinutes INTEGER (nullable) Duration (for calls, meetings)
completed BOOLEAN Whether the activity is completed
nextFollowUpDate DATE (nullable) Scheduled follow-up date
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

Ticket

Support ticket for tracking member inquiries, issues, and operational requests through resolution.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
ticketNumber VARCHAR(50) Human-readable ticket number (auto-generated)
idMember BIGINT (FK, nullable) Reporting member (null for internal tickets)
idCreatedBy BIGINT (FK) User who created the ticket
idAssignedTo BIGINT (FK, nullable) Assigned support agent
categoryCd VARCHAR(50) BILLING, ACCESS, TECHNICAL, FEEDBACK, COMPLAINT, CONTRACT, GENERAL
priorityCd VARCHAR(50) LOW, NORMAL, HIGH, URGENT
statusCd VARCHAR(50) OPEN, IN_PROGRESS, WAITING, RESOLVED, CLOSED
subject VARCHAR(500) Ticket subject
description TEXT Ticket body/description
channelCd VARCHAR(50) EMAIL, IN_APP, WEB_FORM, PHONE, WHATSAPP
slaResponseDeadline TIMESTAMPTZ (nullable) SLA: first response due by
slaResolutionDeadline TIMESTAMPTZ (nullable) SLA: resolution due by
firstResponseAt TIMESTAMPTZ (nullable) Actual first response time
resolvedAt TIMESTAMPTZ (nullable) When ticket was resolved
satisfactionScore INTEGER (nullable) CSAT rating (1-5)
tags JSONB Flexible tagging (e.g., ["recurring", "escalated"])
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

TicketComment

A comment on a support ticket, either public (visible to member) or internal (staff-only).

Field Type Description
id BIGINT (PK) Primary key
idTicket BIGINT (FK) Parent ticket
idUser BIGINT (FK) Comment author
body TEXT Comment text (HTML supported)
isInternal BOOLEAN True = staff-only note, false = visible to member
attachments JSONB Array of attachment references [{name, storagePath, mimeType, size}]
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

KnowledgeBaseArticle

Help center article for member self-service and agent reference.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant (null for platform-wide articles)
title VARCHAR(500) Article title
slug VARCHAR(255) URL-friendly slug
body TEXT Article body (HTML)
categoryCd VARCHAR(50) BILLING, ACCESS, ACCOUNT, TECHNICAL, GETTING_STARTED, FAQ
statusCd VARCHAR(50) DRAFT, PUBLISHED, ARCHIVED
viewCount INTEGER Number of views
helpfulCount INTEGER "Was this helpful?" positive votes
notHelpfulCount INTEGER "Was this helpful?" negative votes
tags JSONB Flexible tagging
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

AccountingEntry

General ledger journal entry for bookkeeping and DATEV export.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
entryNumber VARCHAR(50) Sequential journal entry number
entryDate DATE Posting date
accountCode VARCHAR(20) Chart of accounts code (e.g., "8400" for revenue)
contraAccountCode VARCHAR(20) Contra account code (double-entry)
debitAmount DECIMAL(19,4) Debit amount
creditAmount DECIMAL(19,4) Credit amount
currencyCode VARCHAR(3) ISO 4217
description VARCHAR(500) Posting description
idCostCenter BIGINT (FK, nullable) Cost center allocation
idTransaction BIGINT (FK, nullable) Link to billing transaction (for auto-postings)
postingTypeCd VARCHAR(50) AUTOMATIC, MANUAL, ADJUSTMENT
statusCd VARCHAR(50) DRAFT, POSTED, VOID
periodYear INTEGER Fiscal year
periodMonth INTEGER Fiscal month (1-12)
datevExported BOOLEAN Whether this entry has been included in a DATEV export
datevExportDate TIMESTAMPTZ (nullable) When exported to DATEV
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

CostCenter

Organizational cost center for financial reporting and budget management.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
code VARCHAR(20) Cost center code
name VARCHAR(255) Cost center name
description TEXT Description
budget DECIMAL(19,4) (nullable) Annual budget
currencyCode VARCHAR(3) ISO 4217
statusCd VARCHAR(50) ACTIVE, ARCHIVED
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

ChartOfAccount

Account definition in the general ledger chart of accounts (SKR03/SKR04 compatible).

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
accountCode VARCHAR(20) Account number (e.g., "1200", "8400")
accountName VARCHAR(255) Account name
accountTypeCd VARCHAR(50) ASSET, LIABILITY, EQUITY, REVENUE, EXPENSE
parentAccountCode VARCHAR(20) (nullable) Parent account for hierarchy
datevAccountCode VARCHAR(20) (nullable) DATEV-mapped account code (if different)
statusCd VARCHAR(50) ACTIVE, ARCHIVED
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

AccessZone

Hierarchical physical zone for access control management (building > floor > room > locker).

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
name VARCHAR(255) Zone name
typeCd VARCHAR(50) BUILDING, FLOOR, ROOM, LOCKER_AREA, OUTDOOR, PARKING
idParentZone BIGINT (FK, nullable) Parent zone (self-referencing hierarchy)
capacity INTEGER (nullable) Maximum occupancy
currentOccupancy INTEGER Real-time occupancy count
description TEXT Description
statusCd VARCHAR(50) ACTIVE, MAINTENANCE, CLOSED
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

AccessRule

Defines which membership templates grant access to which zones, with time and day restrictions.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idAccessZone BIGINT (FK) Target zone
idMembershipTemplate BIGINT (FK, nullable) Applicable membership template (null = all templates)
ruleName VARCHAR(255) Human-readable rule name
timeRestriction JSONB Allowed times: {"mon": ["06:00-22:00"], "sat": ["08:00-18:00"]}
antiPassback BOOLEAN Require exit before re-entry
priorityOrder INTEGER Rule evaluation priority (lower = higher priority)
statusCd VARCHAR(50) ACTIVE, DISABLED
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

Credential

Physical or digital access credential issued to a member for check-in and door access.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idMember BIGINT (FK) Credential holder
typeCd VARCHAR(50) NFC_CARD, QR_CODE, BLE, BIOMETRIC_FINGERPRINT, BIOMETRIC_FACE, PIN
credentialIdentifier VARCHAR(500) Encrypted credential data (card UID, QR token, BLE key)
statusCd VARCHAR(50) ACTIVE, SUSPENDED, REVOKED, EXPIRED
validFrom TIMESTAMPTZ Credential valid from
validUntil TIMESTAMPTZ (nullable) Credential expiry (null = no expiry)
fallbackOrder INTEGER Priority in fallback chain (lower = preferred)
lastUsedAt TIMESTAMPTZ (nullable) Last successful use
issuedBy BIGINT (FK) User who issued the credential
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

DashboardConfig

User-specific dashboard layout configuration with role-appropriate defaults.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK, nullable) Tenant (null for vendor-level dashboards)
idUser BIGINT (FK) Dashboard owner
name VARCHAR(255) Dashboard name
roleCd VARCHAR(50) Target role (for default dashboards)
layout JSONB Widget positions, sizes, data sources, filters
isDefault BOOLEAN Whether this is the default for the role
version INTEGER Optimistic locking
createdAt TIMESTAMPTZ Audit
updatedAt TIMESTAMPTZ Audit

AuditLog

Immutable audit trail for compliance and debugging.

Field Type Description
id BIGINT (PK) Primary key
idEntity BIGINT (FK) Tenant
idUser BIGINT (FK) User who performed the action
action VARCHAR(50) CREATE, UPDATE, DELETE, LOGIN, EXPORT, etc.
entityType VARCHAR(100) Target entity class name
entityId BIGINT Target entity ID
oldValue JSONB Previous state (for updates)
newValue JSONB New state (for creates/updates)
ipAddress VARCHAR(45) Client IP
userAgent VARCHAR(500) Client user agent
createdAt TIMESTAMPTZ Timestamp (immutable, no updatedAt)

Entity-Relationship Diagram

erDiagram Entity ||--o{ Member : "has members" Entity ||--o{ User : "has users" Entity ||--o{ MembershipTemplate : "defines templates" Entity ||--o{ Product : "offers products" Entity ||--o{ Resource : "owns resources" Entity ||--o{ Event : "hosts events" Entity ||--o{ Course : "runs courses" Entity ||--o{ Device : "manages devices" Entity ||--o{ DataImport : "imports data" Entity }o--o| Entity : "parent-child" Member ||--o| User : "has login" Member ||--o{ Contract : "has contracts" Member ||--o{ BankAccount : "has bank accounts" Member ||--o{ Transaction : "has transactions" Member ||--o{ CheckIn : "check-in history" Member ||--o{ Document : "has documents" Member ||--o{ Credential : "has credentials" Member ||--o{ Ticket : "reports issues" Member }o--o| Member : "responsible person" MembershipTemplate ||--o{ Contract : "instantiated as" MembershipTemplate ||--o{ AccessRule : "grants access" Contract ||--o{ Transaction : "generates transactions" Contract ||--o{ Document : "signed documents" Product ||--o{ Transaction : "purchased via" Resource ||--o{ ResourceBooking : "booked via" Resource ||--o{ CheckIn : "accessed via" Event ||--o{ ResourceBooking : "reserves resources" Course ||--o{ ResourceBooking : "uses resources" Course }o--|| User : "taught by instructor" Device ||--o{ CheckIn : "records check-ins" Communication }o--o| CommunicationTemplate : "based on template" Communication }o--|| User : "sent by" Lead ||--o{ Deal : "generates deals" Lead ||--o{ Activity : "has activities" Lead }o--o| User : "assigned to" Deal ||--o{ Activity : "has activities" Deal }o--o| Member : "converts to member" Activity }o--|| User : "performed by" Ticket ||--o{ TicketComment : "has comments" Ticket }o--o| User : "assigned to" Entity ||--o{ AccessZone : "has zones" AccessZone }o--o| AccessZone : "parent-child" AccessZone ||--o{ AccessRule : "governed by" Entity ||--o{ AccountingEntry : "has entries" AccountingEntry }o--o| CostCenter : "allocated to" AccountingEntry }o--o| Transaction : "linked to" Entity ||--o{ ChartOfAccount : "has accounts" Entity ||--o{ CostCenter : "has cost centers" Entity ||--o{ Lead : "has leads" Entity ||--o{ Ticket : "has tickets" Entity ||--o{ KnowledgeBaseArticle : "has articles" Entity ||--o{ DashboardConfig : "has dashboards" CheckIn }o--o| AccessZone : "in zone" CheckIn }o--o| Credential : "using credential"

Migration Mapping from Cash360

The following table maps Cash360 entities to the new Membership data model. This mapping guides data migration (see Chapter 15).

Cash360 Entity Cash360 Table Membership Entity Key Differences
MbLogin mb_login User Added: refresh token, MFA, brute-force protection, password reset flow
MbConsumer mb_consumer Member Added: emergency contacts, responsible person, tags, member number
CsrConsumer csr_consumer Member (backend enrichment) JSONB custom attributes preserved; bank details moved to BankAccount
CsrContractPreDefined csr_contract_pre_defined MembershipTemplate Added: age restrictions, access rules, homepage visibility, setup fee
CsrContract2Product csr_contract_2_product Contract Added: cancellation workflow, eIDAS signature, next billing date
CsrBankAccount csr_bank_account BankAccount Added: mandate type (CORE/B2B), status tracking, default flag
PmTransaction pm_transaction Transaction Simplified: only membership-relevant fields; Cash360 handles payment processing
PpProduct pp_product Product Added: categories, capacity, duration; removed: complex pricing tiers
McEntity mc_entity Entity Added: white-label (logo, color), timezone, locale, JSONB settings
McUser mc_user User (admin roles) Merged with MbLogin into unified User entity with role-based access
EbSepaExport eb_sepa_export (handled by Cash360) SEPA export generation stays in Cash360; Membership only submits transactions

New entities (no Cash360 equivalent — net new):

Membership Entity Module Purpose
Lead membership-crm Sales lead tracking
Deal membership-crm Pipeline deal management
Activity membership-crm Sales/support activity log
Ticket membership-support Support ticket management
TicketComment membership-support Ticket conversation thread
KnowledgeBaseArticle membership-support Self-service help center
AccountingEntry membership-accounting General ledger journal entries
CostCenter membership-accounting Financial cost centers
ChartOfAccount membership-accounting Ledger account definitions
AccessZone membership-checkin Physical access zones
AccessRule membership-checkin Zone access policies
Credential membership-checkin Member access credentials
DashboardConfig membership-core User dashboard layouts

Multi-Tenancy Strategy

Every business entity in the database carries an idEntity column that references the Organization table. This is enforced at three levels:

  1. Database level: All queries include a WHERE id_entity = ? clause. A TenantInterceptor in Hibernate automatically injects the tenant filter, preventing cross-tenant data leakage even if application code omits the filter.

  2. Application level: The TenantContext is resolved from the JWT token at request entry and propagated via a ThreadLocal (or Reactor context for reactive flows). Every repository method receives the tenant ID implicitly.

  3. API level: Tenant resolution happens during authentication. A user can only access data belonging to their assigned entity. Group admins and franchise admins can access child entities through explicit parent-child traversal, never through a blanket "all data" query.

For large enterprise deployments, the architecture supports schema-per-tenant isolation as an upgrade path, where each tenant gets a dedicated PostgreSQL schema. This is configured per deployment, not per tenant.


JSONB Custom Attributes

Following the Cash360 pattern, several entities include a customAttributes column of type JSONB. This allows tenants to define custom fields without schema changes.

Structure convention:

{
  "fields": [
    {
      "key": "jersey_size",
      "label": "Jersey Size",
      "type": "SELECT",
      "options": ["XS", "S", "M", "L", "XL", "XXL"],
      "required": false,
      "value": "L"
    },
    {
      "key": "medical_note",
      "label": "Medical Note",
      "type": "TEXT",
      "required": false,
      "value": "Asthma - carries inhaler"
    }
  ]
}

Supported field types: TEXT, NUMBER, DATE, BOOLEAN, SELECT, MULTI_SELECT, URL, EMAIL, PHONE.

Custom attribute definitions are stored in the Entity settings JSONB column as a schema that client applications render dynamically. This keeps the database schema stable while allowing per-tenant customization.