spring-petclinic/README.md
2026-02-08 18:07:59 +05:30

5.8 KiB

Prerequisites Java 17+ Docker (for PostgreSQL) Maven

  1. Start PostgreSQL

    docker run --name petclinic-ff
    -e POSTGRES_DB=petclinic
    -e POSTGRES_USER=petclinic
    -e POSTGRES_PASSWORD=petclinic
    -p 5432:5432
    -d postgres:15

  2. Run Application ./mvnw spring-boot:run -Dspring.profiles.active=postgres

URLs: App: http://localhost:8080 Flags API: http://localhost:8080/api/flags H2 Console: http://localhost:8080/h2-console Database: localhost:5432/petclinic (user: petclinic, pass: petclinic)

Feature Flags Implemented Flag Key Controls Controller Method Strategy Examples add-pet Add New Pet form PetController.initNewPetForm() Global OFF/ON, Percentage add-visit Add Visit form VisitController.processNewVisit() Percentage rollout (50%) owner-search Owner search OwnerController.processFindForm() Blacklist/Whitelist users

Behavior when OFF: Returns 403 Forbidden → redirects to /oups error page.

Feature Flag Strategies (Advanced) Strategy Configuration Logic GLOBAL {"enabled": true} Everyone ON/OFF BLACKLIST {"users":["test@example.com"]} Blocks listed users WHITELIST {"users":["admin@company.com"]} Only listed users PERCENTAGE {"percentage":25} 25% of users randomly

Feature Flag Management API GET /api/flags # List all flags GET /api/flags/{key} # Get specific flag POST /api/flags # Create flag PUT /api/flags/{key} # Update flag
DELETE /api/flags/{key} # Delete flag

Example API Calls

  1. Global OFF (blocks everyone): curl -X POST http://localhost:8080/api/flags
    -H "Content-Type: application/json"
    -d '{ "flagKey": "add-pet", "name": "Add New Pet", "enabled": false, "strategyType": "GLOBAL" }'

  2. Percentage Rollout (50% users): curl -X POST http://localhost:8080/api/flags
    -H "Content-Type: application/json"
    -d '{ "flagKey": "add-visit", "name": "Add Visit", "enabled": true, "strategyType": "PERCENTAGE", "strategyValue": "{"percentage":50}" }'

  3. Blacklist specific user: curl -X POST http://localhost:8080/api/flags
    -H "Content-Type: application/json"
    -d '{ "flagKey": "owner-search", "name": "Owner Search", "enabled": true, "strategyType": "BLACKLIST", "strategyValue": "{"users":["test@example.com"]}" }'

Test with user email: Add ?email=test@example.com to flagged URLs.

Architecture Overview

┌─────────────────┐    ┌──────────────────┐    ┌─────────────┐
│   PetClinic     │◄──►│FeatureFlagService│◄──►│ PostgreSQL  │
│   Controllers   │    │  + Strategies    │    │  feature_   │
│                 │    │                  │    │  flags table│
└─────────────────┘    └──────────────────┘    └─────────────┘
│                      ▲
└──────────┬───────────┘
           │
┌─────────────────┐
│  @FeatureFlag   │  ← Custom Annotation + AOP
│    Aspect       │
└─────────────────┘

Key Implementation Features Custom-built (No FF4J/Togglz) Database persistence (survives restarts) 4 Strategies: Global/Blacklist/Whitelist/Percentage Custom Annotation @FeatureFlag("add-pet") + AOP Helper function: featureFlagService.isFeatureEnabled(flagKey, userEmail) Edge cases: Fail-open, JSON parsing errors, missing flags default ON No authentication on flag API (per requirements)

Code Locations src/main/java/org/springframework/samples/petclinic/model/ ├── FeatureFlag.java # Entity

src/main/java/org/springframework/samples/petclinic/system/
├── FeatureFlag.java              #  @FeatureFlag annotation

src/main/java/org/springframework/samples/petclinic/service/
├── FeatureFlagService.java       # Core logic + strategies

src/main/java/org/springframework/samples/petclinic/repository/
├── FeatureFlagRepository.java    # JPA

src/main/java/org/springframework/samples/petclinic/controller/
├── FeatureFlagController.java    # REST API

src/main/java/org/springframework/samples/petclinic/aop/
└── FeatureFlagAspect.java        # AOP interceptor

Controllers with flags:
├── PetController.java           # @FeatureFlag("add-pet")
├── VisitController.java         # @FeatureFlag("add-visit")  
└── OwnerController.java         # @FeatureFlag("owner-search")

Demo Script 1. App running normally → All 3 features work 2. Create Global OFF flag → Add Pet → 403 Forbidden 3. Percentage flag → Add Visit works ~50% time (random) 4. Blacklist → Owner search blocked for test@example.com 5. Database → Flags persist after restart 6. CRUD → Create/Update/Delete via API

Troubleshooting

Issue	                Solution
AOP not working	        Add @EnableAspectJAutoProxy to PetClinicApplication.java
JSON parsing fails	    Check strategyValue format
Flags not persisting	Verify Postgres connection
Package not found	    Use org.springframework.samples.petclinic.system

Original Documentation For original PetClinic features, see Spring Petclinic.

🎥 Loom Video Walkthrough: [Insert Loom Link Here]

Fully functional with advanced feature flag strategies, custom annotation, and production-ready code!