Skip to main content

Data Models


Module: Lens Version: 1.0.0-RELEASE Last Updated: October 25, 2025


Overview​

Total DTOs: 165 data transfer objects Database Tables: 3 primary tables (Snowflake) + 5 collections (MongoDB) + 7 tables (MySQL)


DTO Categories​

1. Cost Summary DTOs (dto/AwsVsActualCost/)​

CostSummaryDTO​

public class CostSummaryDTO {
private String service;
private Double awsCost;
private Double actualCost;
private Double variance;
private Double variancePercent;
private Double savingsRealized;
}

CostDetailDTO​

public class CostDetailDTO {
private String resourceId;
private String instanceType;
private String region;
private Double hourlyRate;
private Integer hours;
private Double totalCost;
}

2. Billing Console DTOs (dto/billingconsole/)​

BillingConsoleDTO​

public class BillingConsoleDTO {
private Double monthToDateCost;
private Double projectedMonthEndCost;
private Double budget;
private Double budgetUtilizationPercent;
private Integer daysElapsed;
private Integer daysRemaining;
private `List<ServiceCostDTO>` topServices;
private AlertDTO alert;
}

3. Reservation DTOs (dto/reservation/)​

ReservationResponseDTO​

public class ReservationResponseDTO {
private Integer totalReservations;
private Double totalMonthlyCost;
private Double totalSavings;
private `List<ReservationDTO>` reservations;
}

ReservationDTO​

public class ReservationDTO {
private String reservationId;
private String instanceType;
private String service; // EC2, RDS, ElastiCache
private String region;
private String availabilityZone;
private Integer instanceCount;
private String offeringClass; // standard, convertible
private String offeringType; // No Upfront, Partial, All Upfront
private String term; // 1yr, 3yr
private LocalDate startDate;
private LocalDate endDate;
private Integer daysUntilExpiry;
private Double utilizationPercent;
private Double monthlySavings;
}

4. RI Utilization DTOs (dto/reservation/)​

RiUtilizationDTO​

public class RiUtilizationDTO {
private String reservationId;
private String instanceType;
private Integer riHoursPurchased;
private Integer riHoursUsed;
private Double utilizationPercent;
private Integer unusedHours;
private Double wastedCost;
private AlertDTO alert; // If utilization \<80%
}

5. Cost Breakup DTOs (dto/costbreakup/)​

Structure: Each AWS service category has dedicated DTOs

DatabaseCostBreakupDTO​

public class DatabaseCostBreakupDTO {
private Double totalCost;
private RdsCostDTO rds;
private DynamoDbCostDTO dynamodb;
private ElastiCacheCostDTO elasticache;
private RedshiftCostDTO redshift;
}

S3CostBreakupDTO​

public class S3CostBreakupDTO {
private Double totalCost;
private `List<StorageClassCostDTO>` storageByClass;
private RequestCostDTO requestCosts;
private DataTransferCostDTO dataTransferCosts;
private `List<BucketCostDTO>` topBuckets;
private LifecyclePolicyEffectivenessDTO lifecyclePolicyEffectiveness;
}

6. CUDOS DTOs (dto/cudos/)​

S3DashboardDTO​

public class S3DashboardDTO {
private Double totalCost;
private Long totalStorageGB;
private `List<StorageClassDTO>` storageByClass;
private RequestCostsDTO requestCosts;
private DataTransferCostsDTO dataTransferCosts;
private `List<BucketDTO>` topBuckets;
}

7. Recommendation DTOs (dto/recommendation/)​

RecommendationDTO​

public class RecommendationDTO {
private String id;
private String type; // EC2_RIGHTSIZING, RI_PURCHASE, IDLE_RESOURCES
private String category; // COMPUTE, STORAGE, DATABASE, COMMITMENT, WASTE
private String severity; // HIGH, MEDIUM, LOW
private String title;
private String description;
private `List<ResourceDTO>` resources;
private Double totalMonthlySavings;
private Double annualSavings;
private String implementationDifficulty; // EASY, MEDIUM, HARD
private String riskLevel; // LOW, MEDIUM, HIGH
}

8. Alert DTOs (dto/costalert/)​

CostAlertDTO​

public class CostAlertDTO {
private String alertId;
private String alertName;
private String alertType; // BUDGET_THRESHOLD, ANOMALY
private `List<ThresholdDTO>` thresholds;
private Double budget;
private Boolean enabled;
}

9. Generic Request DTO​

GenericRequestDTO​

public class GenericRequestDTO {
@NotNull(message = "Customer ID required")
private String customerId;

@NotNull(message = "Account ID required")
private String accountId;

@NotNull(message = "Start date required")
@PastOrPresent(message = "Start date cannot be future")
private LocalDate startDate;

@NotNull(message = "End date required")
private LocalDate endDate;

@AssertTrue(message = "Date range cannot exceed 365 days")
public boolean isValidDateRange() {
return ChronoUnit.DAYS.between(startDate, endDate) <= 365;
}
}

Database Schemas​

Snowflake Tables​

COST_DAILY​

CREATE TABLE COST_DAILY (
DATE DATE NOT NULL,
ACCOUNT_ID VARCHAR(20) NOT NULL,
SERVICE VARCHAR(100) NOT NULL,
REGION VARCHAR(50),
USAGE_TYPE VARCHAR(200),
COST NUMBER(18,2),
USAGE_QUANTITY NUMBER(18,6),
CURRENCY VARCHAR(3) DEFAULT 'USD',
TAGS VARIANT, -- JSON column for AWS tags
PRIMARY KEY (DATE, ACCOUNT_ID, SERVICE, REGION, USAGE_TYPE)
) CLUSTER BY (DATE);

COST_HOURLY​

CREATE TABLE COST_HOURLY (
TIMESTAMP TIMESTAMP_NTZ NOT NULL,
ACCOUNT_ID VARCHAR(20) NOT NULL,
SERVICE VARCHAR(100),
REGION VARCHAR(50),
RESOURCE_ID VARCHAR(500),
COST NUMBER(18,6),
USAGE_QUANTITY NUMBER(18,6),
PRIMARY KEY (TIMESTAMP, ACCOUNT_ID, RESOURCE_ID)
) CLUSTER BY (TIMESTAMP);

RI_UTILIZATION​

CREATE TABLE RI_UTILIZATION (
DATE DATE NOT NULL,
ACCOUNT_ID VARCHAR(20),
RESERVATION_ID VARCHAR(100),
INSTANCE_TYPE VARCHAR(50),
REGION VARCHAR(50),
RI_HOURS_PURCHASED NUMBER(18,2),
RI_HOURS_USED NUMBER(18,2),
UTILIZATION_PCT NUMBER(5,2),
UNUSED_COST NUMBER(18,2),
PRIMARY KEY (DATE, RESERVATION_ID)
) CLUSTER BY (DATE);

MongoDB Collections​

saved_reports​

{
"_id": ObjectId("..."),
"reportId": "RPT-2024-001",
"customerId": "CUST-123",
"reportName": "Monthly EC2 Costs",
"reportType": "COST_SUMMARY",
"filters": {
"startDate": "2024-01-01",
"endDate": "2024-01-31",
"accounts": ["123456789012"],
"services": ["EC2"]
},
"createdAt": ISODate("2024-02-01T10:30:00Z"),
"shared": false
}

Indexes:

db.saved_reports.createIndex({ "customerId": 1, "reportType": 1 });
db.saved_reports.createIndex({ "reportId": 1 }, { unique: true });

filter_metadata​

{
"_id": ObjectId("..."),
"customerId": "CUST-123",
"filterType": "SERVICE",
"values": ["EC2", "RDS", "S3"],
"lastUpdated": ISODate("2024-02-15T08:00:00Z"),
"ttl": ISODate("2024-02-15T09:00:00Z")
}

MySQL Tables​

accounts​

CREATE TABLE accounts (
account_id VARCHAR(20) PRIMARY KEY,
customer_id VARCHAR(36) NOT NULL,
account_name VARCHAR(255),
account_type ENUM('PAYER', 'LINKED'),
status ENUM('ACTIVE', 'SUSPENDED'),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_customer (customer_id)
) ENGINE=InnoDB;

billing_metadata​

CREATE TABLE billing_metadata (
billing_id VARCHAR(36) PRIMARY KEY,
customer_id VARCHAR(36) NOT NULL,
billing_month DATE NOT NULL,
total_cost DECIMAL(18,2),
invoice_generated BOOLEAN DEFAULT FALSE,
UNIQUE KEY unique_customer_month (customer_id, billing_month)
) ENGINE=InnoDB;

Data Mapping Examples​

Snowflake → DTO Mapping​

Example: Mapping COST_DAILY to CostSummaryDTO

public class AwsVsActualCostDaoImpl implements AwsVsActualCostDao {

private final RowMapper<CostSummaryDTO> costSummaryRowMapper = (rs, rowNum) -> {
CostSummaryDTO dto = new CostSummaryDTO();
dto.setService(rs.getString("SERVICE"));
dto.setAwsCost(rs.getDouble("AWS_COST"));
dto.setActualCost(rs.getDouble("ACTUAL_COST"));
dto.setVariance(rs.getDouble("VARIANCE"));
dto.setVariancePercent(rs.getDouble("VARIANCE_PERCENT"));
dto.setSavingsRealized(rs.getDouble("SAVINGS"));
return dto;
};

@Override
public `List<CostSummaryDTO>` queryCostSummary(GenericRequestDTO request) {
String sql = loadQuery("query.cost.summary");
return jdbcTemplate.query(sql, costSummaryRowMapper,
request.getAccountId(), request.getStartDate(), request.getEndDate());
}
}

Validation Rules​

Field-Level Validation​

Example DTOs with JSR-303 validation:

public class ReportDTO {
@NotNull(message = "Customer ID required")
@Pattern(regexp = "CUST-[0-9]+", message = "Invalid customer ID format")
private String customerId;

@NotNull
@Size(min = 1, max = 10, message = "Select 1-10 accounts")
private `List<String>` accountIds;

@PastOrPresent(message = "Start date cannot be in future")
private LocalDate startDate;

@Future(message = "End date must be in future")
private LocalDate endDate;

@Min(value = 1, message = "Page must be >= 1")
private Integer page = 1;

@Min(1)
@Max(1000)
private Integer pageSize = 100;
}

Cross-Field Validation​

@AssertTrue(message = "End date must be after start date")
public boolean isValidDateRange() {
if (startDate == null || endDate == null) {
return true; // Let @NotNull handle null cases
}
return endDate.isAfter(startDate);
}

@AssertTrue(message = "Date range cannot exceed 365 days")
public boolean isWithinMaxRange() {
if (startDate == null || endDate == null) {
return true;
}
return ChronoUnit.DAYS.between(startDate, endDate) <= 365;
}

Summary​

DTOs: 165 total across 9 categories Snowflake Tables: 3 core tables (COST_DAILY, COST_HOURLY, RI_UTILIZATION) MongoDB Collections: 5 (saved_reports, filter_metadata, custom_queries, etc.) MySQL Tables: 7 (accounts, users, billing_metadata, etc.)

Validation: JSR-303 Bean Validation on all request DTOs Mapping: RowMapper for SQL → DTO conversion Serialization: Jackson for JSON serialization


Document Version: 1.0 Last Updated: October 25, 2025