{"openapi":"3.0.0","paths":{"/":{"get":{"operationId":"IndexController_index","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/"}}}}},"tags":["index"]}},"/_health":{"get":{"operationId":"HealthController_getHealthStatus","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}},"tags":["Health"]}},"/api/v1/customers/{customerId}/sites":{"post":{"operationId":"CreateCustomerSiteController_handle_v1","parameters":[{"name":"customerId","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCustomerSiteRequestDto"}}}},"responses":{"201":{"description":"Created customer site"}},"tags":["site"]}},"/api/v1/tenant":{"get":{"operationId":"TenantController_getTenants_v1","parameters":[],"responses":{"200":{"description":""}},"tags":["Tenants"]}},"/api/v1/tenant/switch":{"post":{"operationId":"TenantController_switchActiveTenant_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwitchTenantRequestDto"}}}},"responses":{"200":{"description":""}},"tags":["Tenants"]}},"/api/v1/auth0/user/exists":{"post":{"operationId":"Auth0UserController_userExistsByEmail_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckUserAuth0RequestDto"}}}},"responses":{"200":{"description":"Check if user exists in Auth0","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckAuth0UserResponseDto"}}}}},"tags":["Users"]}},"/api/v1/users/me":{"put":{"operationId":"UpdateUserController_handle_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequestDto"}}}},"responses":{"2XX":{"description":"User profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileResponseDto"}}}}},"tags":["Users"]},"get":{"operationId":"GetUserProfileController_handle_v1","parameters":[],"responses":{"200":{"description":"User profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileResponseDto"}}}}},"tags":["Users"]}},"/api/v1/users":{"get":{"operationId":"GetAllUsersController_getUsers_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserDto"}}}}}},"summary":"Get all users","tags":["Users"]}},"/api/v1/users/me/profile-picture":{"post":{"operationId":"UserProfilePhotoController_handle_v1","parameters":[],"responses":{"200":{"description":""}},"tags":["users"]},"delete":{"operationId":"UserProfilePhotoController_delete_v1","parameters":[],"responses":{"204":{"description":""}},"tags":["users"]}},"/api/v1/users/sales-persons":{"get":{"operationId":"GetSalesUsersController_getSalesUsers_v1","parameters":[{"name":"search","required":false,"in":"query","description":"Filter users by name","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SalesPersonDto"}}}}}},"summary":"Get all sales users","tags":["Sales Users"]}},"/api/v1/payment-options":{"get":{"operationId":"GetAllPaymentOptionsController_handle_v1","parameters":[],"responses":{"2XX":{"description":"Return all payment options for the user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAllPaymentOptionsDtoResponse"}}}}},"tags":["payment-options"]}},"/api/v1/customers/{id}":{"put":{"operationId":"UpdateCustomerController_handle_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomerRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponseDto"}}}}},"summary":"Update a customer","tags":["Customers"]},"get":{"operationId":"GetCustomerController_get_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponseDto"}}}}},"summary":"Get customer","tags":["Customers"]},"delete":{"operationId":"DeleteCustomerController_handle_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"properties":{"message":{"type":"string"}}}}}}},"summary":"Delete a customer","tags":["Customers"]}},"/api/v1/customers":{"get":{"operationId":"GetAllCustomersController_handle_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PaginatedResponseDto"}}}}}},"summary":"Get all customers","tags":["Customers"]},"post":{"operationId":"CreateCustomerController_handle_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCustomerRequestDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCustomerResponseDto"}}}}},"summary":"Create a customer","tags":["Customers"]}},"/api/v1/customers/{id}/details":{"get":{"description":"Return the same customer information but with the sites associated","operationId":"GetCustomerDetailsController_handle_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerDetailsResponseDto"}}}}},"summary":"Get customer details","tags":["customers"]}},"/api/v1/admin/countries":{"get":{"description":"Returns all countries with their currency and VAT configuration. This is reference data used for filtering, not an administered entity.","operationId":"GetCountriesController_getCountries_v1","parameters":[],"responses":{"200":{"description":"List of all countries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CountryDto"}}}}}},"summary":"Get all countries","tags":["Admin - Countries"]}},"/api/v1/product":{"get":{"operationId":"ProductGetAllController_handle_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductGetAllResponse"}}}}},"summary":"List all products","tags":["Products"]}},"/api/v1/product/{id}":{"get":{"operationId":"GetProductController_get_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}},{"name":"relationships","required":false,"in":"query","description":"Comma-separated list of relationships to include (e.g., brochures)","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductDTO"}}}}},"summary":"Get product","tags":["Products"]}},"/api/v1/concepts-public":{"get":{"operationId":"GetConceptsController_getAll_v1","parameters":[{"name":"type","required":false,"in":"query","description":"Type of concept (pv or heat). Defaults to pv.","schema":{"enum":["pv","heat"],"type":"string"}}],"responses":{"200":{"description":"List of energy concepts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/"}}}}}},"summary":"Get public energy concepts/templates","tags":["Concepts"]}},"/api/v1/effective-price/de/check-simulation-data":{"post":{"operationId":"EffectivePriceController_checkSimulationDataDe_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}}},"summary":"Check simulation data for DE requests","tags":["EffectivePrice"]}},"/api/v1/effective-price/de":{"post":{"operationId":"EffectivePriceController_getEffectivePriceDe_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EffectivePriceRequestDeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EffectivePriceResponseDeDto"}}}},"404":{"description":"Scenario not found or post-processed scenario missing"}},"summary":"Calculate effective price for DE requests","tags":["EffectivePrice"]}},"/api/v1/crm/reject-offer/{crmOfferId}":{"patch":{"operationId":"RejectOfferController_handle_v1","parameters":[{"name":"crmOfferId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"Reject an offer, this endpoint will be called by the CRM whenever an quote is rejected on their side","tags":["CRM"]}},"/api/v1/crm/deals/{dealId}":{"get":{"operationId":"GetDealController_getDeal_v1","parameters":[{"name":"dealId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Deal retrieved successfully"}},"summary":"Get deal by ID (testing endpoint)","tags":["CRM"]}},"/api/v1/configs/{id}":{"get":{"operationId":"GetConfigController_get_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigDetailsResponseDto"}}}}},"summary":"Get config by ID","tags":["Configs"]}},"/api/v1/configs/{id}/send-offer":{"post":{"operationId":"SendOfferController_sendOffer_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"authorization","required":true,"in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendOfferRequestDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendOfferResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Send offer to GetAccept for a configuration","tags":["Configs"]}},"/api/v1/configs/{configId}/pdf":{"post":{"operationId":"PdfController_generatePdf_v1","parameters":[{"name":"configId","required":true,"in":"path","schema":{"type":"string"}},{"name":"authorization","required":true,"in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeneratePdfDto"}}}},"responses":{"200":{"description":"PDF generation initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PdfResponseDto"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"503":{"description":"PDF service unavailable"}},"security":[{"bearer":[]}],"summary":"Generate PDF for a configuration","tags":["PDF"]}},"/api/v1/admin/audit-logs":{"get":{"operationId":"GetAuditLogsController_getAuditLogs_v1","parameters":[{"name":"page","required":false,"in":"query","description":"Page number (1-based)","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of items per page","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"action","required":false,"in":"query","description":"Filter by action type","schema":{"example":"created","type":"string"}},{"name":"subjectType","required":false,"in":"query","description":"Filter by subject type","schema":{"example":"User","type":"string"}},{"name":"actorType","required":false,"in":"query","description":"Filter by actor type","schema":{"example":"User","type":"string"}},{"name":"traceId","required":false,"in":"query","description":"Filter by trace ID (exact match)","schema":{"example":"abc-trace-123","type":"string"}},{"name":"actorIdentifier","required":false,"in":"query","description":"Filter by actor identifier (exact match)","schema":{"example":"42","type":"string"}},{"name":"subjectIdentifier","required":false,"in":"query","description":"Filter by subject identifier (exact match)","schema":{"example":"123","type":"string"}},{"name":"startDate","required":false,"in":"query","description":"Filter by start date (ISO 8601 format)","schema":{"example":"2024-01-01T00:00:00.000Z","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"Filter by end date (ISO 8601 format)","schema":{"example":"2024-12-31T23:59:59.999Z","type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"$ref":"#/components/schemas/AuditLogSortField"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"$ref":"#/components/schemas/SortOrder"}}],"responses":{"200":{"description":"Paginated list of audit logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAuditLogsResponseDto"}}}}},"summary":"Get paginated audit logs with filtering and sorting","tags":["Admin - Audit Logs"]}},"/api/v1/admin/users":{"get":{"operationId":"GetAdminUsersController_getAdminUsers_v1","parameters":[{"name":"page","required":false,"in":"query","description":"Page number (1-based)","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of items per page","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search by name or email","schema":{"example":"john","type":"string"}},{"name":"tenantIds","required":false,"in":"query","description":"Filter by tenant IDs (comma-separated)","schema":{"example":"tenant-1,tenant-2","type":"array","items":{"type":"string"}}},{"name":"countryId","required":false,"in":"query","description":"Filter by country ID","schema":{"example":1,"type":"number"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"$ref":"#/components/schemas/AdminUserSortField"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"$ref":"#/components/schemas/SortOrder"}}],"responses":{"200":{"description":"Paginated list of team users","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAdminUsersResponseDto"}}}}},"summary":"Get paginated team users with filtering and sorting","tags":["Admin - Users"]},"post":{"operationId":"CreateAdminUserController_createAdminUser_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAdminUserDto"}}}},"responses":{"201":{"description":"User created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserDetailResponseDto"}}}},"409":{"description":"Email already exists"}},"summary":"Create a new team user","tags":["Admin - Users"]}},"/api/v1/admin/users/me":{"get":{"operationId":"GetCurrentAdminUserController_getCurrentAdminUser_v1","parameters":[],"responses":{"200":{"description":"Current admin user access level info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentAdminUserResponseDto"}}}}},"summary":"Get current admin user access level info","tags":["Admin - Users"]}},"/api/v1/admin/users/me/branches":{"get":{"description":"Returns branches based on access level: GLOBAL users get all branches, COUNTRY users get branches in their country, BRANCH users get their assigned branches.","operationId":"GetMyBranchesController_getMyBranches_v1","parameters":[],"responses":{"200":{"description":"List of accessible branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MyBranchesResponseDto"}}}}},"summary":"Get branches accessible to the current user","tags":["Admin - Users"]}},"/api/v1/admin/users/assignable-branches":{"get":{"description":"Returns branches that the current user can assign to other users. Used in user creation/edit forms for branch selection.","operationId":"GetAssignableBranchesController_getAssignableBranches_v1","parameters":[{"name":"countryId","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"List of branches in the specified country","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AdminBranchDto"}}}}}},"summary":"Get branches assignable to users for a given country","tags":["Admin - Users"]}},"/api/v1/admin/users/{id}":{"get":{"operationId":"GetAdminUserController_getAdminUser_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserDetailResponseDto"}}}},"404":{"description":"User not found"}},"summary":"Get a single team user by ID","tags":["Admin - Users"]},"patch":{"operationId":"UpdateAdminUserController_updateAdminUser_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAdminUserDto"}}}},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserDetailResponseDto"}}}},"404":{"description":"User not found"},"409":{"description":"Email already exists"}},"summary":"Update a team user","tags":["Admin - Users"]}},"/api/v1/admin/users/{id}/resend-invitation":{"post":{"description":"Sends a password setup email to the user. If the user does not exist in Auth0, they will be created first.","operationId":"ResendInvitationController_resendInvitation_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Invitation email sent successfully"},"400":{"description":"Auth0 not configured or failed to send email"},"404":{"description":"User not found"}},"summary":"Resend invitation email to a user","tags":["Admin - Users"]}},"/api/v1/admin/branches":{"get":{"operationId":"GetAdminBranchesController_getAdminBranches_v1","parameters":[{"name":"page","required":false,"in":"query","description":"Page number (1-based)","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of items per page","schema":{"minimum":1,"maximum":1000,"default":20,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search by branch name","schema":{"example":"Berlin","type":"string"}},{"name":"zohoIdSearch","required":false,"in":"query","description":"Search by Zoho ID","schema":{"example":"12345","type":"string"}},{"name":"countryId","required":false,"in":"query","description":"Filter by country ID","schema":{"example":1,"type":"number"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"$ref":"#/components/schemas/AdminBranchSortField"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"$ref":"#/components/schemas/SortOrder"}}],"responses":{"200":{"description":"Paginated list of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAdminBranchesResponseDto"}}}}},"summary":"Get paginated branches with filtering and sorting","tags":["Admin - Branches"]},"post":{"operationId":"CreateAdminBranchController_createAdminBranch_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAdminBranchDto"}}}},"responses":{"201":{"description":"Branch created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminBranchDto"}}}}},"summary":"Create a new branch","tags":["Admin - Branches"]}},"/api/v1/admin/branches/{id}":{"get":{"operationId":"GetAdminBranchController_getAdminBranch_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Branch found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminBranchDto"}}}},"404":{"description":"Branch not found"}},"summary":"Get a branch by ID","tags":["Admin - Branches"]},"patch":{"operationId":"UpdateAdminBranchController_updateAdminBranch_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAdminBranchDto"}}}},"responses":{"200":{"description":"Branch updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminBranchDto"}}}},"404":{"description":"Branch not found"}},"summary":"Update a branch","tags":["Admin - Branches"]}},"/api/v1/admin/concepts":{"get":{"operationId":"GetAdminConceptsController_getAdminConcepts_v1","parameters":[{"name":"page","required":false,"in":"query","description":"Page number (1-based)","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of items per page","schema":{"minimum":1,"maximum":1000,"default":20,"type":"number"}},{"name":"type","required":false,"in":"query","description":"Filter by template type","schema":{"$ref":"#/components/schemas/ConceptTemplateType"}},{"name":"scope","required":false,"in":"query","description":"Filter by scope (global = no tenant, branch = tenant-specific)","schema":{"$ref":"#/components/schemas/ConceptScope"}},{"name":"visibility","required":false,"in":"query","description":"Filter by visibility (visible or hidden)","schema":{"$ref":"#/components/schemas/ConceptVisibility"}},{"name":"tenantId","required":false,"in":"query","description":"Filter by branch/tenant ID","schema":{"example":"42","type":"string"}},{"name":"countryId","required":false,"in":"query","description":"Filter by country ID (for Global users)","schema":{"example":1,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search by concept name","schema":{"example":"Solar Basic","type":"string"}},{"name":"updatedFrom","required":false,"in":"query","description":"Filter concepts updated on or after this date (ISO 8601, e.g. 2025-01-01T00:00:00.000Z)","schema":{"example":"2025-01-01T00:00:00.000Z","type":"string"}},{"name":"updatedTo","required":false,"in":"query","description":"Filter concepts updated on or before this date (ISO 8601, e.g. 2025-12-31T23:59:59.999Z)","schema":{"example":"2025-12-31T23:59:59.999Z","type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"$ref":"#/components/schemas/ConceptSortField"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"$ref":"#/components/schemas/SortOrder"}}],"responses":{"200":{"description":"Paginated list of concepts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedConceptsResponseDto"}}}}},"summary":"Get paginated concepts with filtering and sorting","tags":["Admin - Concepts"]},"post":{"operationId":"CreateAdminConceptController_createAdminConcept_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAdminConceptDto"}}}},"responses":{"201":{"description":"Concept created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConceptListItemDto"}}}}},"summary":"Create a new concept","tags":["Admin - Concepts"]}},"/api/v1/admin/concepts/{id}":{"get":{"operationId":"GetAdminConceptController_getAdminConcept_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Concept found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConceptListItemDto"}}}},"404":{"description":"Concept not found"}},"summary":"Get a concept by ID","tags":["Admin - Concepts"]},"patch":{"operationId":"UpdateAdminConceptController_updateAdminConcept_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAdminConceptDto"}}}},"responses":{"200":{"description":"Concept updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConceptListItemDto"}}}},"404":{"description":"Concept not found"}},"summary":"Update a concept","tags":["Admin - Concepts"]}},"/api/v1/admin/products":{"get":{"description":"Returns all products (country-scoped based on user access level). Global admins can filter by country.","operationId":"GetAdminProductsController_getAdminProducts_v1","parameters":[{"name":"page","required":false,"in":"query","description":"Page number (1-based)","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of items per page","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search by product name","schema":{"example":"Solar Panel","type":"string"}},{"name":"categoryId","required":false,"in":"query","description":"Filter by category ID","schema":{"example":1,"type":"number"}},{"name":"brandId","required":false,"in":"query","description":"Filter by brand ID","schema":{"example":1,"type":"number"}},{"name":"countryId","required":false,"in":"query","description":"Filter by country ID (only for global admins)","schema":{"example":1,"type":"number"}},{"name":"public","required":false,"in":"query","description":"Filter by visibility (public)","schema":{"example":true,"type":"boolean"}},{"name":"canbesold","required":false,"in":"query","description":"Filter by can be sold status","schema":{"example":true,"type":"boolean"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"$ref":"#/components/schemas/AdminProductSortField"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"$ref":"#/components/schemas/SortOrder"}}],"responses":{"200":{"description":"Paginated list of products","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAdminProductsResponseDto"}}}}},"summary":"Get paginated global products list with filtering and sorting","tags":["Admin - Products"]},"post":{"operationId":"CreateAdminProductController_createAdminProduct_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAdminProductDto"}}}},"responses":{"201":{"description":"Product created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminProductDto"}}}}},"summary":"Create a new product","tags":["Admin - Products"]}},"/api/v1/admin/products/{id}":{"get":{"operationId":"GetAdminProductController_getProduct_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":"Product details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminProductDto"}}}}},"summary":"Get a single product by ID","tags":["Admin - Products"]},"patch":{"operationId":"UpdateAdminProductController_updateAdminProduct_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAdminProductDto"}}}},"responses":{"200":{"description":"Product updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminProductDto"}}}},"404":{"description":"Product not found"}},"summary":"Update a product","tags":["Admin - Products"]}},"/api/v1/admin/pricebook":{"get":{"description":"Returns products that are in the pricebook for the specified branch/tenant. User must have access to the branch.","operationId":"GetAdminPricebookController_getAdminPricebook_v1","parameters":[{"name":"tenantId","required":true,"in":"query","description":"Tenant/Branch ID to fetch pricebook for","schema":{"example":"tenant-uuid-123","type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number (1-based)","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of items per page","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search by product name","schema":{"example":"Solar Panel","type":"string"}},{"name":"categoryId","required":false,"in":"query","description":"Filter by category ID","schema":{"example":1,"type":"number"}},{"name":"brandId","required":false,"in":"query","description":"Filter by brand ID","schema":{"example":1,"type":"number"}},{"name":"public","required":false,"in":"query","description":"Filter by effective visibility (public)","schema":{"example":true,"type":"boolean"}},{"name":"canbesold","required":false,"in":"query","description":"Filter by effective can be sold status","schema":{"example":true,"type":"boolean"}},{"name":"hasOverride","required":false,"in":"query","description":"Filter by override status: true = only products with overrides, false = only products without overrides","schema":{"example":true,"type":"boolean"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"$ref":"#/components/schemas/AdminProductSortField"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"$ref":"#/components/schemas/SortOrder"}}],"responses":{"200":{"description":"Paginated list of pricebook products","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAdminPricebookResponseDto"}}}}},"summary":"Get paginated pricebook products for a specific branch","tags":["Admin - Products"]}},"/api/v1/admin/categories":{"get":{"operationId":"GetAdminCategoriesController_getCategories_v1","parameters":[],"responses":{"200":{"description":"List of categories","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CategoryDto"}}}}}},"summary":"List all product categories","tags":["Admin - Products"]}},"/api/v1/admin/brands":{"get":{"operationId":"GetAdminCategoriesController_getBrands_v1","parameters":[],"responses":{"200":{"description":"List of brands","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BrandDto"}}}}}},"summary":"List all product brands","tags":["Admin - Products"]}},"/api/v1/admin/roles":{"get":{"description":"Returns roles filtered based on the current user's permissions. Super admins can assign all roles, while other users have restricted role assignment capabilities.","operationId":"GetAssignableRolesController_getAssignableRoles_v1","parameters":[],"responses":{"200":{"description":"List of assignable roles with metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignableRolesResponseDto"}}}}},"summary":"Get list of roles the current user can assign","tags":["Admin - Roles"]}},"/api/v1/admin/maintenance/backfill-config-hashes":{"post":{"description":"Idempotent one-shot maintenance task. Queues a worker job that iterates over configs without a hash lookup row and inserts one using the runtime HashService. Progress and results are logged by the worker. Restricted to Superadmin.","operationId":"BackfillConfigHashesController_backfillConfigHashes_v1","parameters":[{"name":"batchSize","required":false,"in":"query","description":"Number of configs to process per batch","schema":{"minimum":1,"maximum":5000,"default":1000,"type":"number"}}],"responses":{"200":{"description":"Backfill queued for worker processing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackfillConfigHashesResponseDto"}}}}},"summary":"Backfill missing rows in config_hash_lookup","tags":["Admin - Maintenance"]}},"/api/v1/admin/megasearch":{"get":{"operationId":"MegasearchController_search_v1","parameters":[{"name":"q","required":true,"in":"query","description":"Search query string","schema":{"minLength":2,"example":"john","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Maximum number of results per entity type","schema":{"minimum":1,"maximum":20,"default":5,"type":"number"}}],"responses":{"200":{"description":"Grouped search results by entity type","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MegasearchResponseDto"}}}}},"summary":"Search across multiple entities (users, branches) based on user permissions","tags":["Admin - Megasearch"]}},"/api/migration-frozen-state/configs/{configId}/migrate-all":{"post":{"description":"Triggers all migration services for the given configId. If force is true, cleans up existing migration data before running.","operationId":"ConfigMigrationOrchestratorController_migrateAll","parameters":[{"name":"configId","required":true,"in":"path","schema":{"type":"number"}},{"name":"force","required":false,"in":"query","description":"If true, re-runs all steps even if already migrated.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigMigrationOrchestratorResponseDto"}}}}},"summary":"Run all migration steps for a configuration","tags":["migration-frozen-state"]}},"/api/v1/migration-frozen-state/configs/{configId}/config-products":{"post":{"description":"Extracts category_id, category_name, brand_id, and brand_name from frozen_state JSON and updates config_products table. Tracks migration status in MigrationFrozenStateConfig. Returns early if migration was already completed successfully (unless force=true).","operationId":"ConfigProductsMigrationController_migrateConfigProducts_v1","parameters":[{"name":"configId","required":true,"in":"path","schema":{"type":"number"}},{"name":"force","required":false,"in":"query","description":"If true, re-runs the migration even if it was already completed successfully. Defaults to false.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Migration completed successfully or already completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigProductsMigrationResponseDto"}}}},"400":{"description":"Invalid configId (not an integer) or failed to parse frozen_state"},"404":{"description":"Config not found"},"500":{"description":"Internal server error during migration"}},"summary":"Migrate config products from frozen_state","tags":["Migrations"]}},"/api/v1/migration-frozen-state/configs/{configId}/config-documents":{"post":{"description":"Extracts file entries from frozen_state JSON (from $.site.files[] and $.gewinnprognose.files[]) and inserts rows into config_documents table. Tracks migration status in MigrationFrozenStateConfig. Returns early if migration was already completed successfully (unless force=true).","operationId":"ConfigDocumentsMigrationController_migrateConfigDocuments_v1","parameters":[{"name":"configId","required":true,"in":"path","schema":{"type":"number"}},{"name":"force","required":false,"in":"query","description":"If true, re-runs the migration even if it was already completed successfully. Defaults to false.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Migration completed successfully or already completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigDocumentsMigrationResponseDto"}}}},"400":{"description":"Invalid configId (not an integer) or failed to parse frozen_state"},"404":{"description":"Config not found"},"500":{"description":"Internal server error during migration"}},"summary":"Migrate config documents from frozen_state","tags":["Migrations"]}},"/api/v1/migration-frozen-state/configs/{configId}/config-table":{"post":{"description":"Extracts roofSize and specificYieldBasedOnRoofAlignment from frozen_state JSON, and populates paymentOptionName, tenantName, countryName, and countryCurrency from related tables. Tracks migration status in MigrationFrozenStateConfig. Returns early if migration was already completed successfully (unless force=true).","operationId":"ConfigTableMigrationController_migrateConfigTable_v1","parameters":[{"name":"configId","required":true,"in":"path","schema":{"type":"number"}},{"name":"force","required":false,"in":"query","description":"If true, re-runs the migration even if it was already completed successfully. Defaults to false.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Migration completed successfully or already completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigTableMigrationResponseDto"}}}},"400":{"description":"Invalid configId (not an integer) or failed to parse frozen_state"},"404":{"description":"Config not found"},"500":{"description":"Internal server error during migration"}},"summary":"Migrate config table columns from frozen_state","tags":["Migrations"]}},"/api/v1/migration-frozen-state/configs/{configId}/config-customer":{"post":{"description":"Extracts customer address data from frozen_state.site.address JSON and populates/updates the config_customer table. Tracks migration status in MigrationFrozenStateConfig. Returns early if migration was already completed successfully (unless force=true).","operationId":"ConfigCustomerMigrationController_migrateConfigCustomer_v1","parameters":[{"name":"configId","required":true,"in":"path","schema":{"type":"number"}},{"name":"force","required":false,"in":"query","description":"If true, re-runs the migration even if it was already completed successfully. Defaults to false.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Migration completed successfully or already completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigCustomerMigrationResponseDto"}}}},"400":{"description":"Invalid configId (not an integer) or failed to parse frozen_state"},"404":{"description":"Config not found"},"500":{"description":"Internal server error during migration"}},"summary":"Migrate config_customer table from frozen_state","tags":["Migrations"]}},"/api/v1/migration-frozen-state/configs/{configId}/config-consumption-table":{"post":{"description":"Extracts consumption values (heat, mobility, household, fossil consumption) from effective_price_data JSON and populates the config_consumption table. Tracks migration status in MigrationFrozenStateConfig.configConsumptionsTable. Returns early if migration was already completed successfully (unless force=true).","operationId":"ConfigConsumptionMigrationController_migrateConfigConsumption_v1","parameters":[{"name":"configId","required":true,"in":"path","schema":{"type":"number"}},{"name":"force","required":false,"in":"query","description":"If true, re-runs the migration even if it was already completed successfully. Defaults to false.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Migration completed successfully or already completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigConsumptionMigrationResponseDto"}}}},"400":{"description":"Invalid configId (not an integer) or failed to parse effective_price_data"},"404":{"description":"Config not found"},"500":{"description":"Internal server error during migration"}},"summary":"Migrate config_consumption table from effective_price_data","tags":["Migrations"]}},"/api/v1/migration-frozen-state/configs/{configId}/config-margins":{"post":{"description":"Extracts margin data (total, pv, heat) from frozen_state JSON at $.margins and populates the config_margins table. Tracks migration status in MigrationFrozenStateConfig. Returns early if migration was already completed successfully (unless force=true).","operationId":"ConfigMarginsMigrationController_migrateConfigMargins_v1","parameters":[{"name":"configId","required":true,"in":"path","schema":{"type":"number"}},{"name":"force","required":false,"in":"query","description":"If true, re-runs the migration even if it was already completed successfully. Defaults to false.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Migration completed successfully or already completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigMarginsMigrationResponseDto"}}}},"400":{"description":"Invalid configId (not an integer) or failed to parse frozen_state"},"404":{"description":"Config not found"},"500":{"description":"Internal server error during migration"}},"summary":"Migrate config margins from frozen_state","tags":["Migrations"]}},"/api/v1/migration-frozen-state/configs/{configId}/config-calculation-legacy-table":{"post":{"description":"Extracts calculation values (consumption, roof direction, specific yield, spot price, self-sufficiency) from frozen_state.gewinnprognose JSON and populates the config_calculation_legacy table. Tracks migration status in MigrationFrozenStateConfig.configCalculationLegacyTable. Returns early if migration was already completed successfully (unless force=true).","operationId":"ConfigCalculationLegacyMigrationController_migrateConfigCalculationLegacy_v1","parameters":[{"name":"configId","required":true,"in":"path","schema":{"type":"number"}},{"name":"force","required":false,"in":"query","description":"If true, re-runs the migration even if it was already completed successfully. Defaults to false.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Migration completed successfully or already completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigCalculationLegacyMigrationResponseDto"}}}},"400":{"description":"Invalid configId (not an integer) or failed to parse frozen_state"},"404":{"description":"Config not found"},"500":{"description":"Internal server error during migration"}},"summary":"Migrate config_calculation_legacy table from frozen_state","tags":["Migrations"]}},"/api/v1/migration-frozen-state/configs/{configId}/config-calculation-table":{"post":{"description":"Populates the config_calculation table using a fallback pattern: Frozen State (effective_price_data) -> Database Columns -> Calculated/Default Values. Tracks migration status in MigrationFrozenStateConfig.configCalculationTable. Returns early if migration was already completed successfully (unless force=true).","operationId":"ConfigCalculationMigrationController_migrateConfigCalculation_v1","parameters":[{"name":"configId","required":true,"in":"path","schema":{"type":"number"}},{"name":"force","required":false,"in":"query","description":"If true, re-runs the migration even if it was already completed successfully. Defaults to false.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Migration completed successfully or already completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigCalculationMigrationResponseDto"}}}},"400":{"description":"Invalid configId (not an integer) or failed to parse data"},"404":{"description":"Config not found"},"500":{"description":"Internal server error during migration"}},"summary":"Migrate config_calculation table from various sources","tags":["Migrations"]}},"/api/v1/migration-frozen-state/configs/{configId}/config-metrics":{"post":{"description":"Extracts CO2 savings, PV power, storage capacity, and other metrics from frozen_state JSON (gewinnprognose, panels, batteries) and effective_price_data JSON. Populates config_metrics child table. Tracks migration status in MigrationFrozenStateConfig. Returns early if migration was already completed successfully (unless force=true).","operationId":"ConfigMetricsMigrationController_migrateConfigMetrics_v1","parameters":[{"name":"configId","required":true,"in":"path","schema":{"type":"number"}},{"name":"force","required":false,"in":"query","description":"If true, re-runs the migration even if it was already completed successfully. Defaults to false.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Migration completed successfully or already completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigMetricsMigrationResponseDto"}}}},"400":{"description":"Invalid configId (not an integer) or failed to parse frozen_state"},"404":{"description":"Config not found"},"500":{"description":"Internal server error during migration"}},"summary":"Migrate config_metrics table from frozen_state and effective_price_data","tags":["Migrations"]}},"/api/v1/migration-frozen-state/configs/{configId}/config-self-sufficiency":{"post":{"description":"Extracts scenario self-sufficiency (autarky) values from frozen_state.gewinnprognose.scenarios and populates the config_self_sufficiency table. Maps scenario keys (no, pv, pv_bat, hb, dp) to type values (unoptimized, pv, pv_optimized, heartbeat, dynamic_pulse). Tracks migration status in MigrationFrozenStateConfig.configSelfSufficiencyTable. Returns early if migration was already completed successfully (unless force=true).","operationId":"ConfigSelfSufficiencyMigrationController_migrateConfigSelfSufficiency_v1","parameters":[{"name":"configId","required":true,"in":"path","schema":{"type":"number"}},{"name":"force","required":false,"in":"query","description":"If true, re-runs the migration even if it was already completed successfully. Defaults to false.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Migration completed successfully or already completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigSelfSufficiencyMigrationResponseDto"}}}},"400":{"description":"Invalid configId (not an integer) or failed to parse frozen_state"},"404":{"description":"Config not found"},"500":{"description":"Internal server error during migration"}},"summary":"Migrate config_self_sufficiency table from frozen_state","tags":["Migrations"]}},"/api/v1/migration-frozen-state/configs/{configId}/config-market-components":{"post":{"description":"Extracts market component data from frozen_state JSON at $.angebot, $.angebot_combined, $.angebot_hp, or $.angebot_charger (first with data) and populates the config_market_components table. Tracks migration status in MigrationFrozenStateConfig. Returns early if migration was already completed successfully (unless force=true).","operationId":"ConfigMarketComponentsMigrationController_migrateConfigMarketComponents_v1","parameters":[{"name":"configId","required":true,"in":"path","schema":{"type":"number"}},{"name":"force","required":false,"in":"query","description":"If true, re-runs the migration even if it was already completed successfully. Defaults to false.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Migration completed successfully or already completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigMarketComponentsMigrationResponseDto"}}}},"400":{"description":"Invalid configId (not an integer) or failed to parse frozen_state"},"404":{"description":"Config not found"},"500":{"description":"Internal server error during migration"}},"summary":"Migrate config market components from frozen_state","tags":["Migrations"]}},"/api/v1/migration-frozen-state/configs/{configId}/config-effective-prices":{"post":{"description":"Computes effective price data from frozen_state.gewinnprognose (profit forecast scenarios) and populates the config_effective_price table with up to 11 rows per config (unoptimized, pv, dynamic_tariff x categories). Tracks migration status in MigrationFrozenStateConfig. Returns early if migration was already completed successfully (unless force=true).","operationId":"ConfigEffectivePricesMigrationController_migrateConfigEffectivePrices_v1","parameters":[{"name":"configId","required":true,"in":"path","schema":{"type":"number"}},{"name":"force","required":false,"in":"query","description":"If true, re-runs the migration even if it was already completed successfully. Defaults to false.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Migration completed successfully or already completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigEffectivePricesMigrationResponseDto"}}}},"400":{"description":"Invalid configId (not an integer) or failed to parse frozen_state"},"404":{"description":"Config not found"},"500":{"description":"Internal server error during migration"}},"summary":"Migrate config effective prices from frozen_state","tags":["Migrations"]}},"/api/v1/test/pubsub":{"post":{"operationId":"TestPubsubController_publishTestPing_v1","parameters":[],"responses":{"202":{"description":"Event published to message bus"}},"summary":"Publish a test.ping event to the message bus for E2E PubSub verification","tags":["Test"]}},"/api/v1/configs/{id}/lookup-energy-service-data":{"post":{"operationId":"RefreshConfigEnergySiteInfoController_refresh_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"properties":{"success":{"type":"boolean"}}}}}}},"summary":"Refresh a config's energy site info (grid/metering fees) from ESI.","tags":["Configs"]}},"/api/v1/sites/{id}/lookup-energy-service-data":{"post":{"operationId":"QueueSiteEnergySiteInfoRefreshController_queue_v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"202":{"description":"","content":{"application/json":{"schema":{"properties":{"queued":{"type":"boolean"}}}}}}},"summary":"Queue energy site info refresh for all configs on a site.","tags":["Sites"]}}},"info":{"title":"Offer Tool API","description":"Api definitions for Offer Tool","version":"1.0","contact":{}},"tags":[],"servers":[],"components":{"schemas":{"HealthResponse":{"type":"object","properties":{}},"CreateCustomerSiteRequestDto":{"type":"object","properties":{}},"SwitchTenantRequestDto":{"type":"object","properties":{"tenantId":{"type":"string","description":"ID of the tenant to switch to"}},"required":["tenantId"]},"CheckUserAuth0RequestDto":{"type":"object","properties":{"email":{"type":"string","example":"foo@bar.com"}},"required":["email"]},"CheckAuth0UserResponseDto":{"type":"object","properties":{"id":{"type":"number","description":"The unique identifier of the user","example":1},"email":{"type":"string","description":"The email address of the user","example":"foo@bar.com"}},"required":["id","email"]},"UpdateUserRequestDto":{"type":"object","properties":{"name":{"type":"string","description":"The name that will be updated"},"calendarUrl":{"type":"string","description":"Optional calendar URL to book appointments"}},"required":["name"]},"Currency":{"type":"string","enum":["EUR","DKK","SEK"]},"CountryCode":{"type":"string","enum":["DE","DK","SE","NL"]},"Locale":{"type":"string","enum":["de-DE","da-DK","en-US","sv-SE","nl-NL"]},"CountryDto":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string","description":"Country name"},"countryCode":{"allOf":[{"$ref":"#/components/schemas/CountryCode"}]},"locale":{"allOf":[{"$ref":"#/components/schemas/Locale"}]},"currency":{"allOf":[{"$ref":"#/components/schemas/Currency"}]},"vatRate":{"type":"number","description":"Default VAT rate as percentage"}},"required":["id","name","countryCode","locale","currency","vatRate"]},"TenantDto":{"type":"object","properties":{"name":{"type":"string"},"id":{"type":"string"},"country":{"$ref":"#/components/schemas/CountryDto"},"isEnabledHeatpump":{"type":"boolean"}},"required":["name","id","country"]},"AccessLevel":{"type":"string","enum":["global","country","branch"]},"UserProfileResponseDto":{"type":"object","properties":{"id":{"type":"number","description":"The unique identifier of the user"},"name":{"type":"string","description":"The name of the user"},"email":{"type":"string","description":"The email address of the user"},"phone":{"type":"object","description":"The phone number of the user","nullable":true},"currency":{"description":"The currency used by the user","allOf":[{"$ref":"#/components/schemas/Currency"}]},"country":{"description":"The country details of the user","nullable":true,"allOf":[{"$ref":"#/components/schemas/CountryDto"}]},"profilePhotoUrl":{"type":"object","description":"The profile photo URL of the user","nullable":true},"calendarUrl":{"type":"object","description":"The URL to book an appointment with the user","nullable":true},"permissions":{"description":"The permissions assigned to the user","items":{"type":"array"},"type":"array"},"roles":{"description":"The roles assigned to the user","nullable":true,"type":"array","items":{"type":"string"}},"abilities":{"description":"The computed abilities (subject/action pairs) for the user","items":{"type":"array"},"type":"array"},"tenant":{"description":"The tenant details of the user","nullable":true,"allOf":[{"$ref":"#/components/schemas/TenantDto"}]},"accessLevel":{"description":"The access level of the user (global, country, or branch)","example":"branch","allOf":[{"$ref":"#/components/schemas/AccessLevel"}]}},"required":["id","name","email","currency","permissions","abilities","accessLevel"]},"UserDto":{"type":"object","properties":{"id":{"type":"number"},"tenantId":{"type":"string","nullable":true},"countryId":{"type":"number","nullable":true},"name":{"type":"string"},"email":{"type":"string"},"currentTeamId":{"type":"number","nullable":true},"profilePhotoPath":{"type":"string","nullable":true},"calendarUrl":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"isTeam":{"type":"boolean","nullable":true},"isTemplateUser":{"type":"boolean","nullable":true},"zohoId":{"type":"string","nullable":true},"zohoUserId":{"type":"string","nullable":true},"tenantIdHeat":{"type":"string","nullable":true},"activeTenantId":{"type":"string","nullable":true}},"required":["id","tenantId","countryId","name","email","currentTeamId","profilePhotoPath","calendarUrl","phone","isTeam","isTemplateUser","zohoId","zohoUserId","tenantIdHeat","activeTenantId"]},"SalesPersonDto":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true}},"required":["id","name","email"]},"GetAllPaymentOptionsDtoResponse":{"type":"object","properties":{"id":{"type":"string","description":"The id of the payment option"},"name":{"type":"string","description":"The name of the payment option"}},"required":["id","name"]},"AddressDto":{"type":"object","properties":{"address":{"type":"string","nullable":true},"zipcode":{"type":"string","nullable":false},"city":{"type":"string","nullable":true}},"required":["zipcode"]},"UpdateCustomerRequestDto":{"type":"object","properties":{"salesContact":{"type":"number","description":"Sales contact id","nullable":true},"phone":{"type":"string","nullable":true},"email":{"type":"string","nullable":false},"firstName":{"type":"string","nullable":false},"lastName":{"type":"string","nullable":false},"company":{"type":"string","nullable":true},"salutation":{"type":"string","nullable":true},"zohoId":{"type":"string","nullable":true},"dateOfBirth":{"type":"string","format":"date","nullable":true},"address":{"nullable":false,"allOf":[{"$ref":"#/components/schemas/AddressDto"}]}},"required":["email","firstName","lastName","address"]},"CustomerResponseDto":{"type":"object","properties":{"id":{"type":"number"},"tenantId":{"type":"string","nullable":true},"countryId":{"type":"number","nullable":true},"name":{"type":"string"},"email":{"type":"string"},"source":{"type":"string","nullable":true},"currentTeamId":{"type":"number","nullable":true},"profilePhotoPath":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"dateOfBirth":{"type":"string","format":"date","nullable":true},"isTeam":{"type":"boolean"},"isTemplateUser":{"type":"boolean","nullable":true},"zohoId":{"type":"string","nullable":true},"zohoLink":{"type":"string","nullable":true},"zohoUserId":{"type":"string","nullable":true},"tenantIdHeat":{"type":"string","nullable":true},"activeTenantId":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"firstName":{"type":"string","nullable":true}},"required":["id","tenantId","countryId","name","email","currentTeamId","profilePhotoPath","phone","isTeam","isTemplateUser","zohoId","zohoUserId","tenantIdHeat","activeTenantId","lastName","firstName"]},"Metadata":{"type":"object","properties":{}},"Links":{"type":"object","properties":{}},"PaginatedResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"type":"array"}},"meta":{"$ref":"#/components/schemas/Metadata"},"links":{"$ref":"#/components/schemas/Links"}},"required":["data","meta","links"]},"SalesContactCustomerDto":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"email":{"type":"string"}},"required":["id","name","email"]},"BasketOption":{"type":"object","properties":{}},"Basket":{"type":"object","properties":{"options":{"description":"All the options that can be selected for the site's basket","type":"array","items":{"$ref":"#/components/schemas/BasketOption"}},"selectedOptions":{"description":"Selected options related with the site","type":"array","items":{"type":"number"}}},"required":["options","selectedOptions"]},"SiteImageMeta":{"type":"object","properties":{"createdAt":{"type":"object","description":"Creation timestamp"},"updatedAt":{"type":"object","description":"Last update timestamp"},"name":{"type":"string","description":"Image name"},"fileName":{"type":"string","description":"Image file name"}},"required":["createdAt","updatedAt","name","fileName"]},"SiteImage":{"type":"object","properties":{"id":{"type":"number","description":"Unique identifier"},"uuid":{"type":"object","description":"Universally unique identifier"},"src":{"type":"string","description":"Image URL"},"meta":{"description":"Image metadata","allOf":[{"$ref":"#/components/schemas/SiteImageMeta"}]}},"required":["id","uuid","src","meta"]},"SiteResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Site ID - hashed","nullable":false},"hashId":{"type":"string","description":"HashId","nullable":false},"maxPanels":{"type":"object","description":"Maximum number of panels","nullable":true},"powerConsumptionYear":{"type":"object","description":"Annual power consumption","nullable":true},"ownersCount":{"type":"number","description":"Number of owners"},"address":{"type":"object","description":"Site address","nullable":true},"zohoId":{"type":"object","description":"Zoho IDs and CRM deal stages","properties":{"pv":{"type":"string","nullable":true,"description":"PV Zoho ID"},"pvLink":{"type":"string","nullable":true,"description":"PV Zoho Link"},"pvDealStage":{"type":"string","nullable":true,"description":"PV deal stage key from CRM sync"},"pvNewOffersAllowed":{"type":"boolean","description":"Whether the PV deal can receive new offers"},"hp":{"type":"string","nullable":true,"description":"HP Zoho ID"},"hpLink":{"type":"string","nullable":true,"description":"HP Zoho Link"},"hpDealStage":{"type":"string","nullable":true,"description":"Heat deal stage key from CRM sync"},"hpNewOffersAllowed":{"type":"boolean","description":"Whether the heat deal can receive new offers"}}},"basket":{"description":"Site basket","allOf":[{"$ref":"#/components/schemas/Basket"}]},"images":{"description":"Site images","type":"array","items":{"$ref":"#/components/schemas/SiteImage"}}},"required":["id","hashId","maxPanels","powerConsumptionYear","ownersCount","address","zohoId","basket","images"]},"CustomerFullSchemaDto":{"type":"object","properties":{"id":{"type":"number"},"tenantId":{"type":"string","nullable":true},"countryId":{"type":"number","nullable":true},"name":{"type":"string"},"email":{"type":"string"},"source":{"type":"string","nullable":true},"currentTeamId":{"type":"number","nullable":true},"profilePhotoPath":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"dateOfBirth":{"type":"string","format":"date","nullable":true},"isTeam":{"type":"boolean"},"isTemplateUser":{"type":"boolean","nullable":true},"zohoId":{"type":"string","nullable":true},"zohoLink":{"type":"string","nullable":true},"zohoUserId":{"type":"string","nullable":true},"tenantIdHeat":{"type":"string","nullable":true},"activeTenantId":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"firstName":{"type":"string","nullable":true},"company":{"type":"string","nullable":true},"salutation":{"type":"string","nullable":true},"tenant":{"$ref":"#/components/schemas/TenantDto"},"address":{"$ref":"#/components/schemas/AddressDto"},"country":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/CountryDto"}]},"salesContact":{"nullable":true,"description":"Person responsible for the customer","allOf":[{"$ref":"#/components/schemas/SalesContactCustomerDto"}]},"sites":{"nullable":true,"description":"Shows the sites associated with the customer","type":"array","items":{"$ref":"#/components/schemas/SiteResponseDto"}}},"required":["id","tenantId","countryId","name","email","currentTeamId","profilePhotoPath","phone","isTeam","isTemplateUser","zohoId","zohoUserId","tenantIdHeat","activeTenantId","lastName","firstName","tenant"]},"CustomerDetailsResponseDto":{"type":"object","properties":{"customer":{"description":"Customer information","allOf":[{"$ref":"#/components/schemas/CustomerFullSchemaDto"}]},"sites":{"description":"Sites associated with the customer","type":"array","items":{"$ref":"#/components/schemas/SiteResponseDto"}},"files":{"type":"object","properties":{"client":{"type":"array","items":{"type":"string"},"description":"Client files"},"roofplan":{"type":"array","items":{"type":"string"},"description":"Roofplan files"},"documentation":{"type":"array","items":{"type":"string"},"description":"Documentation files"},"qm":{"type":"array","items":{"type":"string"},"description":"QM files"}},"nullable":true,"description":"Files associated with the customer"}},"required":["customer","sites"]},"CustomerCreateInputDto":{"type":"object","properties":{"salesContact":{"type":"number","description":"Sales contact id","nullable":true},"phone":{"type":"string","nullable":true},"email":{"type":"string","nullable":false},"firstName":{"type":"string","nullable":false},"lastName":{"type":"string","nullable":false},"company":{"type":"string","nullable":true},"salutation":{"type":"string","nullable":true},"password":{"type":"string","description":"Customer password. If not provided, a secure UUID-based password will be auto-generated.","nullable":true},"zohoId":{"type":"string","nullable":true},"dateOfBirth":{"type":"string","format":"date","nullable":true},"address":{"nullable":false,"allOf":[{"$ref":"#/components/schemas/AddressDto"}]}},"required":["email","firstName","lastName","address"]},"SiteFormFieldsDto":{"type":"object","properties":{"address":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/AddressDto"}]},"basket":{"description":"The IDs of available field_options","nullable":true,"type":"array","items":{"type":"array"}},"maxPanels":{"type":"number"},"powerConsumptionYear":{"type":"number"},"buildingHeatingLoad":{"type":"number","nullable":true},"salesContactId":{"type":"number","description":"Sales contact id","nullable":true},"ownersCount":{"type":"number","nullable":true},"zohoId":{"type":"object","properties":{"pv":{"type":"string","nullable":true},"heat":{"type":"string","nullable":true}}}},"required":["maxPanels","powerConsumptionYear"]},"CreateCustomerRequestDto":{"type":"object","properties":{"customer":{"$ref":"#/components/schemas/CustomerCreateInputDto"},"site":{"$ref":"#/components/schemas/SiteFormFieldsDto"},"country":{"type":"string","enum":["DE","DK","SE"]}},"required":["customer","site","country"]},"CreateCustomerResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Indicates if the customer was successfully created"},"customerId":{"type":"number","description":"The ID of the newly created customer"}},"required":["success","customerId"]},"ProductGetAllResponse":{"type":"object","properties":{"products":{"description":"List of products","items":{"type":"array"},"type":"array"},"categories":{"description":"List of categories associated with the products","items":{"type":"array"},"type":"array"}},"required":["products","categories"]},"CategoryDTO":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"}},"required":["id","name"]},"BrandDTO":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"}},"required":["id","name"]},"PriceDTO":{"type":"object","properties":{"relative":{"type":"number"}},"required":["relative"]},"MediaDTO":{"type":"object","properties":{"id":{"type":"number","nullable":true},"normal":{"type":"string","nullable":true},"thumb":{"type":"string","nullable":true},"url":{"type":"string"}},"required":["url"]},"ProductDTO":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"category":{"$ref":"#/components/schemas/CategoryDTO"},"brand":{"$ref":"#/components/schemas/BrandDTO"},"featured":{"type":"boolean"},"description":{"type":"string","nullable":true},"shortDescription":{"type":"string","nullable":true},"attributes":{"type":"object"},"customPrice":{"type":"number","nullable":true},"image":{"type":"string"},"prices":{"$ref":"#/components/schemas/PriceDTO"},"count":{"type":"number"},"brochures":{"type":"array","items":{"$ref":"#/components/schemas/MediaDTO"}},"canEditCustomPrice":{"type":"boolean"},"canEditCustomInvoiceLine":{"type":"boolean"},"canEditOffer":{"type":"boolean"}},"required":["id","name","category","brand","featured","description","shortDescription","attributes","customPrice","image","prices","count","brochures","canEditCustomPrice","canEditCustomInvoiceLine","canEditOffer"]},"EffectivePriceHouseholdConsumptionRequestDto":{"type":"object","properties":{"amountKwhPerYear":{"type":"number","description":"Annual household consumption in kWh per year"}},"required":["amountKwhPerYear"]},"EffectivePriceHeatConsumptionRequestDto":{"type":"object","properties":{"amountKwhPerYear":{"type":"number","description":"Amount of kWh consumed for heating per year"}}},"EffectivePriceMobilityConsumptionRequestDto":{"type":"object","properties":{"amountKmPerYear":{"type":"number","description":"Amount driven in km per year"},"kwhPer100km":{"type":"number","description":"Consumption kwh per 100 km"},"amountKwhPerYear":{"type":"number","description":"Total amount of kWh consumed for mobility per year"}}},"EffectivePriceConsumptionRequestDto":{"type":"object","properties":{"household":{"description":"Household consumption details","allOf":[{"$ref":"#/components/schemas/EffectivePriceHouseholdConsumptionRequestDto"}]},"heat":{"description":"Heat consumption details","allOf":[{"$ref":"#/components/schemas/EffectivePriceHeatConsumptionRequestDto"}]},"mobility":{"description":"Mobility consumption details","allOf":[{"$ref":"#/components/schemas/EffectivePriceMobilityConsumptionRequestDto"}]}},"required":["household"]},"EffectivePriceFossilHeatRequestDto":{"type":"object","properties":{"amountKwhPerYear":{"type":"number","description":"Amount of kWh consumed for fossil heating per year"},"priceMinorCurrencyUnitPerKwh":{"type":"number","description":"Price per kWh for fossil heating in minor currency unit"},"additionalCosts":{"type":"number","description":"Additional costs for fossil heating"},"priceTotalMajorCurrencyUnitPerYear":{"type":"number","description":"Total price for fossil heating per year in major currency unit"}}},"EffectivePriceFossilMobilityRequestDto":{"type":"object","properties":{"amountKmPerYear":{"type":"number","description":"Amount driven in km per year (fossil)"},"literPer100km":{"type":"number","description":"Liters per 100km (fossil)"},"priceMinorCurrencyUnitPerLiter":{"type":"number","description":"Price per liter in minor currency unit (fossil)"},"amountLiterPerYear":{"type":"number","description":"Total liters per year (fossil)"},"priceTotalMajorCurrencyUnitPerYear":{"type":"number","description":"Total price for fossil mobility per year in major currency unit"}}},"EffectivePriceFossilConsumptionRequestDto":{"type":"object","properties":{"heat":{"description":"Fossil heat consumption details","allOf":[{"$ref":"#/components/schemas/EffectivePriceFossilHeatRequestDto"}]},"mobility":{"description":"Fossil mobility consumption details","allOf":[{"$ref":"#/components/schemas/EffectivePriceFossilMobilityRequestDto"}]}}},"EffectivePriceRequestDeDto":{"type":"object","properties":{"consumption":{"description":"Consumption related values","allOf":[{"$ref":"#/components/schemas/EffectivePriceConsumptionRequestDto"}]},"fossilConsumption":{"description":"Fossil consumption related values","allOf":[{"$ref":"#/components/schemas/EffectivePriceFossilConsumptionRequestDto"}]},"systemInstallationDate":{"type":"string","description":"PV system installation date (ISO 8601)"},"configurationCreatedAt":{"type":"string","description":"Date a configuration was created at"},"pvProductionKwhPerYear":{"type":"number","description":"Annual photovoltaic production in kWh per year"},"pvPeakPowerKwp":{"type":"number","description":"Installed PV peak power in kWp"},"batteryCapacityKwh":{"type":"number","description":"Battery capacity in kWh"},"hasTimeVariableGridFees":{"type":"boolean","description":"Has time variable grid fees"},"hasDynamicPulse":{"type":"boolean","description":"Has dynamic pulse"},"fixedTariffGridCostsMinorCurrencyUnitPerKwh":{"type":"number","description":"Grid costs in minor currency unit per kWh"},"feedInMinorCurrencyUnitPerKwh":{"type":"number","description":"Feed-in tariff in minor currency unit per kWh (legacy)"},"pvProductionPriceMajorCurrencyUnitPerYear":{"type":"number","description":"Pv production price in major currency unit per year"},"fixedGridFeesLeviesAndTaxesCtPerKwh":{"type":"number","description":"Fixed grid fees levies and taxes incl. VAT ct per kWh"},"isEligibleForParagraph14aSavings":{"type":"boolean","description":"Is eligible for paragraph 14a savings"},"gridUsageWorkingPriceMinorCurrencyUnitPerKwh":{"type":"number","description":"Grid usage working price in minor currency unit per kWh"},"directMarketingEnabled":{"type":"boolean","description":"When true, feed-in uses EEG-style remuneration (no Solarspitzen scaling) plus direct-marketing bonus ct/kWh"}},"required":["consumption"]},"Paragraph14aSavingsResponseDto":{"type":"object","properties":{"module1":{"type":"number","description":"Module 1 savings"},"module3":{"type":"number","description":"Module 3 savings"},"priceMinorCurrencyUnitPerKwh":{"type":"number","description":"Total savings per kwh in minor currency unit"}},"required":["module1","module3","priceMinorCurrencyUnitPerKwh"]},"DirectMarketingBreakdownDto":{"type":"object","properties":{"eegPriceMinorCurrencyUnitPerKwh":{"type":"number","description":"EEG remuneration component in minor currency unit per kWh"},"bonusMinorCurrencyUnitPerKwh":{"type":"number","description":"Direct marketing premium in minor currency unit per kWh"}},"required":["eegPriceMinorCurrencyUnitPerKwh","bonusMinorCurrencyUnitPerKwh"]},"EffectivePriceDataComponentDto":{"type":"object","properties":{"amountKwhPerYear":{"type":"number","description":"Amount of kWh per year"},"priceMinorCurrencyUnitPerKwh":{"type":"number","description":"Price per kWh in minor currency unit"},"priceMinorCurrencyUnitPerKwhWithoutInvestmentCost":{"type":"number","description":"Price per kWh without investment cost in minor currency unit"},"priceTotalMajorCurrencyUnitPerYear":{"type":"number","description":"Total price per year in major currency unit"},"priceTotalWithoutInvestmentCostMajorCurrencyUnitPerYear":{"type":"number","description":"Total price without investment costs per year in major currency unit"},"priceMinorCurrencyUnitPerKwhWithout14aSavings":{"type":"number","description":"Price per kWh without 14a savings in minor currency unit"},"savings14a":{"description":"Paragraph 14a savings","allOf":[{"$ref":"#/components/schemas/Paragraph14aSavingsResponseDto"}]},"directMarketing":{"description":"Breakdown when direct marketing applies (EEG rate + premium)","allOf":[{"$ref":"#/components/schemas/DirectMarketingBreakdownDto"}]}},"required":["amountKwhPerYear","priceMinorCurrencyUnitPerKwh","priceTotalMajorCurrencyUnitPerYear"]},"Co2SavingsDto":{"type":"object","properties":{"annualKg":{"type":"number","description":"Annual CO2 savings in kg"},"lifetimeKg":{"type":"number","description":"CO2 savings over the lifetime in kg"},"annualTrees":{"type":"number","description":"CO2 savings represented as number of trees (annual)"},"annualKmDrivenByCar":{"type":"number","description":"CO2 savings represented as number of km driven by an average car (annual)"}},"required":["annualKg","lifetimeKg","annualTrees","annualKmDrivenByCar"]},"EnergyType":{"type":"string","enum":["electric","fossil"]},"ConsumptionBasedBreakdownComponentDto":{"type":"object","properties":{"energyType":{"description":"Energy type","allOf":[{"$ref":"#/components/schemas/EnergyType"}]},"amountKwhPerYear":{"type":"number","description":"Amount of kWh consumed per year"},"amountKwhPerYearBatteryLoss":{"type":"number","description":"Battery loss of kWh per year "},"priceMinorCurrencyUnitPerKwh":{"type":"number","description":"Price per kWh in minor currency unit"},"priceTotalMajorCurrencyUnitPerYear":{"type":"number","description":"Total price per year in major currency unit"}},"required":["energyType","amountKwhPerYear","amountKwhPerYearBatteryLoss","priceMinorCurrencyUnitPerKwh","priceTotalMajorCurrencyUnitPerYear"]},"EffectivePriceHeatResponseDto":{"type":"object","properties":{"energyType":{"description":"Energy type","allOf":[{"$ref":"#/components/schemas/EnergyType"}]},"amountKwhPerYear":{"type":"number","description":"Amount of kWh consumed per year"},"amountKwhPerYearBatteryLoss":{"type":"number","description":"Battery loss of kWh per year "},"priceMinorCurrencyUnitPerKwh":{"type":"number","description":"Price per kWh in minor currency unit"},"priceTotalMajorCurrencyUnitPerYear":{"type":"number","description":"Total price per year in major currency unit"},"additionalCosts":{"type":"number","description":"Additional costs for heating in Euro"}},"required":["energyType","amountKwhPerYear","amountKwhPerYearBatteryLoss","priceMinorCurrencyUnitPerKwh","priceTotalMajorCurrencyUnitPerYear"]},"EffectivePriceMobilityResponseDto":{"type":"object","properties":{"energyType":{"description":"Energy type","allOf":[{"$ref":"#/components/schemas/EnergyType"}]},"amountKwhPerYear":{"type":"number","description":"Amount of kWh consumed per year"},"amountKwhPerYearBatteryLoss":{"type":"number","description":"Battery loss of kWh per year "},"priceMinorCurrencyUnitPerKwh":{"type":"number","description":"Price per kWh in minor currency unit"},"priceTotalMajorCurrencyUnitPerYear":{"type":"number","description":"Total price per year in major currency unit"},"amountKmPerYear":{"type":"number","description":"Amount driven in km per year"},"kwhPer100km":{"type":"number","description":"Consumption kwh per 100 km"},"literPer100km":{"type":"number","description":"Fuel consumption liter per 100 km"},"amountLiterPerYear":{"type":"number","description":"Total fuel consumption for mobility in liters per year"},"priceMinorCurrencyUnitPerLiter":{"type":"number","description":"Price for a liter of fuel in minor currency unit"}},"required":["energyType","amountKwhPerYear","amountKwhPerYearBatteryLoss","priceMinorCurrencyUnitPerKwh","priceTotalMajorCurrencyUnitPerYear","amountKmPerYear","kwhPer100km"]},"ConsumptionBasedBreakdownDto":{"type":"object","properties":{"household":{"description":"Household consumption","allOf":[{"$ref":"#/components/schemas/ConsumptionBasedBreakdownComponentDto"}]},"heat":{"description":"Heat consumption","allOf":[{"$ref":"#/components/schemas/EffectivePriceHeatResponseDto"}]},"mobility":{"description":"Mobility consumption","allOf":[{"$ref":"#/components/schemas/EffectivePriceMobilityResponseDto"}]}},"required":["household","heat","mobility"]},"EffectivePriceResponseDeDto":{"type":"object","properties":{"pvProduction":{"description":"Pv production","allOf":[{"$ref":"#/components/schemas/EffectivePriceDataComponentDto"}]},"gridUsage":{"description":"Grid usage","allOf":[{"$ref":"#/components/schemas/EffectivePriceDataComponentDto"}]},"gridFeedin":{"description":"Grid feed-in","allOf":[{"$ref":"#/components/schemas/EffectivePriceDataComponentDto"}]},"effectivePrice":{"description":"Effective price","allOf":[{"$ref":"#/components/schemas/EffectivePriceDataComponentDto"}]},"autarkyPct":{"type":"number","description":"Autarky in percent"},"hasBattery":{"type":"boolean","description":"Is the calculation based on a battery?"},"co2Savings":{"description":"CO2 savings","allOf":[{"$ref":"#/components/schemas/Co2SavingsDto"}]},"consumptionBasedBreakdown":{"description":"Consumption based breakdown","allOf":[{"$ref":"#/components/schemas/ConsumptionBasedBreakdownDto"}]}},"required":["pvProduction","gridUsage","gridFeedin","effectivePrice","autarkyPct","hasBattery","co2Savings","consumptionBasedBreakdown"]},"FinancingLimitsDto":{"type":"object","properties":{"isBlockedByAge":{"type":"boolean"},"maxInstallmentsPv":{"type":"number","nullable":true},"maxInstallmentsHeat":{"type":"number","nullable":true},"minInstallmentMonths":{"type":"number","nullable":true},"combinedGrossLimitEur":{"type":"number"},"isCombinedGrossOverLimit":{"type":"boolean"},"isPvBlockedByCombinedGrossLimit":{"type":"boolean"},"isHeatBlockedByCombinedGrossLimit":{"type":"boolean"},"isPvAloneOverFinancingLimit":{"type":"boolean"},"isHeatAloneOverFinancingLimit":{"type":"boolean"}}},"FinancingDto":{"type":"object","properties":{"creditOption":{"type":"object"},"creditInvestmentSum":{"type":"object"},"creditInstallments":{"type":"object"},"creditInterestRate":{"type":"object"},"creditMonthlyFee":{"type":"object"},"creditTotalMonthlyCosts":{"type":"object"},"creditInstallmentsPv":{"type":"object"},"creditInstallmentsHeat":{"type":"object"},"creditInterestRatePv":{"type":"object"},"creditInterestRateHeat":{"type":"object"},"creditTotalMonthlyCostsPv":{"type":"object"},"creditTotalMonthlyCostsHeat":{"type":"object"},"financingLimits":{"$ref":"#/components/schemas/FinancingLimitsDto"}}},"OfferPdfDto":{"type":"object","properties":{"id":{"type":"number"},"url":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"name":{"type":"string"},"fileName":{"type":"string"},"thumb":{"type":"string"}},"required":["id","url","createdAt","updatedAt","name","fileName","thumb"]},"ConfigDetailsResponseDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"isFrozen":{"type":"boolean"},"isGeneralVat":{"type":"object"},"site":{"type":"object"},"customer":{"type":"object"},"tenant":{"type":"object"},"paymentOption":{"type":"object"},"financing":{"$ref":"#/components/schemas/FinancingDto"},"crmLinks":{"type":"object"},"notes":{"type":"object"},"roof":{"type":"object"},"getAcceptDocuments":{"type":"object"},"showItemPrices":{"type":"object"},"pdf":{"type":"array","items":{"$ref":"#/components/schemas/OfferPdfDto"}},"metrics":{"type":"object"},"offer":{"type":"object"},"products":{"type":"object"},"margins":{"type":"object"},"profitability":{"type":"object"},"emailPlaceholders":{"type":"object"}},"required":["id","name","isFrozen","site","tenant","crmLinks","notes","roof","getAcceptDocuments","metrics","offer","products","margins","profitability","emailPlaceholders"]},"SendOfferEmailDto":{"type":"object","properties":{"recipient":{"type":"string"},"ccAddress":{"type":"string"},"subject":{"type":"string"},"body":{"type":"string"}},"required":["recipient","subject","body"]},"SendOfferRequestDto":{"type":"object","properties":{"offerType":{"type":"string","enum":["pv","heat"]},"withDataSheets":{"type":"boolean"},"shortVersion":{"type":"boolean"},"email":{"$ref":"#/components/schemas/SendOfferEmailDto"}},"required":["offerType","withDataSheets"]},"SendOfferResponseDto":{"type":"object","properties":{"success":{"type":"boolean"},"getAcceptDocumentId":{"type":"string"}},"required":["success"]},"OfferTypeEnum":{"type":"string","enum":["pv","heat","charger"]},"GeneratePdfDto":{"type":"object","properties":{"offerType":{"allOf":[{"$ref":"#/components/schemas/OfferTypeEnum"}]},"withDataSheets":{"type":"boolean"},"shortVersion":{"type":"boolean"},"hasHeartbeat":{"type":"boolean","description":"Whether the configuration has a Heartbeat product"}},"required":["offerType"]},"PdfResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the PDF generation was initiated"},"message":{"type":"string","description":"Error message if generation failed"}},"required":["success"]},"AuditLogSortField":{"type":"string","enum":["createdAt","action","subjectType","actorType"]},"SortOrder":{"type":"string","enum":["asc","desc"]},"AuditLogResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the audit log entry","example":"550e8400-e29b-41d4-a716-446655440000"},"action":{"type":"string","description":"The action that was performed","example":"created"},"description":{"type":"string","description":"Human-readable description of the action","example":"User created a new configuration"},"actorType":{"type":"object","description":"Type of actor who performed the action","example":"User","nullable":true},"actorIdentifier":{"type":"object","description":"Identifier of the actor","example":"user@example.com","nullable":true},"subjectType":{"type":"object","description":"Type of subject the action was performed on","example":"Configuration","nullable":true},"subjectIdentifier":{"type":"object","description":"Identifier of the subject","example":"12345","nullable":true},"traceId":{"type":"object","description":"Trace ID for request correlation","example":"abc123-def456","nullable":true},"metadata":{"type":"object","description":"Additional metadata about the action","example":{"oldValue":"A","newValue":"B"},"nullable":true},"createdAt":{"type":"string","description":"Timestamp when the action was logged","example":"2024-01-15T10:30:00.000Z"}},"required":["id","action","description","actorType","actorIdentifier","subjectType","subjectIdentifier","traceId","metadata","createdAt"]},"PaginationMetaDto":{"type":"object","properties":{"total":{"type":"number","description":"Total number of items","example":100},"page":{"type":"number","description":"Current page number","example":1},"limit":{"type":"number","description":"Number of items per page","example":20},"totalPages":{"type":"number","description":"Total number of pages","example":5}},"required":["total","page","limit","totalPages"]},"PaginatedAuditLogsResponseDto":{"type":"object","properties":{"data":{"description":"Array of audit log entries","type":"array","items":{"$ref":"#/components/schemas/AuditLogResponseDto"}},"meta":{"description":"Pagination metadata","allOf":[{"$ref":"#/components/schemas/PaginationMetaDto"}]}},"required":["data","meta"]},"AdminUserSortField":{"type":"string","enum":["createdAt","name","email","lastLoginAt"]},"AdminUserTenantDto":{"type":"object","properties":{"id":{"type":"string","description":"Tenant ID","example":"tenant-1"},"name":{"type":"string","description":"Tenant name (branch name)","example":"Berlin Branch"}},"required":["id","name"]},"AdminUserResponseDto":{"type":"object","properties":{"id":{"type":"number","description":"Unique identifier of the user","example":123},"email":{"type":"string","description":"User email address","example":"john.doe@example.com"},"name":{"type":"string","description":"User full name","example":"John Doe"},"accessLevel":{"description":"Access level determining the scope of data the user can access","example":"branch","allOf":[{"$ref":"#/components/schemas/AccessLevel"}]},"createdAt":{"type":"string","description":"Timestamp when the user was created","example":"2024-01-15T10:30:00.000Z"},"lastLoginAt":{"type":"object","description":"Timestamp of last login","example":"2024-06-20T14:45:00.000Z","nullable":true},"tenants":{"description":"Tenants (branches) the user belongs to","type":"array","items":{"$ref":"#/components/schemas/AdminUserTenantDto"}}},"required":["id","email","name","accessLevel","createdAt","lastLoginAt","tenants"]},"PaginatedAdminUsersResponseDto":{"type":"object","properties":{"data":{"description":"Array of user entries","type":"array","items":{"$ref":"#/components/schemas/AdminUserResponseDto"}},"meta":{"description":"Pagination metadata","allOf":[{"$ref":"#/components/schemas/PaginationMetaDto"}]}},"required":["data","meta"]},"CurrentAdminUserResponseDto":{"type":"object","properties":{"id":{"type":"number","description":"User ID","example":123},"accessLevel":{"description":"Access level determining the scope of data the user can access","example":"branch","allOf":[{"$ref":"#/components/schemas/AccessLevel"}]},"countryId":{"type":"object","description":"Country ID (null for GLOBAL users)","example":1,"nullable":true},"countryName":{"type":"object","description":"Country name (null for GLOBAL users)","example":"Germany","nullable":true},"tenants":{"description":"List of tenants the user has access to (for BRANCH level users)","items":{"type":"array"},"type":"array"}},"required":["id","accessLevel","countryId","countryName","tenants"]},"MyBranchesResponseDto":{"type":"object","properties":{"branches":{"description":"List of branches accessible to the current user","items":{"type":"array"},"type":"array"}},"required":["branches"]},"AdminBranchCountryDto":{"type":"object","properties":{"id":{"type":"number","description":"Country ID","example":1},"name":{"type":"string","description":"Country name","example":"Germany"},"countryCode":{"type":"string","description":"Country code (ISO 3166-1 alpha-2)","example":"DE"}},"required":["id","name","countryCode"]},"AdminBranchDto":{"type":"object","properties":{"id":{"type":"string","description":"Branch ID","example":"branch-123"},"name":{"type":"string","description":"Branch name","example":"Berlin Branch"},"zohoId":{"type":"object","description":"Zoho CRM ID","example":"12345678","nullable":true},"country":{"description":"Country information","allOf":[{"$ref":"#/components/schemas/AdminBranchCountryDto"}]}},"required":["id","name","zohoId","country"]},"AdminUserDetailResponseDto":{"type":"object","properties":{"id":{"type":"number","description":"Unique identifier of the user","example":123},"email":{"type":"string","description":"User email address","example":"john.doe@example.com"},"name":{"type":"string","description":"User full name","example":"John Doe"},"accessLevel":{"description":"Access level determining the scope of data the user can access","example":"branch","allOf":[{"$ref":"#/components/schemas/AccessLevel"}]},"countryId":{"type":"object","description":"Country ID","example":1,"nullable":true},"zohoUserId":{"type":"object","description":"Zoho User ID","example":"12345678901234567","nullable":true},"defaultTenantId":{"type":"object","description":"Default tenant/branch ID","example":"tenant-1","nullable":true},"createdAt":{"type":"string","description":"Timestamp when the user was created","example":"2024-01-15T10:30:00.000Z"},"tenants":{"description":"Tenants (branches) the user belongs to","type":"array","items":{"$ref":"#/components/schemas/AdminUserTenantDto"}},"hiddenBranchCount":{"type":"number","description":"Number of branches the user has access to that the current user cannot see or modify","example":0},"roles":{"description":"Role names assigned to the user","example":["sales","branch lead"],"type":"array","items":{"type":"array"}}},"required":["id","email","name","accessLevel","countryId","zohoUserId","defaultTenantId","createdAt","tenants","hiddenBranchCount","roles"]},"CreateAdminUserDto":{"type":"object","properties":{"email":{"type":"string","description":"User email address","example":"john.doe@example.com"},"name":{"type":"string","description":"User full name","example":"John Doe"},"accessLevel":{"description":"Access level determining the scope of data the user can access","example":"branch","allOf":[{"$ref":"#/components/schemas/AccessLevel"}]},"countryId":{"type":"object","description":"Country ID. Required for COUNTRY and BRANCH access levels.","example":1,"nullable":true},"zohoUserId":{"type":"string","description":"Zoho User ID","example":"12345678901234567"},"tenantIds":{"description":"List of tenant/branch IDs to assign to the user","example":["tenant-1","tenant-2"],"type":"array","items":{"type":"array"}},"defaultTenantId":{"type":"object","description":"Default tenant/branch ID. Central users can leave this null.","example":"tenant-1","nullable":true},"roles":{"description":"Role names to assign to the user","example":["sales","branch lead"],"type":"array","items":{"type":"array"}}},"required":["email","name","accessLevel"]},"UpdateAdminUserDto":{"type":"object","properties":{"email":{"type":"string","description":"User email address","example":"john.doe@example.com"},"name":{"type":"string","description":"User full name","example":"John Doe"},"accessLevel":{"type":"string","description":"Access level determining the scope of data the user can access","example":"branch","enum":["global","country","branch"]},"countryId":{"type":"object","description":"Country ID. Required for COUNTRY and BRANCH access levels.","example":1,"nullable":true},"zohoUserId":{"type":"object","description":"Zoho User ID (can be null to clear)","example":"12345678901234567","nullable":true},"tenantIds":{"description":"List of tenant/branch IDs to assign to the user","example":["tenant-1","tenant-2"],"type":"array","items":{"type":"array"}},"defaultTenantId":{"type":"object","description":"Default tenant/branch ID (can be null for central users to clear)","example":"tenant-1","nullable":true},"roles":{"description":"Role names to assign to the user (replaces existing roles)","example":["sales","branch lead"],"type":"array","items":{"type":"array"}}}},"AdminBranchSortField":{"type":"string","enum":["name","zohoId"]},"PaginatedAdminBranchesResponseDto":{"type":"object","properties":{"data":{"description":"List of branches","items":{"type":"array"},"type":"array"},"meta":{"description":"Pagination metadata","allOf":[{"$ref":"#/components/schemas/PaginationMetaDto"}]}},"required":["data","meta"]},"CreateAdminBranchDto":{"type":"object","properties":{"name":{"type":"string","description":"Branch name","example":"Berlin Branch","minLength":1,"maxLength":255}},"required":["name"]},"UpdateAdminBranchDto":{"type":"object","properties":{"name":{"type":"string","description":"Branch name","example":"Berlin Branch","minLength":1,"maxLength":255}}},"ConceptTemplateType":{"type":"string","enum":["pv","wp","spnach","pvwp","mg"]},"ConceptScope":{"type":"string","enum":["global","branch"]},"ConceptVisibility":{"type":"string","enum":["visible","hidden"]},"ConceptSortField":{"type":"string","enum":["name","createdAt"]},"PaginatedConceptsResponseDto":{"type":"object","properties":{"data":{"description":"List of concepts","items":{"type":"array"},"type":"array"},"meta":{"description":"Pagination metadata","allOf":[{"$ref":"#/components/schemas/PaginationMetaDto"}]}},"required":["data","meta"]},"ConceptTenantDto":{"type":"object","properties":{"id":{"type":"string","description":"Tenant ID","example":"tenant-123"},"name":{"type":"string","description":"Tenant name","example":"Berlin Branch"}},"required":["id","name"]},"ConceptPricingDto":{"type":"object","properties":{"totalNet":{"type":"number","description":"Total net price (excl. VAT)","example":12500},"totalGross":{"type":"number","description":"Total gross price (incl. VAT)","example":14875},"vatRate":{"type":"number","description":"VAT rate as percentage","example":19},"currency":{"type":"string","description":"Currency code","example":"EUR"}},"required":["totalNet","totalGross","vatRate","currency"]},"ConceptListItemDto":{"type":"object","properties":{"id":{"type":"number","description":"Concept ID","example":1},"name":{"type":"string","description":"Concept name","example":"PV Basic 10kWp"},"templateType":{"type":"object","description":"Template type (pv, wp, spnach, pvwp, mg)","example":"pv","nullable":true},"templateVisible":{"type":"boolean","description":"Whether the concept is visible to users","example":true},"templateMeta":{"type":"object","description":"Template metadata (e.g. description)","example":{"description":"Basic PV system with battery"},"nullable":true},"templateImage":{"type":"object","description":"Template marketing image URL","example":"https://storage.example.com/templates/concept.jpg","nullable":true},"createdAt":{"type":"string","description":"Creation date","example":"2024-01-15T10:30:00.000Z"},"updatedAt":{"type":"string","description":"Last update date","example":"2024-06-20T14:00:00.000Z"},"scope":{"type":"string","description":"Scope: global (no tenant) or branch (tenant-specific)","example":"global","enum":["global","branch"]},"tenant":{"description":"Tenant info (only for branch-scoped concepts)","nullable":true,"allOf":[{"$ref":"#/components/schemas/ConceptTenantDto"}]},"pricing":{"description":"Pricing information","allOf":[{"$ref":"#/components/schemas/ConceptPricingDto"}]},"products":{"description":"Products in this concept","items":{"type":"array"},"type":"array"}},"required":["id","name","templateType","templateVisible","templateMeta","templateImage","createdAt","updatedAt","scope","tenant","pricing","products"]},"CreateAdminConceptDto":{"type":"object","properties":{"name":{"type":"string","description":"Concept name","example":"PV Basic 10kWp","minLength":1,"maxLength":255}},"required":["name"]},"UpdateAdminConceptDto":{"type":"object","properties":{"name":{"type":"string","description":"Concept name","example":"PV Basic 10kWp","minLength":1,"maxLength":255}}},"AdminProductSortField":{"type":"string","enum":["name","createdAt","price","category"]},"CategoryDto":{"type":"object","properties":{"id":{"type":"number","description":"Category ID"},"name":{"type":"string","description":"Category name"}},"required":["id","name"]},"BrandDto":{"type":"object","properties":{"id":{"type":"number","description":"Brand ID"},"name":{"type":"string","description":"Brand name"}},"required":["id","name"]},"AdminProductDto":{"type":"object","properties":{"id":{"type":"number","description":"Product ID"},"name":{"type":"string","description":"Product name"},"category":{"description":"Product category","allOf":[{"$ref":"#/components/schemas/CategoryDto"}]},"brand":{"description":"Product brand","allOf":[{"$ref":"#/components/schemas/BrandDto"}]},"price":{"type":"number","description":"Product price (EK)"},"factor":{"type":"number","description":"Price factor"},"public":{"type":"boolean","description":"Is product publicly visible"},"canbesold":{"type":"boolean","description":"Can product be sold"},"visibleToTenant":{"type":"boolean","description":"Is product visible to tenants"},"imageUrl":{"type":"object","description":"Product image URL","nullable":true},"createdAt":{"type":"string","description":"Product creation date"},"countryId":{"type":"object","description":"Country ID","nullable":true},"countryCode":{"type":"object","description":"Country code (e.g., DE, SE, DK)","nullable":true},"vatType":{"type":"string","description":"VAT type override (null = inherit from category)","nullable":true,"enum":["pv","general"]}},"required":["id","name","category","brand","price","factor","public","canbesold","visibleToTenant","imageUrl","createdAt","countryId","countryCode","vatType"]},"PaginatedAdminProductsResponseDto":{"type":"object","properties":{"data":{"description":"List of products","type":"array","items":{"$ref":"#/components/schemas/AdminProductDto"}},"meta":{"description":"Pagination metadata","allOf":[{"$ref":"#/components/schemas/PaginationMetaDto"}]}},"required":["data","meta"]},"PricebookOverridesDto":{"type":"object","properties":{"price":{"type":"object","description":"Overridden price","nullable":true},"factor":{"type":"object","description":"Overridden factor","nullable":true},"public":{"type":"object","description":"Overridden visibility","nullable":true},"canbesold":{"type":"object","description":"Overridden canbesold","nullable":true}},"required":["price","factor","public","canbesold"]},"AdminPricebookProductDto":{"type":"object","properties":{"id":{"type":"number","description":"Product ID"},"name":{"type":"string","description":"Product name"},"category":{"description":"Product category","allOf":[{"$ref":"#/components/schemas/CategoryDto"}]},"brand":{"description":"Product brand","allOf":[{"$ref":"#/components/schemas/BrandDto"}]},"price":{"type":"number","description":"Product price (EK)"},"factor":{"type":"number","description":"Price factor"},"public":{"type":"boolean","description":"Is product publicly visible"},"canbesold":{"type":"boolean","description":"Can product be sold"},"visibleToTenant":{"type":"boolean","description":"Is product visible to tenants"},"imageUrl":{"type":"object","description":"Product image URL","nullable":true},"createdAt":{"type":"string","description":"Product creation date"},"countryId":{"type":"object","description":"Country ID","nullable":true},"countryCode":{"type":"object","description":"Country code (e.g., DE, SE, DK)","nullable":true},"vatType":{"type":"string","description":"VAT type override (null = inherit from category)","nullable":true,"enum":["pv","general"]},"pricebookOverrides":{"description":"Pricebook overrides for this tenant","allOf":[{"$ref":"#/components/schemas/PricebookOverridesDto"}]},"effectivePrice":{"type":"number","description":"Effective price (pricebook override or product default)"},"effectiveFactor":{"type":"number","description":"Effective factor (pricebook override or product default)"},"effectivePublic":{"type":"boolean","description":"Effective visibility (pricebook override or product default)"},"effectiveCanbesold":{"type":"boolean","description":"Effective canbesold (pricebook override or product default)"}},"required":["id","name","category","brand","price","factor","public","canbesold","visibleToTenant","imageUrl","createdAt","countryId","countryCode","vatType","pricebookOverrides","effectivePrice","effectiveFactor","effectivePublic","effectiveCanbesold"]},"PaginatedAdminPricebookResponseDto":{"type":"object","properties":{"data":{"description":"List of pricebook products","type":"array","items":{"$ref":"#/components/schemas/AdminPricebookProductDto"}},"meta":{"description":"Pagination metadata","allOf":[{"$ref":"#/components/schemas/PaginationMetaDto"}]}},"required":["data","meta"]},"CreateAdminProductDto":{"type":"object","properties":{"name":{"type":"string","description":"Product name","example":"Solar Panel XL","minLength":1,"maxLength":255}},"required":["name"]},"UpdateAdminProductDto":{"type":"object","properties":{"name":{"type":"string","description":"Product name","example":"Solar Panel XL","minLength":1,"maxLength":255}}},"RoleDto":{"type":"object","properties":{"name":{"type":"string","description":"Role name (database value)","example":"sales"},"displayName":{"type":"string","description":"Human-readable display name","example":"Sales"},"category":{"type":"string","description":"Role category - central or tenant level","example":"tenant","enum":["central","tenant"]}},"required":["name","displayName","category"]},"AssignableRolesResponseDto":{"type":"object","properties":{"roles":{"description":"List of roles the current user can assign","type":"array","items":{"$ref":"#/components/schemas/RoleDto"}}},"required":["roles"]},"BackfillConfigHashesResponseDto":{"type":"object","properties":{"queued":{"type":"boolean","description":"Whether the backfill was queued for async processing on the worker"},"batchSize":{"type":"number","description":"Batch size the worker uses per iteration"}},"required":["queued","batchSize"]},"MegasearchResultTagDto":{"type":"object","properties":{"label":{"type":"string","description":"Tag display label","example":"PV"},"variant":{"type":"string","description":"Color variant for the tag","example":"amber"},"style":{"type":"string","description":"Rendering style: pill (scope badges), dot (type accent), icon (visibility)","example":"pill"}},"required":["label","variant"]},"MegasearchResultDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the entity","example":"1"},"title":{"type":"string","description":"Display title (usually the name)","example":"John Doe"},"subtitle":{"type":"string","description":"Additional information (email, country, zoho ID)","example":"john@example.com"},"tags":{"description":"Colored tags for rich metadata display","type":"array","items":{"$ref":"#/components/schemas/MegasearchResultTagDto"}},"url":{"type":"string","description":"URL path to navigate to this entity","example":"/users/1"}},"required":["id","title","url"]},"MegasearchGroupDto":{"type":"object","properties":{"type":{"type":"string","description":"Entity type identifier","example":"user"},"label":{"type":"string","description":"Human-readable label for the group","example":"Users"},"results":{"description":"Search results in this group","type":"array","items":{"$ref":"#/components/schemas/MegasearchResultDto"}}},"required":["type","label","results"]},"MegasearchMetaDto":{"type":"object","properties":{"query":{"type":"string","description":"The search query that was executed","example":"john"},"totalResults":{"type":"number","description":"Total number of results across all groups","example":5}},"required":["query","totalResults"]},"MegasearchResponseDto":{"type":"object","properties":{"groups":{"description":"Search results grouped by entity type","type":"array","items":{"$ref":"#/components/schemas/MegasearchGroupDto"}},"meta":{"description":"Metadata about the search","allOf":[{"$ref":"#/components/schemas/MegasearchMetaDto"}]}},"required":["groups","meta"]},"MigrationSummaryDto":{"type":"object","properties":{"total":{"type":"number","example":12},"succeeded":{"type":"number","example":10},"skipped":{"type":"number","example":1},"failed":{"type":"number","example":1}},"required":["total","succeeded","skipped","failed"]},"ConfigMigrationOrchestratorResponseDto":{"type":"object","properties":{"configId":{"type":"number","example":12345},"success":{"type":"boolean","example":true},"steps":{"items":{"type":"array"},"type":"array"},"summary":{"$ref":"#/components/schemas/MigrationSummaryDto"}},"required":["configId","success","steps","summary"]},"ConfigProductsMigrationResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the migration was successful"},"configId":{"type":"number","description":"The config ID that was migrated"},"productsUpdated":{"type":"number","description":"Number of products updated"},"message":{"type":"string","description":"Optional message about the migration"},"skipped":{"type":"boolean","description":"Whether the step was skipped (already migrated, not frozen, no data)"}},"required":["success","configId","productsUpdated"]},"ConfigDocumentsMigrationResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the migration was successful"},"configId":{"type":"number","description":"The config ID that was migrated"},"documentsCreated":{"type":"number","description":"Number of documents created"},"message":{"type":"string","description":"Optional message about the migration"},"skipped":{"type":"boolean","description":"Whether the step was skipped (already migrated, not frozen, no data)"}},"required":["success","configId","documentsCreated"]},"ConfigTableMigrationResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the migration was successful"},"configId":{"type":"number","description":"The config ID that was migrated"},"columnsUpdated":{"type":"number","description":"Number of columns updated (out of 6 possible columns)"},"message":{"type":"string","description":"Optional message about the migration"},"skipped":{"type":"boolean","description":"Whether the step was skipped (already migrated, not frozen, no data)"}},"required":["success","configId","columnsUpdated"]},"ConfigCustomerMigrationResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the migration was successful"},"configId":{"type":"number","description":"The config ID that was migrated"},"columnsUpdated":{"type":"number","description":"Number of columns updated (out of 9 possible columns)"},"message":{"type":"string","description":"Optional message about the migration"},"skipped":{"type":"boolean","description":"Whether the step was skipped (already migrated, not frozen, no data)"}},"required":["success","configId","columnsUpdated"]},"ConfigConsumptionMigrationResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the migration was successful"},"configId":{"type":"number","description":"The config ID that was migrated"},"columnsUpdated":{"type":"number","description":"Number of columns updated (out of 6 possible columns)"},"message":{"type":"string","description":"Optional message about the migration"},"skipped":{"type":"boolean","description":"Whether the step was skipped (already migrated, not frozen, no data)"}},"required":["success","configId","columnsUpdated"]},"ConfigMarginsMigrationResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the migration was successful"},"configId":{"type":"number","description":"The config ID that was migrated"},"marginsCreated":{"type":"number","description":"Number of margin rows created (out of 3 possible: total, pv, heat)"},"message":{"type":"string","description":"Optional message about the migration"},"skipped":{"type":"boolean","description":"Whether the step was skipped (already migrated, not frozen, no data)"}},"required":["success","configId","marginsCreated"]},"ConfigCalculationLegacyMigrationResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the migration was successful"},"configId":{"type":"number","description":"The config ID that was migrated"},"columnsUpdated":{"type":"number","description":"Number of columns updated (out of 9 possible columns)"},"message":{"type":"string","description":"Optional message about the migration"},"skipped":{"type":"boolean","description":"Whether the step was skipped (already migrated, not frozen, no data)"}},"required":["success","configId","columnsUpdated"]},"ConfigCalculationMigrationResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the migration was successful","example":true},"configId":{"type":"number","description":"The ID of the config that was migrated","example":123},"columnsUpdated":{"type":"number","description":"Number of columns updated in the config_calculation table","example":15},"message":{"type":"string","description":"Optional message about the migration status","example":"Successfully updated 15 column(s)"},"skipped":{"type":"boolean","description":"Whether the step was skipped (already migrated, not frozen, no data)"}},"required":["success","configId","columnsUpdated"]},"ConfigMetricsMigrationResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the migration was successful"},"configId":{"type":"number","description":"The config ID that was migrated"},"columnsUpdated":{"type":"number","description":"Number of columns updated (out of 20 possible columns)"},"message":{"type":"string","description":"Optional message about the migration"},"skipped":{"type":"boolean","description":"Whether the step was skipped (already migrated, not frozen, no data)"}},"required":["success","configId","columnsUpdated"]},"ConfigSelfSufficiencyMigrationResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the migration was successful"},"configId":{"type":"number","description":"The config ID that was migrated"},"rowsCreated":{"type":"number","description":"Number of config_self_sufficiency rows created"},"message":{"type":"string","description":"Optional message about the migration"},"skipped":{"type":"boolean","description":"Whether the step was skipped (already migrated, not frozen, no data)"}},"required":["success","configId","rowsCreated"]},"ConfigMarketComponentsMigrationResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the migration was successful"},"configId":{"type":"number","description":"The config ID that was migrated"},"marketComponentsCreated":{"type":"number","description":"Number of market component rows created"},"message":{"type":"string","description":"Optional message about the migration"},"skipped":{"type":"boolean","description":"Whether the step was skipped (already migrated, not frozen, no data)"}},"required":["success","configId","marketComponentsCreated"]},"ConfigEffectivePricesMigrationResponseDto":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the migration was successful"},"configId":{"type":"number","description":"The config ID that was migrated"},"rowsCreated":{"type":"number","description":"Number of effective price rows created (up to 11 possible: 2 unoptimized + 4 pv + 5 dynamic_tariff)"},"message":{"type":"string","description":"Optional message about the migration"},"skipped":{"type":"boolean","description":"Whether the step was skipped (already migrated, not frozen, no data)"}},"required":["success","configId","rowsCreated"]}}}}