In a large pot, heat the olive oil over medium heat. Add chopped onions and cook for 3-4 minutes until soft and translucent. Stir in the garlic, carrots, and celery and sauté for another 5 minutes until fragrant and slightly tender.
Sprinkle in the dried rosemary, thyme, and red pepper flakes (if using). Stir well to coat the vegetables and let the herbs bloom for about 1 minute.
Pour in the cannellini beans, vegetable broth, and water. Stir everything together, bring to a gentle boil, then reduce heat and let it simmer uncovered for 20 minutes to allow flavors to develop.
Using an immersion blender, blend part of the soup directly in the pot to create a creamy texture while still keeping some whole beans and veggies intact. If using a standard blender, remove 2 cups of soup, blend until smooth, and stir it back in.
Stir in the chopped kale or spinach and simmer for another 5 minutes until wilted and tender. Season with salt, pepper, and a squeeze of fresh lemon juice to brighten the flavors.
Ladle the soup into bowls, top with fresh parsley or basil, and a sprinkle of Parmesan if desired. Serve with crusty bread or a side salad for a complete meal.