Case Study 1: Namespaced Dashboard Design
This case study explores the design and architecture of a namespaced dashboard that supports multiple domains. The goal is to create a flexible and scalable solution that can handle the unique requirements of each domain while maintaining a cohesive user experience.
Table of Contents
Introduction
One and half years ago, I was tasked with designing a dashboard (Frontend only) that could support multiple domains. The challenge was to create a system that could easily adapt to the needs of different teams while providing a consistent user experience. This case study outlines the approach taken to achieve this goal, including the architectural decisions made and the technologies used. The dashboard was designed to be modular and extensible, allowing for the addition of new features and domains without significant rework. The key focus was on namespacing, which ensures that each domain operates independently while still being part of a larger system. The design also emphasizes user experience, ensuring that each domain can provide a tailored interface that meets the specific needs of its users. This case study will detail the architectural decisions made, the technologies used, and the lessons learned during the development process.
Main Content
Key Considerations
When designing a namespaced dashboard, several key considerations must be addressed:
- Scalability: The dashboard should be able to scale with the addition of new domains without requiring significant rework.
- User Experience: Each domain may have different user expectations, so the design must be flexible enough to accommodate these variations.
Subsection
Architectural Decisions
To achieve the goals outlined above, the following architectural decisions were made:
- Modular Design: The dashboard is built using a modular architecture, allowing for easy addition of new features and domains.
- Namespacing: Each domain is treated as a separate namespace, ensuring that data and functionality do not conflict across domains.
- Configuration Management: A centralized configuration management system is implemented to handle domain-specific settings and preferences.
Technologies Used
The following technologies were chosen to implement the dashboard:
- Frontend Framework: React was selected for its component-based architecture, which aligns well with the modular design approach.
- State Management: React Context API is selected as primary state management solution, allowing for easy sharing of state across components without the need for complex state management libraries.
- API Integration: Axios is used for making API calls and TanStack Query is used for data fetching and caching, providing a robust solution for handling asynchronous data.
- Routing: React Router is used to handle navigation between different domains and sections of the dashboard.
- Styling: Tailwind CSS is used for styling, providing a utility-first approach that allows for rapid development and consistent design across domains.
- Testing: Cypress is used for end-to-end testing, ensuring that the dashboard functions correctly across different domains and user scenarios.
- Build Tools: Vite is used as the build tool, providing fast development and build times with modern JavaScript features.
User Experience Design
The user experience design focuses on creating a consistent and intuitive interface across all domains. Key aspects include:
- Responsive Design: The dashboard is designed to be fully responsive, ensuring a seamless experience across devices.
- Customizable Themes: Each domain can have its own theme, allowing for branding and personalization while maintaining a consistent overall layout.
Lessons Learned
Throughout the development process, several lessons were learned:
Importance of Namespacing: Proper namespacing is crucial for preventing conflicts and ensuring that each domain can operate independently.
- Namespacing is controlled via environment variables, which allows for easy configuration and management of different domains. This approach ensures that each domain can have its own set of configurations without affecting others. For example, the
VITE_APP_DOMAIN
environment variable is used to determine the current domain context, allowing the application to load the appropriate resources and configurations dynamically. - Namespacing also helps in organizing code better, making it easier to navigate, maintain and extend the codebase. Here’s an example of how namespacing is structured in the codebase:
// Example of namespacing in the codebase
|- src
|- domains
|- app (default namespace)
|- pages
|- components
|- domainA
|- pages
|- components
|- domainB
|- pages
|- components
|- router
|- index.ts
|- namespaced-router.ts
|- config
|- app
|- domainA
|- domainB
|- vendor
|- modules
|- services
|- utils
|- Entry.ts
Modular Architecture Benefits: A modular architecture not only simplifies development but also makes it easier to maintain and extend the dashboard over time.
- Modular architecture allows teams to work on different parts of the dashboard independently, reducing the risk of conflicts and enabling faster development cycles. Here’s an example of how a modular component structure might look:
// Example of a modular component structure
|- packages
|- other-frontend-framework (e.g., Vue, Angular. This is our initial thought of modular architecture to support multiple frontend design systems)
|- react-ui
|- other-css-framework (e.g., Bootstrap, Material UI. This is our initial thought of modular architecture to support multiple frontend design systems)
|- tailwind
|- components
|- Button
|- Button.tsx
|- Card
|- Card.tsx
With this structure, each component can be developed, tested, and deployed independently, allowing for greater flexibility and faster iteration. For advanced use cases, we did implement a versioning system for the components by utilising TypeScript, allowing us to maintain backward compatibility while introducing new features. This is particularly useful in a multi-domain environment where different domains may rely on different versions of the same component. (Though, this is not a common practice, it can be beneficial in certain scenarios and done it via package manager like npm or yarn)
User Feedback is Essential: Regular user feedback helped refine the design and ensure that the dashboard met the needs of its users.
- Engaging with users early and often can lead to valuable insights that shape the design and functionality of the dashboard. User testing sessions were conducted to gather feedback on usability, which informed several design iterations.
Documentation: Maintaining clear documentation throughout the development process is essential for onboarding new team members and ensuring that the architecture is understood by all stakeholders.
- Comprehensive documentation helps in maintaining the codebase and ensures that new developers can quickly get up to speed. This includes architectural decisions, naming conventions, and usage guidelines for components and modules.
- We are glad to have a documentation system in place that allows us to easily update and share information with the team. This action indirectly enabled the team to onboard "AI assistant" to help with code generation and documentation updates, further enhancing productivity and stability.
Other Considerations: Feature flags and trunk based development were also implemented to allow for safe deployments and testing of new features without affecting the production environment.
- Feature flags allow for toggling features on and off without deploying new code, enabling safer testing and gradual rollouts. This is particularly useful in a multi-domain environment where different domains may require different features at different times.
- Trunk based development encourages small, frequent commits to the main branch, reducing the complexity of merges and ensuring that the codebase remains stable.
Conclusion
The solution has been successfully implemented and lasted for over a year, with multiple domains running smoothly. The modular architecture and namespacing approach have proven to be effective in managing complexity and ensuring a consistent user experience across different domains.
The design and architecture of a namespaced dashboard that supports multiple domains is a complex but rewarding challenge. By focusing on modularity, namespacing, and user experience, it is possible to create a flexible and scalable solution that meets the needs of various teams and users.
This case study highlights the importance of careful planning, user feedback, and the use of modern technologies to achieve a successful implementation. The lessons learned throughout the process will inform future projects and contribute to the ongoing evolution of the dashboard.
Impact
The impact of this design and architecture approach has been significant:
- Increased Efficiency: Teams can now work independently on their respective domains, leading to faster development cycles and reduced bottlenecks.
- Improved Collaboration: The clear separation of concerns and modular design has facilitated better collaboration between teams, as they can work on their components without interfering with each other's work.
- Enhanced User Experience: By focusing on user feedback and iterative design, the dashboard has evolved to better meet the needs of its users, resulting in higher satisfaction and engagement.