+ * This configuration class sets up the essential beans required for multi-tenant + * account management, including the custom account scope and a fallback no-op + * implementation of {@link AccountServiceAPI}. + *
+ * The configuration is automatically loaded when the module is present in the classpath, + * and provides sensible defaults that can be overridden by custom implementations. + * + * @author Mario Serrano Leones */ @Configuration public class AccountAPIConfig { - /** - * This bean is used to register the AccountScope in the application context. - * @return CustomScopeConfigurer + * Registers the custom "account" scope with the Spring container. + *
+ * This bean configures the {@link AccountScope} which enables beans to be scoped + * at the account level, ensuring proper isolation in multi-tenant environments. + * Once registered, beans can use {@code @Scope("account")} to be managed at the account level. + * + * @return a {@link CustomScopeConfigurer} with the account scope registered + * @see AccountScope */ @Bean public CustomScopeConfigurer accountScopeConfigurer() { @@ -42,10 +55,14 @@ public CustomScopeConfigurer accountScopeConfigurer() { } /** - * If no AccountServiceAPI is configured, this bean will be used as a default. - * This is useful for testing. + * Provides a no-op implementation of {@link AccountServiceAPI} as a fallback. + *
+ * This bean is only created if no other {@link AccountServiceAPI} implementation + * is found in the application context. It's primarily useful for testing scenarios + * or when the SaaS features are not fully configured. * - * @return NoOpAccountServiceAPI instance + * @return a {@link NoOpAccountServiceAPI} instance + * @see NoOpAccountServiceAPI */ @Bean @ConditionalOnMissingBean(AccountServiceAPI.class) diff --git a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAdminAction.java b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAdminAction.java index d93ed79..7f899fd 100644 --- a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAdminAction.java +++ b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAdminAction.java @@ -22,11 +22,49 @@ import tools.dynamia.actions.ActionSelfFilter; import tools.dynamia.integration.Containers; +/** + * Base class for administrative actions that require authorization in a SaaS environment. + *
+ * This class extends {@link AbstractAction} and provides built-in support for authorization + * checks before executing administrative operations. It integrates with + * {@link AccountAdminActionAuthorizationProvider} to enforce security policies. + *
+ * Actions extending this class can require authorization by setting the + * {@code authorizationRequired} flag. When enabled, the action will delegate to the + * configured authorization provider before executing. + *
+ * Example usage: + *
{@code
+ * public class DeleteAccountAction extends AccountAdminAction {
+ * public DeleteAccountAction() {
+ * setName("Delete Account");
+ * setAuthorizationRequired(true);
+ * }
+ *
+ * @Override
+ * public void actionPerformed(ActionEvent evt) {
+ * // Delete account logic
+ * }
+ * }
+ * }
+ *
+ * @author Mario Serrano Leones
+ * @see AccountAdminActionAuthorizationProvider
+ * @see AbstractAction
+ */
public abstract class AccountAdminAction extends AbstractAction implements ActionSelfFilter {
private boolean authorizationRequired;
-
+ /**
+ * Hook method executed before the action is performed.
+ * + * If authorization is required, this method will delegate to the + * {@link AccountAdminActionAuthorizationProvider} to perform authorization checks. + * The actual action will only execute if authorization is granted. + * + * @param evt the action event + */ @Override public void beforeActionPerformed(ActionEvent evt) { if (isAuthorizationRequired()) { @@ -39,15 +77,33 @@ public void beforeActionPerformed(ActionEvent evt) { } } + /** + * Hook method executed after the action is performed. + *
+ * This implementation does nothing and can be overridden by subclasses + * to add post-execution logic. + * + * @param evt the action event + */ @Override public void afterActionPerformed(ActionEvent evt) { //do nothing } + /** + * Checks if authorization is required before executing this action. + * + * @return true if authorization is required, false otherwise + */ public boolean isAuthorizationRequired() { return authorizationRequired; } + /** + * Sets whether authorization is required before executing this action. + * + * @param authorizationRequired true to require authorization, false otherwise + */ public void setAuthorizationRequired(boolean authorizationRequired) { this.authorizationRequired = authorizationRequired; } diff --git a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAdminActionAuthorizationProvider.java b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAdminActionAuthorizationProvider.java index 16c5c07..6beb3d6 100644 --- a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAdminActionAuthorizationProvider.java +++ b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAdminActionAuthorizationProvider.java @@ -4,7 +4,51 @@ import tools.dynamia.actions.ActionEvent; import tools.dynamia.commons.Callback; +/** + * Interface for providing custom authorization logic for administrative actions in a SaaS environment. + *
+ * This interface allows modules to implement custom authorization checks before executing + * administrative actions on accounts. It provides a hook point for adding security layers, + * audit requirements, or business rules that must be validated before an action proceeds. + *
+ * The authorization process is asynchronous, using a callback mechanism to either grant or deny access. + * This design allows for complex authorization workflows, including user confirmations, multi-factor + * authentication, or external authorization services. + *
+ * Example usage: + *
{@code
+ * @Component
+ * public class MFAAuthorizationProvider implements AccountAdminActionAuthorizationProvider {
+ * @Override
+ * public void authorize(Action action, ActionEvent evt, Callback onAuthorization) {
+ * if (requiresMFA(action)) {
+ * promptForMFA(success -> {
+ * if (success) {
+ * onAuthorization.doSomething();
+ * }
+ * });
+ * } else {
+ * onAuthorization.doSomething();
+ * }
+ * }
+ * }
+ * }
+ *
+ * @author Mario Serrano Leones
+ */
public interface AccountAdminActionAuthorizationProvider {
+ /**
+ * Performs authorization checks for an administrative action.
+ * + * This method is called before executing administrative actions on accounts. + * Implementations should perform any necessary authorization checks and invoke + * the callback if authorization is granted. If authorization is denied, the + * callback should not be invoked. + * + * @param action the action being authorized + * @param evt the event context containing information about the action execution + * @param onAuthorization callback to invoke if authorization is granted + */ void authorize(Action action, ActionEvent evt, Callback onAuthorization); } diff --git a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAware.java b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAware.java index bd93170..62e4bbe 100644 --- a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAware.java +++ b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAware.java @@ -19,13 +19,45 @@ package tools.dynamia.modules.saas.api; /** + * Interface for entities or components that belong to a specific account in a multi-tenant SaaS environment. + *
+ * Implementing this interface allows objects to be associated with an account, enabling proper data isolation + * and tenant-specific operations. This is a fundamental interface for multi-tenancy support, ensuring that + * each entity knows which account it belongs to. + *
+ * Example usage: + *
{@code
+ * @Entity
+ * public class Customer implements AccountAware {
+ * @Column
+ * private Long accountId;
+ *
+ * public Long getAccountId() {
+ * return accountId;
+ * }
+ *
+ * public void setAccountId(Long accountId) {
+ * this.accountId = accountId;
+ * }
+ * }
+ * }
*
* @author Mario Serrano Leones
*/
public interface AccountAware {
+ /**
+ * Returns the unique identifier of the account this entity belongs to.
+ *
+ * @return the account ID
+ */
Long getAccountId();
+ /**
+ * Sets the account this entity belongs to.
+ *
+ * @param account the account ID to assign to this entity
+ */
void setAccountId(Long account);
}
diff --git a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountFeatureProvider.java b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountFeatureProvider.java
index 844daa2..1f5e4b4 100644
--- a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountFeatureProvider.java
+++ b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountFeatureProvider.java
@@ -17,10 +17,48 @@
package tools.dynamia.modules.saas.api;
+/**
+ * Provider interface for defining account features in a SaaS multi-tenant environment.
+ * + * This interface allows modules to register features that can be enabled or disabled + * per account. Features can be used to control access to specific functionality, + * allowing different subscription tiers or custom feature sets for different accounts. + *
+ * Implementations should be registered as Spring beans and will be automatically + * discovered by the SaaS module to populate the available features list. + *
+ * Example usage: + *
{@code
+ * @Component
+ * public class AdvancedReportsFeature implements AccountFeatureProvider {
+ * public String getId() {
+ * return "advanced-reports";
+ * }
+ *
+ * public String getName() {
+ * return "Advanced Reports";
+ * }
+ * }
+ * }
+ *
+ * @author Mario Serrano Leones
+ */
public interface AccountFeatureProvider {
+ /**
+ * Returns the unique identifier for this feature.
+ * This ID is used to reference the feature programmatically throughout the application.
+ *
+ * @return the feature identifier (e.g., "advanced-reports", "api-access")
+ */
String getId();
+ /**
+ * Returns the human-readable name of this feature.
+ * This name is typically displayed in the user interface for feature management.
+ *
+ * @return the feature display name
+ */
String getName();
}
diff --git a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountInitializer.java b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountInitializer.java
index fdc34cf..8a2cd43 100644
--- a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountInitializer.java
+++ b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountInitializer.java
@@ -27,22 +27,75 @@
import java.util.Locale;
/**
+ * Interface for components that perform initialization tasks when a new account is created in a SaaS environment.
+ * + * Implementations of this interface are automatically discovered and executed during account creation, + * allowing modules to set up initial data, configurations, or resources for new accounts. + * Multiple initializers can be chained together, with execution order controlled by priority. + *
+ * Common use cases include: + *
+ * Example usage: + *
{@code
+ * @Component
+ * public class DefaultRolesInitializer implements AccountInitializer {
+ * @Override
+ * public void init(AccountDTO accountDTO) {
+ * // Create default roles for the new account
+ * createRole(accountDTO, "ADMIN");
+ * createRole(accountDTO, "USER");
+ * }
+ *
+ * @Override
+ * public int getPriority() {
+ * return 100; // Execute after basic setup
+ * }
+ * }
+ * }
+ *
* @author Mario Serrano Leones
*/
public interface AccountInitializer {
+ /**
+ * Performs initialization tasks for a newly created account.
+ * + * This method is called automatically after an account is created and persisted. + * Implementations should create any necessary initial data or configurations + * required for the account to function properly. + * + * @param accountDTO the newly created account's data transfer object + */ void init(AccountDTO accountDTO); /** - * Define account initializer priority or order. Lower value is high priority + * Defines the execution priority for this initializer. + *
+ * When multiple initializers exist, they are executed in order from lowest to highest priority value. + * Lower values indicate higher priority and will execute first. * - * @return + * @return the priority value (default is 0, lower values execute first) */ default int getPriority() { return 0; } - + /** + * Retrieves a localized message for the account's configured locale. + *
+ * This helper method simplifies obtaining localized strings during account initialization, + * using the account's locale setting if available, or falling back to the system default. + * + * @param key the message key to retrieve + * @param accountDTO the account containing locale information + * @return the localized message string, or the key itself if no translation is found + */ default String localizedMessage(String key, AccountDTO accountDTO) { try { var provider = Containers.get().findObjects(LocalizedMessagesProvider.class) diff --git a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountLocalStorage.java b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountLocalStorage.java index b82e269..b30ffa4 100644 --- a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountLocalStorage.java +++ b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountLocalStorage.java @@ -22,35 +22,114 @@ import java.util.Date; +/** + * Interface for managing account-specific temporary storage in a multi-tenant SaaS environment. + *
+ * This interface provides a key-value storage mechanism that is scoped to the current account, + * useful for caching data, storing temporary state, or maintaining session-like information + * at the account level. The storage is typically backed by in-memory caching or similar mechanisms. + *
+ * All stored entries include metadata such as timestamps and optional messages, + * making it suitable for audit trails or debugging purposes. + *
+ * Example usage: + *
{@code
+ * AccountLocalStorage storage = AccountLocalStorage.load();
+ * storage.add("last-sync-time", new Date());
+ * Date lastSync = (Date) storage.get("last-sync-time");
+ * }
+ *
+ * @author Mario Serrano Leones
+ */
public interface AccountLocalStorage {
+ /**
+ * Loads the current account's local storage instance.
+ * + * This static factory method retrieves the active implementation of AccountLocalStorage + * from the dependency injection container, automatically scoped to the current account context. + * + * @return the AccountLocalStorage instance for the current account + */ static AccountLocalStorage load() { return Containers.get().findObject(AccountLocalStorage.class); } + /** + * Retrieves a value from storage by its key. + * + * @param key the storage key + * @return the stored value, or null if not found + */ Object get(String key); + /** + * Retrieves a complete entry from storage, including metadata. + * + * @param key the storage key + * @return the Entry object containing value and metadata, or null if not found + */ Entry getEntry(String key); + /** + * Stores a value with the specified key. + *
+ * If a value already exists for this key, it will be replaced. + * + * @param key the storage key + * @param value the value to store + */ void add(String key, Object value); + /** + * Stores a complete entry with metadata. + * + * @param entry the entry to store, containing key, value, and optional message + */ void addEntry(Entry entry); + /** + * Removes a value from storage. + * + * @param key the storage key to remove + */ void remove(String key); + /** + * Clears all entries from the current account's storage. + */ void clear(); + /** + * Represents a storage entry with metadata including timestamp and optional message. + *
+ * Each entry captures not only the key-value pair but also when it was created + * and an optional descriptive message, useful for audit trails or debugging. + */ class Entry { - private String key; - private Object value; - private long timestamp; - private String message; - private Date date; - + private final String key; + private final Object value; + private final long timestamp; + private final String message; + private final Date date; + + /** + * Creates a new entry with the specified key and value. + * + * @param key the storage key + * @param value the value to store + */ public Entry(String key, Object value) { this(key, value, null); } + /** + * Creates a new entry with the specified key, value, and descriptive message. + * + * @param key the storage key + * @param value the value to store + * @param message an optional descriptive message for this entry + */ public Entry(String key, Object value, String message) { this.key = key; this.value = value; @@ -59,22 +138,47 @@ public Entry(String key, Object value, String message) { this.date = DateTimeUtils.createDate(timestamp); } + /** + * Returns the storage key for this entry. + * + * @return the key + */ public String getKey() { return key; } + /** + * Returns the stored value. + * + * @return the value + */ public Object getValue() { return value; } + /** + * Returns the timestamp (milliseconds since epoch) when this entry was created. + * + * @return the creation timestamp + */ public long getTimestamp() { return timestamp; } + /** + * Returns the optional descriptive message associated with this entry. + * + * @return the message, or null if none was provided + */ public String getMessage() { return message; } + /** + * Returns the creation date of this entry. + * + * @return the creation date + */ public Date getDate() { return date; } diff --git a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountScope.java b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountScope.java index ac69af8..88a1662 100644 --- a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountScope.java +++ b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountScope.java @@ -25,10 +25,43 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +/** + * Custom Spring bean scope implementation for account-scoped beans in a multi-tenant SaaS environment. + *
+ * This scope manages beans at the account level, ensuring that each tenant account has its own + * isolated instances of account-scoped beans. This is essential for maintaining proper data + * isolation and state management in multi-tenant applications. + *
+ * Beans defined with this scope will be created once per account and reused for all requests + * within that account's context. The scope automatically handles bean lifecycle and cleanup + * when accounts are switched or removed. + *
+ * Example usage in Spring configuration: + *
{@code
+ * @Component
+ * @Scope("account")
+ * public class AccountSpecificService {
+ * // This bean will have one instance per account
+ * }
+ * }
+ *
+ * @author Mario Serrano Leones
+ * @see org.springframework.beans.factory.config.Scope
+ */
public class AccountScope implements Scope {
- private Map+ * This method is called by Spring when resolving account-scoped beans. + * It ensures that each account has its own isolated instance of the bean. + * + * @param name the name of the bean + * @param objectFactory the factory to create the bean if it doesn't exist + * @return the scoped bean instance, or null if no account context is available + */ @Override public Object get(String name, ObjectFactory> objectFactory) { Object object = null; @@ -44,7 +77,15 @@ public Object get(String name, ObjectFactory> objectFactory) { return object; } - + /** + * Removes a bean instance from the current account's scope. + *
+ * This method is called when explicitly removing a bean from the scope + * or during account cleanup operations. + * + * @param name the name of the bean to remove + * @return the removed bean instance, or null if not found or no account context + */ @Override public Object remove(String name) { Long accountId = getAccountId(); @@ -54,16 +95,40 @@ public Object remove(String name) { return null; } + /** + * Registers a callback to be executed when a bean is destroyed. + *
+ * This implementation currently does not support destruction callbacks. + * + * @param name the name of the bean + * @param callback the callback to execute on destruction + */ @Override public void registerDestructionCallback(String name, Runnable callback) { } + /** + * Resolves a contextual object for the given key. + *
+ * This implementation does not provide contextual objects. + * + * @param key the key to resolve + * @return always returns null + */ @Override public Object resolveContextualObject(String key) { return null; } + /** + * Returns a unique conversation ID for the current account scope. + *
+ * The conversation ID is based on the current account ID and is used
+ * by Spring to identify the scope context.
+ *
+ * @return a conversation ID in the format "account{accountId}", or null if no account context
+ */
@Override
public String getConversationId() {
Long accountId = getAccountId();
@@ -74,6 +139,12 @@ public String getConversationId() {
}
+ /**
+ * Retrieves or creates the bean storage map for the specified account.
+ *
+ * @param accountId the account identifier
+ * @return a map containing all beans for the account
+ */
private Map
+ * Implementations of this interface handle the business logic for account operations,
+ * tenant isolation, and account lifecycle management in a SaaS architecture.
+ *
+ * Example usage:
+ *
+ * This interface enables modules to define custom metrics or usage calculators that can be tracked
+ * per account. These calculations can be used for billing purposes, usage analytics, or quota enforcement.
+ *
+ * Common use cases include:
+ *
+ * Implementations should be registered as Spring beans and will be automatically discovered
+ * by the SaaS module for service quantity tracking.
+ *
+ * Example usage:
+ *
+ * This method should perform any necessary queries or calculations to determine
+ * the current usage or quantity value for the given account.
+ *
+ * @param accountId the unique identifier of the account
+ * @return the calculated quantity value
+ */
long calculate(Long accountId);
}
diff --git a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountStatsProvider.java b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountStatsProvider.java
index f6e0ef4..f6d0616 100644
--- a/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountStatsProvider.java
+++ b/sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountStatsProvider.java
@@ -19,7 +19,52 @@
import java.util.List;
+/**
+ * Interface for providing statistical information about an account.
+ *
+ * This interface allows modules to contribute custom statistics and metrics
+ * that can be displayed in account dashboards, reports, or administrative interfaces.
+ * Multiple providers can coexist, each providing different types of statistics.
+ *
+ * Statistics can include metrics such as:
+ *
+ * Example usage:
+ *
+ * Implementations should gather and return relevant statistical information
+ * for the given account. Each statistic should be represented as an {@link AccountStats}
+ * object containing a label and value.
+ *
+ * @param accountId the unique identifier of the account
+ * @return a list of {@link AccountStats} objects representing various metrics
+ */
List
+ * This interface is useful when integrating with third-party services, payment gateways,
+ * or external APIs where entities need to store external identifiers for synchronization
+ * or cross-referencing purposes.
+ *
+ * Common use cases include:
+ *
+ * Example usage:
+ *
+ * This typically contains an ID or reference code from an external system.
+ *
+ * @return the external reference, or null if not set
+ */
String getExternalRef();
+ /**
+ * Sets the external reference identifier.
+ *
+ * @param externalRef the external reference to assign to this entity
+ */
void setExternalRef(String externalRef);
}
diff --git a/sources/api/src/main/java/tools/dynamia/modules/saas/api/SimpleAccountLocalStorage.java b/sources/api/src/main/java/tools/dynamia/modules/saas/api/SimpleAccountLocalStorage.java
index d2b9f1f..eadb858 100644
--- a/sources/api/src/main/java/tools/dynamia/modules/saas/api/SimpleAccountLocalStorage.java
+++ b/sources/api/src/main/java/tools/dynamia/modules/saas/api/SimpleAccountLocalStorage.java
@@ -32,7 +32,7 @@ class SimpleAccountLocalStorage implements AccountLocalStorage {
@Autowired
private AccountServiceAPI accountServiceAPI;
- private Map{@code
+ * AccountServiceAPI accountService = Containers.get().findObject(AccountServiceAPI.class);
+ * AccountDTO account = accountService.getCurrentAccount();
+ * if (accountService.hasFeature(account.getId(), "advanced-reports")) {
+ * // Enable advanced reporting features
+ * }
+ * }
+ *
+ * @author Mario Serrano Leones
+ */
public interface AccountServiceAPI {
+ /**
+ * Attribute name used to store the current account ID in the session or context.
+ */
String CURRENT_ACCOUNT_ID_ATTRIBUTE = "currentAccountId";
+ /**
+ * Retrieves the current status of the specified account.
+ *
+ * @param accountId the unique identifier of the account
+ * @return the current {@link AccountStatus} of the account
+ */
AccountStatus getAccountStatus(Long accountId);
+ /**
+ * Retrieves the complete account information for the specified account ID.
+ *
+ * @param accountId the unique identifier of the account
+ * @return an {@link AccountDTO} containing all account details
+ */
AccountDTO getAccount(Long accountId);
+ /**
+ * Returns the system account ID. The system account represents the main
+ * administrative account with special privileges.
+ *
+ * @return the unique identifier of the system account
+ */
Long getSystemAccountId();
+ /**
+ * Retrieves the ID of the account currently active in the session or execution context.
+ *
+ * @return the unique identifier of the current account, or null if no account is set
+ */
Long getCurrentAccountId();
+ /**
+ * Retrieves the complete information of the currently active account.
+ *
+ * @return an {@link AccountDTO} with the current account details
+ */
AccountDTO getCurrentAccount();
+ /**
+ * Sets the specified account as the current active account in the session or context.
+ * This is typically used for account switching in multi-tenant scenarios.
+ *
+ * @param accountId the unique identifier of the account to set as current
+ * @return the {@link AccountDTO} of the newly set current account
+ */
AccountDTO setCurrentAccount(Long accountId);
+ /**
+ * Updates the user count statistics for the specified account.
+ *
+ * @param accountId the unique identifier of the account
+ * @param users the total number of users registered in the account
+ * @param activedUsers the number of currently active users in the account
+ */
void updateAccountUsers(Long accountId, long users, long activedUsers);
+ /**
+ * Retrieves all payment records associated with the specified account.
+ *
+ * @param accountId the unique identifier of the account
+ * @return a list of {@link AccountPaymentDTO} objects representing payment history
+ */
List
+ *
+ * {@code
+ * @Component
+ * public class StorageCalculator implements AccountServiceQuantityCalculator {
+ * @Autowired
+ * private FileRepository fileRepository;
+ *
+ * public String getId() {
+ * return "storage-used";
+ * }
+ *
+ * public String getName() {
+ * return "Storage Used (MB)";
+ * }
+ *
+ * public long calculate(Long accountId) {
+ * return fileRepository.getTotalSizeByAccount(accountId) / (1024 * 1024);
+ * }
+ * }
+ * }
+ *
+ * @author Mario Serrano Leones
*/
public interface AccountServiceQuantityCalculator {
+ /**
+ * Returns the unique identifier for this quantity calculator.
+ * This ID is used to reference the calculator throughout the system.
+ *
+ * @return the calculator identifier (e.g., "storage-used", "api-calls")
+ */
String getId();
+ /**
+ * Returns the human-readable name of this quantity calculator.
+ * This name is typically displayed in reports and billing statements.
+ *
+ * @return the calculator display name
+ */
String getName();
+ /**
+ * Calculates the current quantity for the specified account.
+ *
+ *
+ * {@code
+ * @Component
+ * public class UserActivityStatsProvider implements AccountStatsProvider {
+ * @Autowired
+ * private UserRepository userRepository;
+ *
+ * public List
+ *
+ * @author Mario Serrano Leones
+ */
public interface AccountStatsProvider {
+ /**
+ * Retrieves a list of statistics for the specified account.
+ *
+ *
+ * {@code
+ * @Entity
+ * public class Account implements ExternalReferenceAware {
+ * @Column
+ * private String externalRef;
+ *
+ * public String getExternalRef() {
+ * return externalRef;
+ * }
+ *
+ * public void setExternalRef(String externalRef) {
+ * this.externalRef = externalRef;
+ * }
+ * }
+ * }
+ *
+ * @author Mario Serrano Leones
+ */
public interface ExternalReferenceAware {
+ /**
+ * Returns the external reference identifier.
+ *