Project Architecture & Design
The CLI Inventory Management System (IMS) integrates every concept from Modules 1–11. Architecture: a `Product` hierarchy (physical/digital/perishable) uses OOP and polymorphism. `Inventory<T>` is a class template wrapping STL containers. `FileStore` handles JSON-like CSV persistence with `std::filesystem`. All operations are exception-safe. The system uses `unique_ptr` for sole ownership, `optional` for nullable results, lambdas for filtering, and the Rule of 5 for the custom string buffer used in reports.
Architecture — Class Diagram & Module Integration Map
// ══════════════════════════════════════════════════════════════
// CLI Inventory Management System — Architecture Overview
// ══════════════════════════════════════════════════════════════
//
// ┌──────────────────────────────────────────────────────┐
// │ main.cpp │
// │ CLI loop → parses commands → calls IMS API │
// └────────────────┬─────────────────────────────────────┘
// │
// ┌────────────────▼─────────────────────────────────────┐
// │ InventorySystem │
// │ owns: Inventory<Product> │
// │ FileStore │
// │ ReportBuilder │
// └────────────────┬─────────────────────────────────────┘
// │
// ┌────────────────▼─────────────────────────────────────┐
// │ Inventory<T> (class template) │
// │ vector<unique_ptr<T>> — main storage │
// │ unordered_map<int,T*> — O(1) id lookup │
// │ map<string,vector<int>>— category index │
// └────────────────┬─────────────────────────────────────┘
// │
// ┌────────────────▼─────────────────────────────────────┐
// │ Product (abstract base class) │
// │ + id_, name_, price_, quantity_ [private] │
// │ + category() [pure virtual] │
// │ + description() [pure virtual] │
// │ + apply_discount() [virtual — default impl] │
// │ + serialize() [pure virtual] │
// │ │
// │ ┌───────────┐ ┌───────────────┐ ┌─────────────┐ │
// │ │ Physical │ │ Digital │ │ Perishable │ │
// │ │ weight_ │ │ download_url_│ │ expiry_ │ │
// │ │ supplier_│ │ license_key_ │ │ storage_ │ │
// │ └───────────┘ └───────────────┘ └─────────────┘ │
// └──────────────────────────────────────────────────────┘
//
// ┌──────────────────────────────────────────────────────┐
// │ FileStore │
// │ read_csv() / write_csv() using std::fstream │
// │ backup on write failure (strong guarantee) │
// │ std::filesystem for directory management │
// └──────────────────────────────────────────────────────┘
//
// ┌──────────────────────────────────────────────────────┐
// │ ReportBuilder │
// │ lambdas for filter/sort/aggregate │
// │ string_view parameters │
// │ std::optional for "not found" results │
// └──────────────────────────────────────────────────────┘
//
// ── Modules integrated ──────────────────────────────────────
// M1: namespaces, const, enum class, CMake
// M2: range-for, functions, default args
// M3: OOP — class, MIL, const methods, static counter
// M4: Polymorphism — virtual, override, pure virtual
// M5: unique_ptr sole ownership, shared_ptr for reports
// M6: Operator overloading (<, ==), const-correct API
// M7: Inventory<T> class template, make_inventory factory
// M8: vector/map/unordered_map, STL algorithms, string_view
// M9: Lambdas for filter/sort, optional<Product*>, variant
// M10: Custom exceptions, fstream/filesystem, CSV parser
// M11: Rule of 5 for ReportBuffer, constexpr constants
// ── Project file structure ────────────────────────────────────
// ims/
// ├── CMakeLists.txt
// ├── include/
// │ ├── product.h — Product base + PhysicalProduct etc.
// │ ├── inventory.h — Inventory<T> class template
// │ ├── filestore.h — CSV persistence
// │ ├── report_builder.h — filtering and aggregation
// │ └── exceptions.h — custom exception hierarchy
// ├── src/
// │ ├── product.cpp
// │ ├── filestore.cpp
// │ ├── report_builder.cpp
// │ └── main.cpp
// └── data/
// └── inventory.csv
// ── CMakeLists.txt ───────────────────────────────────────────
/*
cmake_minimum_required(VERSION 3.16)
project(InventoryMS CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Warnings
add_compile_options(-Wall -Wextra -Wpedantic)
# AddressSanitizer in Debug
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(-fsanitize=address,undefined)
add_link_options(-fsanitize=address,undefined)
endif()
file(GLOB_RECURSE SOURCES "src/*.cpp")
add_executable(ims ${SOURCES})
target_include_directories(ims PRIVATE include)
*/Design Decisions
- **Sole ownership with `unique_ptr`** — `Inventory<T>` stores `vector<unique_ptr<T>>`. Raw pointers in `unordered_map` and `map` indices are non-owning observers — they never delete. This models a valid observation pattern: the vector holds ownership, indices hold views. When a product is removed from the vector, both indices must be updated.
- **Abstract `Product` base** — pure virtual prevents Product instantiation. The serialize()/deserialize() interface makes the class hierarchy extensible — adding `SubscriptionProduct` only requires inheriting Product and implementing three pure virtuals. The FileStore doesn't need to know about new subclasses if it uses the virtual serialize() API.
- **Template `Inventory<T>` for future flexibility** — while current use is `Inventory<Product>`, the template design allows `Inventory<Customer>` or `Inventory<Order>` with the same indexing, sorting, and filtering infrastructure without code duplication (Rule of 0 — the template handles all specials).
Tip
Tip
Practice Project Architecture Design in small, isolated examples before integrating into larger projects. Breaking concepts into small experiments builds genuine understanding faster than reading alone.
The four pillars of Object-Oriented Programming in C++
Practice Task
Note
Practice Task — (1) Write a working example of Project Architecture Design from scratch without looking at notes. (2) Modify it to handle an edge case (empty input, null value, or error state). (3) Share your solution in the Priygop community for feedback.
Quick Quiz
Common Mistake
Warning
A common mistake with Project Architecture Design is skipping edge case testing — empty inputs, null values, and unexpected data types. Always validate boundary conditions to write robust, production-ready cpp code.
Key Takeaways
- The CLI Inventory Management System (IMS) integrates every concept from Modules 1–11.
- *Sole ownership with `unique_ptr`** — `Inventory<T>` stores `vector<unique_ptr<T>>`. Raw pointers in `unordered_map` and `map` indices are non-owning observers — they never delete. This models a valid observation pattern: the vector holds ownership, indices hold views. When a product is removed from the vector, both indices must be updated.
- *Abstract `Product` base** — pure virtual prevents Product instantiation. The serialize()/deserialize() interface makes the class hierarchy extensible — adding `SubscriptionProduct` only requires inheriting Product and implementing three pure virtuals. The FileStore doesn't need to know about new subclasses if it uses the virtual serialize() API.
- *Template `Inventory<T>` for future flexibility** — while current use is `Inventory<Product>`, the template design allows `Inventory<Customer>` or `Inventory<Order>` with the same indexing, sorting, and filtering infrastructure without code duplication (Rule of 0 — the template handles all specials).