Database Properties
Database Type: Redshift - 8.0.2
Schema erp_v2
Real-Time PerfectGym Next Enterprise Data Warehouse
These are the docs for the new
erp_v2Data Warehouse schema that is served in near real time. To see the docs for the old schema, please refer to the legacy schema documentation.
This read-only schema provides selected business relevant data of PerfectGym Next in an unaggregated per-event grain in the form of multiple fact and dimension tables (star/galaxy/fact-constellation schema).
It’s targeted to use for analytical purposes in BI tools like PowerBI, time uncritical direct queries or as source for a custom pipeline, where data can be further enriched or prepared for fast access.
Authentication
- Connection is restricted to a static IP address we need from you
- A single
USER&PASSWORD+HOSTare provided - User has access to a single database of the same name
Connection
Please fill in the arguments, as provided by us.
Via odbc see aws documentation
Driver={Amazon Redshift (x64)};Server=<HOST>;Database=<USER>;UID=<USER>;PWD=<PASSWORD>;Port=5439
Via jdbc see aws documentation
jdbc:redshift://<HOST>:5439/<USER>
Updates
Tables are synced incrementally (inserts/updates/deletes) every few minutes
Non-Breaking Changes
- New tables are announced in the Changelog on the same date they are added
- New columns on existing tables are announced in the Changelog on the same date they are added
Breaking Changes
- Tables are marked as deprecated in their documentation before they are deleted, to allow users to adapt beforehand
- Columns are marked as deprecated in their documentation before they are deleted, to allow users to adapt beforehand
- Deprecations are announced in the Changelog on the same date
For Data Extractions
Use data_landing_time as the incremental extraction watermark. It is the UTC timestamp assigned when a row is applied to the Data Warehouse.
Rows applied in the same table batch share one value. Table batches are applied sequentially across the schema, so values are non-decreasing in warehouse application order across tables. A full refresh also assigns a new landing timestamp to the refreshed rows. The value represents warehouse application time, not source-event time.
For independent table loads:
SELECT *
FROM perfectgym_next.your_table
WHERE data_landing_time > :last_watermark;
Advance the watermark only after the extraction and destination load succeed.
If referential consistency across multiple tables is required, use one common cutoff for the extraction run:
SELECT *
FROM perfectgym_next.your_table
WHERE data_landing_time > :last_watermark
AND data_landing_time <= :cutoff;
Set :cutoff once for the run, optionally excluding recent data:
CURRENT_TIMESTAMP - INTERVAL '1 hour'
This allows related tables to be extracted consistently up to the same point. An overlap, such as subtracting one hour from :last_watermark, is an alternative defensive strategy for retries or partial loads; overlapping rows must be processed idempotently.
data_landing_time differs from last_updated: data_landing_time records warehouse application time and is the recommended extraction watermark, while last_updated records the upstream row update or processing timestamp and is not a reliable replacement.
data_landing_time does not retain deleted rows. Use periodic reconciliation or another deletion-handling strategy when deletes must be captured.
Anonymization / Access Level
Generally all data-privacy settings from the source System, like anonymizing checkins after a certain time period, are also applied on this Data Warehouse.
Additionally, there are 3 different types of access level we provide:
- Owner: Client that owns the whole tenant in the source System. All data is provided.
- Franchisee: Client that owns a subset of the tenants studios in the source System. Only fact data of selected studios is provided. Dimensional data of other studios can appear but is anonymized.
- Franchise System: Client that owns the whole tenant in the source System but doesn’t operate studios directly. All fact data is provided but anonymized.
Your accounts access level will be defined during setup with your account manager.
Best Practices
Using Views
To ensure our ETL process can properly refresh the underlying tables, it is critical that you create views using the WITH NO SCHEMA BINDING option.
This type of view, also known as a late-binding view, does not create a dependency between the view and the underlying tables. This allows us to drop and recreate tables without affecting your views.
To create a late-binding view in Redshift, use the following syntax:
CREATE VIEW public.your_view_name
AS
SELECT
column1,
column2,
...
FROM
perfectgym_next.dim_or_fact_table_name
WITH NO SCHEMA BINDING;
By adhering to this practice, you will prevent issues with our data refresh process and ensure the continuous availability of your data.
Contact
- For feedback and issues, please contact your account manager
Tables
| Table / View | Children | Parents | Columns | Type | Comments |
|---|---|---|---|---|---|
| fct_trainer_class_appointments | 0 | 7 | 10 | Table | |
| dim_inclusive_contingent | 3 | 0 | 9 | Table | |
| dim_discount_campaign_discount_period | 0 | 2 | 14 | Table | Defines the discount amounts and effective periods for discount campaigns. Covers all three campaign scope types — main contract rate bundle (RATE_BUNDLE), flat-fee bundle (FLAT_FEE), and optional add-on module (MODULE) — in a single table. Each row represents one discount tier (position) for one campaign scope entry. Multiple tiers per scope entry are possible (e.g. position 0: 100% off for 3 months, position 1: 50% off for the following 3 months). Join to |
| fct_payment_run | 0 | 5 | 15 | Table | |
| dim_employee | 5 | 0 | 22 | Table | Table contains all employees and their relevant information |
| dim_contract_voucher_definition | 3 | 3 | 23 | Table | A definition of a voucher that can be generated into voucher codes and applied to a contract to get a discount or credit. Vouchers can be used to grant discounts on contracts, waive fees, or provide credit. |
| fct_revenue_cash_based | 0 | 6 | 29 | Table | |
| dim_purchased_contingent | 4 | 4 | 23 | Table | |
| fct_idle_period | 0 | 8 | 21 | Table | |
| dim_customer_dunning_configuration | 0 | 1 | 14 | Table | Dimension table exposing the dunning and billing stop configuration per customer. Each customer has at most one row. All four stop types are sourced from a single record configured manually by studio operators. Stop types use a three-value LimitType pattern: - DISABLED — the stop is not active - UNLIMITED — the stop is permanently active (until_date is NULL) - LIMITED — the stop is active until until_date (inclusive) To test whether a stop is currently active as of a reference date, apply: Important: This table covers only manually configured stops set by studio operators. Dunning-engine-triggered collection stops (automatically set when a dunning level is reached) are stored in
Use cases: - Active billable member counts: exclude customers where collection_stop_limit_type is UNLIMITED or (LIMITED and collection_stop_until_date >= reference_date) - Dunning portfolio analysis: identify customers where dunning is paused - Debt collection oversight: track customers blocked from external collection handover - Invoice audit: identify customers where invoice generation is suppressed |
| dim_customer_group_member_discount | 0 | 1 | 7 | Table | Defines the group discount schedule for a customer group. Each row is one step in the schedule: when the number of eligible group members reaches or exceeds |
| dim_date | 24 | 0 | 17 | Table | Date dimension covering years 1900-2099 |
| dim_studio_starter_package_adjustment | 0 | 3 | 7 | Table | |
| fct_pos_saleposition | 2 | 3 | 23 | Table | |
| dim_contract_term | 1 | 0 | 5 | Table | The term of the contract. |
| bridge_organization_unit_to_organization_unit_code | 0 | 2 | 5 | Table | Link organization unit (gym) to all its organization unit codes (tags). |
| fct_rate_term_payment_frequency_price_adjustment | 0 | 3 | 15 | Table | |
| bridge_rate_bundle_to_company | 0 | 2 | 7 | Table | Bridge table linking rate bundles to partner companies for corporate deals, including any cooperation identifier used for that partnership. |
| dim_device | 2 | 0 | 7 | Table | A device connected to the system, which enables registering customers using certain areas (the whole gym, the gym sauna) or machines (eg a massage bed) of a gym. |
| dim_trainer_appointment_status | 1 | 0 | 4 | Table | |
| dim_rate_term_configuration | 6 | 1 | 23 | Table | |
| dim_rate_localized | 0 | 1 | 7 | Table | |
| fct_contract_voucher | 1 | 4 | 24 | Table | |
| dim_campaign | 3 | 0 | 8 | Table | Campaign dimension |
| bridge_rate_bundle_to_payment_choice | 0 | 1 | 5 | Table | Bridge table listing which payment choices are allowed when selling a rate bundle. |
| bridge_rate_to_rate_code | 0 | 2 | 5 | Table | Bridge table linking rates to their assigned rate codes (tags). A rate can have multiple codes and a code can be assigned to multiple rates. |
| fct_payment_instrument_status_history | 0 | 4 | 13 | Table | |
| fct_rate_bundle_term_availability | 0 | 2 | 7 | Table | |
| dim_cancellation_reason | 3 | 0 | 7 | Table | DEPRECATED. Use
|
| bridge_revenue_to_purchased_contingent | 0 | 2 | 5 | Table | Bridge table linking revenue transactions to purchased contingents (day passes, class packs, etc.). Handles many-to-many relationships where one sale position may create multiple contingents (e.g., bundle products, family packs). Use this table to analyze revenue by specific purchased contingent while avoiding grain issues and revenue duplication. Example use cases: - “Show revenue generated from day pass sales with their utilization rates” - “Analyze which purchased contingents contribute most to revenue” - “Track revenue for bundle products that create multiple contingents” |
| dim_organization_unit_code | 1 | 0 | 5 | Table | |
| dim_contract_voucher_rate_discount_period | 0 | 5 | 15 | Table | A period during which a discount is applied in the context of a contract voucher. Discounts are defined at a hierarchical granularity: rate → term configuration → payment frequency. A null at any level means the discount applies to all values at that level and below. For example, a null rate_id means the discount covers all rates; a set rate_id with a null rate_term_configuration_id means all term configurations of that rate. |
| dim_rate_bundle_term | 3 | 3 | 7 | Table | |
| bridge_pos_saleposition_to_payment | 0 | 1 | 5 | Table | Bridge table linking each POS sale position to every payment actively settling it. A single sale position can be split across multiple payments (e.g. partial settlements or split payment methods), so this table has a many-to-many grain: one row per active sale-position-to-payment link. Use this table instead of the deprecated fct_pos_saleposition.internal_payment_id, which collapses splits down to a single link and loses this granularity. |
| dim_class | 3 | 0 | 10 | Table | A class that a customer can participate in, e.g. yoga, dance class, etc |
| dim_service | 6 | 0 | 12 | Table | |
| dim_dunning_level | 1 | 0 | 7 | Table | Dimension table for dunning levels configured in the Magicline dunning engine. Each row represents one level in a dunning escalation ladder, as defined by a studio’s dunning configuration template. Two level types exist ( Join from |
| fct_invoice | 1 | 7 | 32 | Table | |
| bridge_service_to_organization_unit | 0 | 2 | 6 | Table | Access control mapping that defines which services are available at which gym locations. Services must be explicitly whitelisted for a gym before they can be booked or used there. This enables multi-location businesses to offer different service menus at different facilities (e.g., specialized classes only at flagship locations, or region-specific offerings). |
| dim_contract_property | 1 | 0 | 10 | Table | A set of basic contract properties, e.g whether or not contract is signed, via which service it was created, is contract disabled, which payment type was used for the contract, etc. |
| dim_rate | 15 | 0 | 7 | Table | |
| dim_appointment | 5 | 0 | 10 | Table | The unique event of an appointment on the calendar with its properties. |
| dim_loss_reason | 1 | 0 | 5 | Table | |
| dim_rate_term_payment_frequency | 4 | 2 | 10 | Table | |
| bridge_discount_campaign_to_organization_unit | 0 | 2 | 5 | Table | Maps studios (organization units) to their currently active discount campaign. One row per studio — at most one active discount campaign per studio is represented here. This is a point-in-time snapshot sourced from Important limitation: When a studio deactivates a discount campaign, the corresponding row is hard-deleted — no historical record is preserved. |
| fct_payment | 0 | 4 | 21 | Table | |
| fct_class_appointment | 0 | 6 | 15 | Table | |
| dim_payment_instrument | 1 | 2 | 12 | Table | |
| fct_revenue_invoice_based | 0 | 9 | 25 | Table | |
| fct_class_event | 0 | 10 | 14 | Table | |
| dim_customer | 31 | 0 | 33 | Table | A customer is a person who signed up to a studio owned by you or your franchise. |
| dim_discount_campaign_localized | 0 | 1 | 7 | Table | Localized public names and descriptions for discount campaigns, one row per campaign per locale. Used to display campaign information in the member’s preferred language (e.g. in the MySports app or online checkout). Follows the same pattern as dim_rate_localized and dim_cancellation_reason_localized. |
| dim_cash_register | 1 | 1 | 10 | Table | A physical or virtual point-of-sale register, used to process sales and issue receipts. |
| dim_daytime | 0 | 0 | 7 | Table | This table contains all times of a day from |
| dim_payment_run_property | 1 | 0 | 7 | Table | |
| dim_idle_period_property | 1 | 1 | 10 | Table | |
| dim_closing_hours | 0 | 1 | 10 | Table | Irregular or recurring closure times for an organization unit (gym). Defines exceptions to the regular opening hours, including one-time closures and yearly recurring closures (holidays, maintenance, etc.). YEARLY entries are expanded into specific datetime ranges based on creation/archival dates. |
| dim_lead_stage | 2 | 0 | 8 | Table | |
| dim_revenue_group | 3 | 0 | 5 | Table | |
| dim_contract_payment_frequency | 1 | 0 | 8 | Table | Defines how often and how much is paid for an individual contract. |
| dim_contract_voucher_definition_localized | 0 | 1 | 11 | Table | Localized text for contract voucher definitions, one row per definition per locale. Includes the public-facing name and description shown to members, plus the staff-only internal description used to categorise a promotion or voucher (not visible to members). |
| dim_discount_campaign_scope | 1 | 3 | 9 | Table | Defines which rate bundles (and optionally which specific terms) are in scope for each discount campaign, across all three price component types: RATE_BUNDLE (main contract), FLAT_FEE (flat-fee bundle), and MODULE (optional add-on). One row per scope entry. A NULL Use this table to answer: “Which rate bundles have a discount campaign set on them?” and “Does this campaign apply to all bundles or only specific ones?” Join with |
| fct_employee_access | 0 | 2 | 7 | Table | |
| fct_lead_stage_history | 0 | 4 | 13 | Table | |
| dim_rate_bundle | 4 | 0 | 8 | Table | |
| dim_class_event_property | 1 | 0 | 6 | Table | The table contains simple properties of class events. This is a junk dimension that stores distinct combinations of event status, source, and booked_for_free flag. |
| dim_customer_code | 1 | 0 | 8 | Table | Dimension table containing customer codes (tags) used to categorize customers. Customer codes help organize and filter customers based on business-defined categories. Each customer code has a unique identifier and can be associated with multiple customers. |
| bridge_customer_group_to_customer | 0 | 2 | 11 | Table | Records each customer’s membership in a customer group, one row per membership event. Captures the validity period, the member’s individual discount eligibility, and — for |
| dim_organization_unit | 40 | 0 | 16 | Table | |
| fct_dunning_step | 0 | 2 | 18 | Table | |
| dim_cancellation_reason_localized | 0 | 1 | 6 | Table | The localized version of a cancellation reason, defining translated information of a cancellation reason per locale. One cancellation reason can have multiple localized versions. |
| fct_customer_studio_history | 0 | 2 | 8 | Table | |
| dim_contract_cancellation_reason | 1 | 1 | 9 | Table | Contract cancellations with their reasons. Built from actual contract cancellations that occurred in the system. Includes information about how the cancellation was initiated, the type of cancellation, and the reason. |
| dim_company_code | 1 | 0 | 6 | Table | Company codes (tags) that can be assigned to companies for categorization and filtering purposes. Similar to customer codes but for partner companies. |
| dim_contract_cancellation_property | 1 | 0 | 5 | Table | DEPRECATED. Use
|
| dim_opening_hours | 0 | 1 | 8 | Table | |
| fct_customer_appointment | 0 | 6 | 17 | Table | |
| dim_discount_campaign | 6 | 0 | 8 | Table | A discount campaign is a time-bound promotional discount configuration that studio administrators define and activate per studio. When active, it automatically applies a discount to contracts signed via the configured allowed sales channels (origin types). A campaign defines its validity window ( |
| bridge_company_to_company_code | 0 | 2 | 5 | Table | Bridge table linking companies to their assigned company codes (tags). A company can have multiple codes and a code can be assigned to multiple companies. |
| bridge_customer_to_customer_code | 0 | 2 | 5 | Table | Link customer to all his customer codes. |
| fct_checkin | 0 | 6 | 12 | Table | |
| bridge_discount_campaign_to_allowed_origin_type | 0 | 1 | 5 | Table | Maps discount campaigns to their allowed sales channel origin types. One row per (campaign, origin_type) pair. Only origin types listed here are permitted to trigger the campaign discount when a contract is signed. If a contract is created via a channel not present in this table for the active campaign, the campaign discount is not applied. |
| dim_company | 8 | 0 | 36 | Table | A ‘partner company’ that contracts can be related to for the Corporate Fitness program. Only includes companies that are currently whitelisted for the studios related to this DWH instance. |
| fct_contract_cancellation | 0 | 10 | 14 | Table | |
| dim_product | 7 | 1 | 18 | Table | |
| fct_lead_lifetime | 0 | 4 | 19 | Table | |
| fct_trainer_appointment | 0 | 4 | 18 | Table | |
| bridge_product_to_organization_unit | 0 | 2 | 6 | Table | Access control mapping that defines which products are available at which gym locations. Products can be made available at gyms through whitelisting (for MATERIAL, VOUCHER, and VIRTUAL types) or by being sold there (for dynamic ad-hoc products). This bridge table replaces the single organization_unit_id foreign key in dim_product to support the many-to-many relationship where products can be available at multiple locations. |
| dim_currency | 8 | 0 | 6 | Table | All available currencies |
| fct_contract | 11 | 19 | 33 | Table | |
| fct_customer_referral | 0 | 2 | 15 | Table | |
| dim_customer_custom_field | 0 | 1 | 9 | Table | Custom field values assigned to customers on lead or member level. |
| dim_customer_communication_consent | 0 | 2 | 15 | Table | Dimension table that tracks customer communication consent preferences across different message categories. This table combines customer-level and organization-level communication configurations, with customer-level settings taking priority over organization-level defaults. |
| fct_contract_price_history | 0 | 3 | 19 | Table | |
| fct_service_usage | 0 | 7 | 14 | Table | |
| dim_rate_code | 1 | 0 | 8 | Table | |
| fct_revenue | 1 | 8 | 17 | Table | |
| bridge_company_to_organization_unit | 0 | 2 | 9 | Table | Bridge table linking companies to organization units (gyms) they are whitelisted for. Represents access permissions for gyms on companies. |
| fct_contract_term_dates | 0 | 3 | 8 | Table | |
| fct_rate_term_payment_frequency_price | 0 | 4 | 18 | Table | |
| dim_customer_group | 2 | 2 | 16 | Table | One row per customer group configured in the system. Customer groups classify customers by membership arrangement and determine whether group discounts apply to their contracts. Groups belong to an organization unit and come in three types: |