This project is a back-end system for managing subscription-based services, such as software or media platforms. It enables businesses to offer subscription plans, process recurring payments, and manage user accounts effectively.
- Java: Main programming language.
- Spring Boot: Framework for building RESTful APIs.
- MySQL: Database for storing user accounts, subscription plans, and transactions.
- Spring Data JPA: ORM for database interactions.
- Spring Security: For authentication and authorization.
- Stripe/PayPal SDK: For payment processing and recurring billing.
- Swagger/OpenAPI: For API documentation.
- Layered Architecture (N-tier architecture)
- Main layers:
- Controller Layer: Handles HTTP requests.
- Service Layer: Implements business logic.
- Repository Layer: Manages database interactions.
- Security Layer: Ensures authentication and authorization.
com.saasplatform
│── controller # Handles HTTP requests
│── service # Contains business logic
│── repository # Database access
│── model # Entity classes representing database tables
│── dto # Data Transfer Objects for API requests/responses
│── config # Configuration files (Security, Database, etc.)
│── exception # Custom exception handling
│── util # Utility classes (e.g., email notifications, validators)
- Users: Stores customer and admin details (ID, name, email, role, etc.).
- Subscription Plans: Stores plan details (ID, name, price, billing cycle, features).
- Subscriptions: Tracks active and canceled subscriptions (ID, user, plan, status, start/end date).
- Payments: Manages transactions, invoices, and billing history.
- Usage Analytics: Tracks customer engagement, churn rate, and revenue.
- Admins can create, update, and remove subscription plans.
- Pricing, billing cycles, and plan features are configurable.
- Customers can register, log in, and manage their accounts.
- Secure payment processing through Stripe or PayPal.
- Users can subscribe to plans, upgrade, downgrade, or cancel subscriptions.
- Manage payment methods and billing preferences.
- Automated handling of recurring payments.
- Manage failed payments, retry logic, and account suspensions.
- Track customer engagement, revenue, and churn rate.
- Generate reports for business insights.
- Manage users, subscriptions, payments, and performance metrics.
- Monitor system activity and subscription trends.
- Java 17+
- MySQL Server
- Maven
- Clone the repository:
git clone https://github.com/stephenombuya/Subscription-Service-Management cd subscription-saas - Configure MySQL database in
application.properties:spring.datasource.url=jdbc:mysql://localhost:3306/saas_db spring.datasource.username=root spring.datasource.password=yourpassword
- Install dependencies:
mvn clean install
- Run the application:
mvn spring-boot:run
A production-grade Spring Boot backend system for managing subscription-based SaaS services. Built with Java 17, Spring Boot 3.2, MySQL, and Stripe.
| Feature | Description |
|---|---|
| JWT Authentication | Access tokens + refresh tokens with configurable expiry |
| Rate Limiting | Per-IP token-bucket rate limiting via Bucket4j |
| Role-Based Access | ADMIN and CUSTOMER roles with method-level security |
| Subscription Management | Subscribe, upgrade/downgrade, cancel, reactivate |
| Recurring Billing | Stripe integration with webhooks for payment events |
| Email Notifications | Async emails for verification, billing, renewals |
| Scheduled Jobs | Auto-expire subscriptions, send renewal reminders |
| Analytics Dashboard | Churn rate, MRR, engagement scores |
| Swagger UI | Full interactive API documentation |
| Comprehensive Testing | Unit + integration tests with H2 in-memory DB |
- Java 17 + Spring Boot 3.2
- Spring Security (JWT, method security)
- Spring Data JPA + MySQL 8
- Bucket4j (rate limiting)
- JJWT 0.12 (JWT)
- Stripe Java SDK (payments)
- SpringDoc OpenAPI 2 (Swagger)
- MapStruct + Lombok
- JUnit 5 + Mockito + H2 (tests)
com.saasplatform
├── controller/ # REST controllers (Auth, Plans, Subscriptions, Payments, Admin, Webhooks)
├── service/ # Business logic
├── repository/ # Spring Data JPA repositories
├── model/ # JPA entities (User, SubscriptionPlan, Subscription, Payment, UsageAnalytics)
├── dto/
│ ├── request/ # Incoming request DTOs (validated with Jakarta Bean Validation)
│ └── response/ # Outgoing response DTOs
├── security/ # JWT filter, rate limiting filter, UserDetailsService
├── config/ # SecurityConfig, OpenApiConfig, AppConfig
├── exception/ # Custom exceptions + GlobalExceptionHandler
└── util/ # DataSeeder (seeds admin + plans on startup)
- Java 17+
- MySQL 8+ running locally
- Maven 3.8+
- (Optional) Stripe account for real payment processing
git clone https://github.com/stephenombuya/Subscription-Service-Management
cd subscription-saasEdit src/main/resources/application.properties:
# Database
spring.datasource.url=jdbc:mysql://localhost:3306/saas_db?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=yourpassword
# JWT (change to a secure 256-bit base64 key in production)
app.jwt.secret=404E635266556A586E3272357538782F413F4428472B4B6250645367566B5970
app.jwt.expiration-ms=86400000 # 24 hours
app.jwt.refresh-expiration-ms=604800000 # 7 days
# Stripe
stripe.api.key=sk_test_YOUR_STRIPE_KEY
stripe.webhook.secret=whsec_YOUR_WEBHOOK_SECRET
# Email (Gmail example)
spring.mail.username=your-email@gmail.com
spring.mail.password=your-app-password
# Rate Limiting (100 requests/minute per IP)
app.rate-limit.capacity=100
app.rate-limit.refill-tokens=100
app.rate-limit.refill-duration-minutes=1mvn clean install
mvn spring-boot:runThe app will:
- Create the database schema automatically
- Seed a default admin account:
admin@saasplatform.com/Admin@123 - Seed 3 default subscription plans (Starter, Professional, Enterprise)
ddca1b9 (Initial commit: Subscription Service Management Backend)
http://localhost:8080/swagger-ui/index.html
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /register |
Public | Register new user |
| POST | /login |
Public | Login, returns JWT tokens |
| POST | /refresh-token |
Public | Refresh access token |
| GET | /verify-email?token= |
Public | Verify email address |
| POST | /forgot-password |
Public | Request password reset |
| POST | /reset-password |
Public | Reset password with token |
| POST | /change-password |
Bearer | Change password |
| POST | /logout |
Bearer | Invalidate refresh token |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | / |
Public | List all active plans |
| GET | /{id} |
Public | Get plan by ID |
| POST | / |
Admin | Create plan |
| PUT | /{id} |
Admin | Update plan |
| PATCH | /{id}/deactivate |
Admin | Deactivate plan |
| DELETE | /{id} |
Admin | Delete plan (no subscribers) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | / |
Bearer | Subscribe to a plan |
| GET | / |
Bearer | Get own subscriptions |
| GET | /{id} |
Bearer | Get subscription detail |
| PATCH | /{id}/change-plan |
Bearer | Upgrade / downgrade plan |
| PATCH | /{id}/cancel |
Bearer | Cancel subscription |
| PATCH | /{id}/reactivate |
Bearer | Reactivate subscription |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | / |
Bearer | Paginated payment history |
| GET | /{id} |
Bearer | Get payment detail |
| POST | /{id}/refund?amount= |
Bearer | Process refund |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /dashboard |
Admin | Stats, MRR, churn rate |
| GET | /users |
Admin | All users (paginated) |
| PATCH | /users/{id}/lock |
Admin | Lock user account |
| PATCH | /users/{id}/unlock |
Admin | Unlock user account |
| PATCH | /users/{id}/promote |
Admin | Promote to admin |
| GET | /subscriptions |
Admin | All subscriptions |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /stripe |
Public | Stripe webhook handler |
1. POST /api/v1/auth/register → Create account (email not yet verified)
2. Click link in email → GET /api/v1/auth/verify-email?token=...
3. POST /api/v1/auth/login → Returns { accessToken, refreshToken }
4. Use accessToken in header: → Authorization: Bearer <accessToken>
5. When expired: → POST /api/v1/auth/refresh-token
All endpoints (except /actuator) are rate-limited per IP address using a token bucket algorithm:
- Default: 100 requests per minute per IP
- Response headers:
X-Rate-Limit-Remaining - 429 Too Many Requests when exceeded
Configure in application.properties:
app.rate-limit.capacity=100
app.rate-limit.refill-tokens=100
app.rate-limit.refill-duration-minutes=1- Get your Stripe API keys from dashboard.stripe.com
- Set
stripe.api.keyinapplication.properties - For webhooks, use Stripe CLI locally:
stripe listen --forward-to localhost:8080/api/v1/webhooks/stripe
invoice.payment_succeeded— Activates subscriptioninvoice.payment_failed— Marks as past_due, suspends after 3 failurescustomer.subscription.deleted— Cancels subscriptioncustomer.subscription.updated— Syncs subscription status
# All tests
mvn test
# Only unit tests
mvn test -Dtest=*Test
# Only integration tests
mvn test -Dtest=*IntegrationTestTests use an H2 in-memory database and do not require MySQL or Stripe.
- BCrypt password hashing (strength 12)
- JWT with configurable expiry
- Refresh tokens stored in DB (single active token per user)
- Method-level
@PreAuthorizesecurity - CORS configured for cross-origin requests
- Account locking for admin control
- Email verification required before login
Contributions are welcome! Feel free to submit a pull request or open an issue.
This project is licensed under the MIT License.