Schema Design
CycleData:
{
"id": { "type": "String", "description": "Primary key, auto-generated by MongoDB" },
"mdn": { "type": "String", "description": "The phone number of a customer" },
"startDate": { "type": "Date", "description": "The start date of a billing cycle" },
"endDate": { "type": "Date", "description": "The end date of a billing cycle" },
"userId": { "type": "String", "description": "Foreign key to the id of the user collection" }
}
Design Considerations:
Scalability: Considering 10 million documents, the schema is kept simple and indexable on `mdn`, `startDate`, and `userId` to enhance query performance.
Data Integrity: The `userId` field ensures a relationship with the User collection to maintain data integrity.
UserData:
{
"id": { "type": "String", "description": "Primary key, auto-generated by MongoDB" },
"firstName": { "type": "String", "description": "First name of the customer" },
"lastName": { "type": "String", "description": "Last name of the customer" },
"email": { "type": "String", "description": "Email of the customer" },
"password": { "type": "String", "description": "Used for the login to our system" },
"createdAt": { "type": "Date", "description": "The date when the user was created" },
"lastLoggedIn": { "type": "Date", "description": "The date when the user last logged in" },
"authKey": { "type": "String", "description": "Authentication key for the user" },
"activeUser": { "type": "Boolean", "description": "Status of the user's account" }
}
Design Considerations:
Security: Password is stored securely (hashed) and additional fields like `authKey` are included for authentication purposes.
User Activity Tracking: Fields like `createdAt` and `lastLoggedIn` are added to monitor user activity and for auditing purposes.
UsageData:
{
"id": { "type": "String", "description": "Primary key, auto-generated by MongoDB" },
"mdn": { "type": "String", "description": "The phone number associated with the usage" },
"userId": { "type": "String", "description": "The customer who owns this phone number, foreign key to user collection" },
"cycleId": { "type": "String", "description": "The billing cycle ID associated with this usage" },
"usageDate": { "type": "Date", "description": "The date of the usage" },
"usedInMb": { "type": "Number", "description": "The usage of that day in megabytes" }
}
Design Considerations:
Efficiency: Indexes on `mdn`, `userId`, and `usageDate` to facilitate fast retrieval of usage data.
Referential Integrity: Includes `cycleId` to link usage to a specific billing cycle, ensuring data consistency across collections.
Scalability: Designed to handle 50 million documents with efficient indexing and storage.
The schema design focuses on scalability, efficiency, and data integrity. By indexing key fields and maintaining referential integrity, the design supports efficient querying and data consistency. Fields for user activity tracking and security considerations are included to ensure a robust and secure system.
This schema can handle the large volume of documents anticipated in each collection while providing the necessary relationships and constraints to ensure data reliability and performance.
The service design depicted in the image follows a well-structured Spring Boot application using Docker for containerization. Here’s an analysis of the thought process and pros of this design:
The project follows a layered architecture, which is a common design pattern in enterprise applications. The codebase is organized into several packages:
- Controller Layer: Handles HTTP requests and responses. This layer acts as the entry point to the application’s functionalities, ensuring that the web-related logic is separated from the business logic.
- DTO (Data Transfer Object) Layer: Manages data transfer between layers. DTOs decouple internal data structures from the external API representation, enhancing flexibility and reducing the risk of exposing internal structures.
- Entity Layer: Contains domain models or entities that represent the data in the application. These entities are typically mapped to database tables, ensuring a clear representation of the data structure.
- Exception Handling: Centralizes error management with custom exceptions and global handlers. This ensures consistent error handling across the application, making it easier to manage and debug errors.
- Repository Layer: Manages data access using Spring Data MongoDB repositories. This layer abstracts the data access logic, making the application easier to maintain and modify.
- Service Layer: Contains the business logic. Services interact with repositories to fetch and manipulate data, and are called by controllers to perform specific operations. This separation ensures that business logic is not mixed with web-related code.
- Testing: The `test` directory includes unit tests for controllers, ensuring that the application’s endpoints behave as expected. This helps in maintaining the quality and reliability of the application.
- Containerization: The presence of a `Dockerfile` and `docker-compose.yml` indicates that the application is containerized using Docker. Containerization ensures that the application can run consistently across different environments, simplifying the deployment process.
- Separation of Concerns: By following a layered architecture, the application achieves a clear separation of concerns, making it easier to manage, test, and scale. Each layer is responsible for a specific part of the application, which enhances maintainability.
- Scalability: Using Spring Boot and MongoDB allows the application to scale efficiently. MongoDB’s horizontal scaling capabilities complement the application’s needs, making it suitable for handling large volumes of data.
- Testability: The structure supports extensive testing. The presence of unit tests for controllers indicates a focus on ensuring the correctness of the application’s functionalities. This helps in identifying issues early in the development process.
- Containerization: Using Docker ensures that the application can run in any environment without compatibility issues. This improves the development workflow and makes the deployment process more reliable.
- Modularity: The modular design allows for individual components to be developed, tested, and deployed independently. This accelerates development and deployment cycles, enabling teams to work on different parts of the application simultaneously.
The service design follows best practices in software architecture, focusing on separation of concerns, maintainability, scalability, testability, and deployability. This approach ensures that the application is robust, easy to maintain, and scalable, providing a strong foundation for future development and enhancements.