Data Models
Relevant source files - controllers/subscription.controller.js - middlewares/error.middleware.js - models/subscription.model.js - models/user.model.js
The Subscription Tracker API utilizes Mongoose to define structured schemas for MongoDB. The data layer is centered around two primary entities: User and Subscription. These models enforce strict validation, handle data integrity through indexes, and implement automated lifecycle logic via middleware hooks.
User Model
The User model represents an authenticated entity within the system. It stores core identity information and serves as the parent entity for all subscription data.
Schema Definition
The schema is defined in models/user.model.js3-26
| Field | Type | Validation / Rules |
|---|---|---|
name |
String | Required, trim, 2-50 characters models/user.model.js4-10 |
email |
String | Required, unique, lowercase, regex-validated email format models/user.model.js11-18 |
password |
String | Required, minimum 6 characters models/user.model.js19-23 |
createdAt |
Date | Automatically generated by timestamps: truemodels/user.model.js25 |
updatedAt |
Date | Automatically generated by timestamps: truemodels/user.model.js25 |
Code Entity Association: User
The following diagram maps the logical user entity to the Mongoose implementation.
User Entity Mapping
[Flowchart Diagram]
Sources: models/user.model.js3-28
Subscription Model
The Subscription model is the core of the application, tracking financial commitments, billing cycles, and categories. It contains complex validation logic and a pre-save hook to manage dates automatically.
Schema Definition
The schema is defined in models/subscription.model.js3-68
| Field | Type | Validation / Enum Values |
|---|---|---|
name |
String | Required, trim, 2-100 characters models/subscription.model.js4-10 |
price |
Number | Required, minimum 0 models/subscription.model.js11-15 |
currency |
String | INR, USD, EUR, GBP (Default: INR) models/subscription.model.js16-20 |
frequency |
String | daily, weekly, monthly, yearlymodels/subscription.model.js21-24 |
category |
String | basic, standard, premium, enterprisemodels/subscription.model.js25-29 |
status |
String | active, inactive, canceled, pending, expiredmodels/subscription.model.js35-39 |
startDate |
Date | Required, must not be in the future models/subscription.model.js40-47 |
renewalDate |
Date | Must be after startDatemodels/subscription.model.js48-59 |
user |
ObjectId | Ref: User, Required, Indexed models/subscription.model.js60-65 |
Automated Lifecycle Logic (Pre-save Hook)
The model implements a Mongoose pre('save') hook to automate date calculations and status transitions before the document is persisted to MongoDB.
-
Renewal Date Calculation: If
renewalDateis not provided, the system calculates it by adding a specific number of days to thestartDatebased on thefrequencymodels/subscription.model.js71-81: -
daily: +1 day weekly: +7 daysmonthly: +30 daysyearly: +365 days- Auto-Expiration: If the
renewalDateis less than or equal to the current system time, thestatusis automatically set to'expired'models/subscription.model.js83
Data Flow: Subscription Creation
The following diagram illustrates how the model interacts with the controller and the database during the creation process.
Subscription Creation Flow
sequenceDiagram
participant C as "subscription.controller.js"
participant M as "subscription.model.js (Mongoose)"
participant DB as "MongoDB"
C->>M: "Subscription.create(req.body)"
Note over M: "pre('save') hook triggered"
M->>M: "Calculate renewalDate"
M->>M: "Check if status == 'expired'"
M->>DB: "Persist Document"
DB-->>C: "Return Saved Document"
Sources: models/subscription.model.js70-84controllers/subscription.controller.js5-10
Indexing and Performance
To ensure efficient querying, especially for user-specific data and upcoming reminders, the following indexes are implemented:
- User Foreign Key: The
userfield in theSubscriptionmodel is indexed to optimizeSubscription.find({ user: userId })calls models/subscription.model.js64 - Unique Email: The
emailfield in theUsermodel is unique, preventing duplicate registrations and speeding up authentication lookups models/user.model.js14
Error Handling for Models
The system uses a global errorMiddleware to catch and format Mongoose-specific errors:
- CastError: Handled when an invalid ObjectId is passed to a query middlewares/error.middleware.js8-13
- Duplicate Key (11000): Handled when a unique constraint (like email) is violated middlewares/error.middleware.js15-19
- ValidationError: Formats the
requiredandvalidatemessages defined in the schemas into a readable array for the client middlewares/error.middleware.js21-26
Sources: middlewares/error.middleware.js1-37models/subscription.model.js86-88models/user.model.js28-30