Skip to content

Conversation

@skand088
Copy link
Contributor

@skand088 skand088 commented Nov 22, 2025

Summary by CodeRabbit

  • New Features

    • Added broad time-series telemetry support: battery, battery faults, motor details, key motor, MPPT/charging, contactors, proximity sensors, button-board, telemetry, telemetry metadata, lap metrics, and driver records with optimized hypertable storage.
  • Chores

    • Removed legacy sample/test data model, its service, repository, controller, and exports.
  • Refactor

    • Standardized repository APIs and base data-access logic for time-based primary keys and consistent CRUD interfaces.

✏️ Tip: You can customize this high-level summary in your review settings.

@skand088 skand088 requested a review from a team as a code owner November 22, 2025 21:18
@vercel
Copy link

vercel bot commented Nov 22, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
helios-telemetry Ready Ready Preview Comment Nov 22, 2025 10:26pm

@coderabbitai
Copy link

coderabbitai bot commented Nov 22, 2025

Walkthrough

Replaces the TestTable feature with 13 new domain entities and their repositories, registers those entities in AppDataSource, and refactors BaseRepository and repository interfaces to use timestamp-based primary keys with a dynamic primaryKey mechanism.

Changes

Cohort / File(s) Summary
Data Source Configuration
packages/db/src/data-source.ts
AppDataSource updated to register 13 new entities (replacing previous TestTable).
New Hypertable Entities
packages/db/src/entities/*.entity.ts
packages/db/src/entities/Telemetry.entity.ts, .../TelemetryMetadata.entity.ts, .../ProximitySensors.entity.ts, .../Battery.entity.ts, .../BatteryFaults.entity.ts, .../MPPT.entity.ts, .../B3.entity.ts, .../MBMS.entity.ts, .../KeyMotor.entity.ts, .../MotorDetails.entity.ts, .../Contactor.entity.ts, .../Lap.entity.ts, .../Telemetry.entity.ts
Added Timescale hypertable entities with @Hypertable/@TimeColumn/@Index and detailed columns for telemetry, sensors, power systems, motor details, contactors, MBMS, B3 button-board, and Lap metrics.
Relational Entity
packages/db/src/entities/Driver.entity.ts
Added Driver entity (relational table) with rfid, name, created_at, updated_at.
Repository Interfaces
packages/db/src/interfaces/repositories.interface.ts
Removed TestTable interfaces; added 13 per-entity repository interfaces (each extends IBaseRepository<T>). IBaseRepository signatures changed to use Date for findById/update/delete parameters.
Base Repository Core
packages/db/src/repositories/BaseRepository.ts
Introduced dynamic primaryKey (default "timestamp"), changed BaseEntity shape to optional timestamp/rfid, renamed findAllfindMany, and updated findById/update/delete to use this.primaryKey lookups.
Entity Repositories
packages/db/src/repositories/*Repository.ts
packages/db/src/repositories/B3Repository.ts, .../BatteryRepository.ts, .../BatteryFaultsRepository.ts, .../ContactorRepository.ts, .../DriverRepository.ts, .../KeyMotorRepository.ts, .../LapRepository.ts, .../MBMSRepository.ts, .../MotorDetailsRepository.ts, .../MPPTRepository.ts, .../ProximitySensorsRepository.ts, .../TelemetryRepository.ts, .../TelemetryMetadataRepository.ts
Added 13 repository classes that extend BaseRepository<T> and wire the TypeORM Repository<T> via constructors; no additional custom methods.
Removed TestTable Feature
packages/db/src/entities/TestTable.entity.ts, packages/db/src/repositories/TestTableRepository.ts, packages/db/src/services/TestTableService.ts, packages/db/src/index.ts, packages/server/src/controllers/TestTableController.ts, packages/server/src/database/DatabaseManager.ts, packages/db/src/services/DatabaseService.ts
Removed TestTable entity, repository, service, controller and related exports/getters. DatabaseService gained rawDataSource() getter; DatabaseManager lost TestTableService getter.

Sequence Diagram(s)

sequenceDiagram
  participant App as AppDataSource
  participant DB as TimescaleDB
  participant Base as BaseRepository<T>
  participant Repo as EntityRepository
  participant Service as DatabaseService

  Note over App,DB: Entity registration
  App->>DB: registerEntities([Telemetry, Battery, MBMS, KeyMotor, ...])

  Note over Repo,Base: Repository wiring
  Repo->>Base: constructor(TypeORM Repository<Entity>)
  Service->>Repo: obtain repository instance
  Repo->>Base: CRUD call (create/findMany/findById/update/delete)
  Base->>DB: query(where: { [primaryKey]: value }) 
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing careful review:
    • BaseRepository dynamic primaryKey logic and type handling across methods.
    • Hypertable decorators/metadata consistency (chunkTimeInterval, compress_segmentby/orderby).
    • AppDataSource entity registration and any missing exports/typing regressions.
    • Removal of TestTable: ensure no remaining references in server or other packages.

Possibly related PRs

  • Timescaledb #262 — Overlaps changes to the db package (data-source, entity/registration, BaseRepository and TestTable removal); likely directly related.

Poem

🐰
Thirteen new burrows in the meadow bright,
Timestamps hop and sensors hum all night.
Batteries, motors, laps — a carrot cheer,
Data hops home, the fields of logs appear.
— your rabbit dev, nose twitching with delight

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'create tables and repositories' directly summarizes the main objective of the changeset, which adds numerous new entity tables and their corresponding repository implementations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch move-to-timescale

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/db/src/repositories/BaseRepository.ts (1)

9-52: delete ignores primaryKey and will not behave as intended

findById and update correctly respect the configurable primaryKey, but delete currently does not:

async delete(timestamp: Date): Promise<boolean> {
  const result = await this.repository.delete(timestamp);
  return (result.affected ?? 0) > 0;
}

This passes the Date directly to repository.delete, which TypeORM interprets as a primary‑key value. For entities where:

  • The actual DB PK is not the timestamp column (e.g., PK on rfid or composites), or
  • You configured primaryKey to something other than the true PK,

delete will either fail to match any rows or delete the wrong row.

To make delete consistent with findById/update and honor primaryKey, it should use a where object:

-  async delete(timestamp: Date): Promise<boolean> {
-    const result = await this.repository.delete(timestamp);
+  async delete(id: Date | string): Promise<boolean> {
+    const result = await this.repository.delete(
+      { [this.primaryKey]: id } as FindOptionsWhere<T>,
+    );
     return (result.affected ?? 0) > 0;
   }

You can keep the parameter type as just Date if you want to enforce timestamp‑only keys at the interface level, but the important part is to route deletes through { [this.primaryKey]: ... } rather than treating the argument as the database PK value.

♻️ Duplicate comments (1)
packages/db/src/entities/BatteryFaults.entity.ts (1)

19-24: Primary key setup matches entity pattern.

This follows the same pattern as the Contactor entity and other hypertable entities in the codebase. Refer to the verification comment in Contactor.entity.ts regarding composite primary key behavior.

🧹 Nitpick comments (2)
packages/db/src/interfaces/repositories.interface.ts (1)

3-60: Clarify repository “ID” semantics vs entity keys

IBaseRepository<T> now hard‑codes timestamp: Date as the identifier for findById, update, and delete, while:

  • BaseRepository actually supports a configurable primaryKey and accepts Date | string for its id.
  • Several entities (e.g., those keyed primarily by rfid or composite keys) don’t naturally have a single timestamp‑only identity, even if they contain a timestamp column.

This mismatch doesn’t immediately break anything if you only ever look up by timestamp for these hypertables, but it does:

  • Prevent you from expressing non‑timestamp keys via IBaseRepository.
  • Make the “id” semantics unclear for repos like drivers or any future non‑time‑series entity.

It may be cleaner to either (a) rename these methods to something like findByTimestamp to match the type, or (b) generalize the key parameter (e.g., key: Date | string or a where object) so it aligns with BaseRepository and the actual entity key strategy.

packages/db/src/entities/Contactor.entity.ts (1)

19-24: Based on the verification, the official @timescaledb/typeorm examples use @PrimaryColumn() for the non-timestamp key field alongside @TimeColumn(), whereas Contactor and all similar entities in the codebase use @Column({ type: "text", primary: true }) instead.

However, the primary: true option in @Column decorator is equivalent to using @PrimaryColumn, so this is functionally correct but represents a stylistic deviation from the official library examples.

The pattern is consistent across all hypertable entities (Battery, B3, MBMS, Telemetry, TelemetryMetadata, ProximitySensors, MotorDetails, KeyMotor, BatteryFaults, and Contactor), suggesting this is an intentional codebase convention. TimescaleDB requires the primary key to contain the partition key (the time column), and the composite primary key satisfies both TypeORM's and TimescaleDB's requirements.

Consider standardizing to use @PrimaryColumn() instead of @Column({ primary: true }) for consistency with official @timescaledb/typeorm examples, but verify this is not enforced elsewhere in the codebase configuration. The current implementation appears functionally sound despite the stylistic difference.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 36a9f11 and 373543d.

📒 Files selected for processing (29)
  • packages/db/src/data-source.ts (1 hunks)
  • packages/db/src/entities/B3.entity.ts (1 hunks)
  • packages/db/src/entities/Battery.entity.ts (1 hunks)
  • packages/db/src/entities/BatteryFaults.entity.ts (1 hunks)
  • packages/db/src/entities/Contactor.entity.ts (1 hunks)
  • packages/db/src/entities/Driver.entity.ts (1 hunks)
  • packages/db/src/entities/KeyMotor.entity.ts (1 hunks)
  • packages/db/src/entities/Lap.entity.ts (1 hunks)
  • packages/db/src/entities/MBMS.entity.ts (1 hunks)
  • packages/db/src/entities/MPPT.entity.ts (1 hunks)
  • packages/db/src/entities/MotorDetails.entity.ts (1 hunks)
  • packages/db/src/entities/ProximitySensors.entity.ts (1 hunks)
  • packages/db/src/entities/Telemetry.entity.ts (1 hunks)
  • packages/db/src/entities/TelemetryMetadata.entity.ts (1 hunks)
  • packages/db/src/interfaces/repositories.interface.ts (1 hunks)
  • packages/db/src/repositories/B3Repository.ts (1 hunks)
  • packages/db/src/repositories/BaseRepository.ts (2 hunks)
  • packages/db/src/repositories/BatteryFaultsRepository.ts (1 hunks)
  • packages/db/src/repositories/BatteryRepository.ts (1 hunks)
  • packages/db/src/repositories/ContactorRepository.ts (1 hunks)
  • packages/db/src/repositories/DriverRepository.ts (1 hunks)
  • packages/db/src/repositories/KeyMotorRepository.ts (1 hunks)
  • packages/db/src/repositories/LapRepository.ts (1 hunks)
  • packages/db/src/repositories/MBMSRepository.ts (1 hunks)
  • packages/db/src/repositories/MPPTRepository.ts (1 hunks)
  • packages/db/src/repositories/MotorDetailsRepository.ts (1 hunks)
  • packages/db/src/repositories/ProximitySensorsRepository.ts (1 hunks)
  • packages/db/src/repositories/TelemetryMetadataRepository.ts (1 hunks)
  • packages/db/src/repositories/TelemetryRepository.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (26)
packages/db/src/repositories/MotorDetailsRepository.ts (2)
packages/db/src/index.ts (1)
  • BaseRepository (7-7)
packages/db/src/interfaces/repositories.interface.ts (1)
  • IMotorDetailsRepository (49-50)
packages/db/src/repositories/LapRepository.ts (1)
packages/db/src/interfaces/repositories.interface.ts (1)
  • ILapRepository (45-45)
packages/db/src/entities/B3.entity.ts (2)
packages/db/src/entities/Battery.entity.ts (1)
  • Entity (8-127)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-33)
packages/db/src/repositories/MBMSRepository.ts (1)
packages/db/src/interfaces/repositories.interface.ts (1)
  • IMBMSRepository (47-47)
packages/db/src/entities/TelemetryMetadata.entity.ts (2)
packages/db/src/entities/Driver.entity.ts (1)
  • Entity (14-28)
packages/db/src/entities/Telemetry.entity.ts (1)
  • Entity (8-81)
packages/db/src/repositories/ProximitySensorsRepository.ts (2)
packages/db/src/index.ts (1)
  • BaseRepository (7-7)
packages/db/src/interfaces/repositories.interface.ts (1)
  • IProximitySensorsRepository (54-55)
packages/db/src/repositories/BatteryRepository.ts (2)
packages/db/src/index.ts (1)
  • BaseRepository (7-7)
packages/db/src/interfaces/repositories.interface.ts (1)
  • IBatteryRepository (34-34)
packages/db/src/repositories/TelemetryRepository.ts (2)
packages/db/src/index.ts (1)
  • BaseRepository (7-7)
packages/db/src/interfaces/repositories.interface.ts (1)
  • ITelemetryRepository (57-57)
packages/db/src/repositories/MPPTRepository.ts (2)
packages/db/src/index.ts (1)
  • BaseRepository (7-7)
packages/db/src/interfaces/repositories.interface.ts (1)
  • IMPPTRepository (52-52)
packages/db/src/entities/MPPT.entity.ts (2)
packages/db/src/entities/Battery.entity.ts (1)
  • Entity (8-127)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-33)
packages/db/src/repositories/KeyMotorRepository.ts (1)
packages/db/src/interfaces/repositories.interface.ts (1)
  • IKeyMotorRepository (43-43)
packages/db/src/repositories/BatteryFaultsRepository.ts (2)
packages/db/src/index.ts (1)
  • BaseRepository (7-7)
packages/db/src/interfaces/repositories.interface.ts (1)
  • IBatteryFaultsRepository (36-37)
packages/db/src/repositories/TelemetryMetadataRepository.ts (2)
packages/db/src/index.ts (1)
  • BaseRepository (7-7)
packages/db/src/interfaces/repositories.interface.ts (1)
  • ITelemetryMetadataRepository (59-60)
packages/db/src/entities/Telemetry.entity.ts (1)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-33)
packages/db/src/entities/MBMS.entity.ts (1)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-33)
packages/db/src/entities/ProximitySensors.entity.ts (2)
packages/db/src/entities/Telemetry.entity.ts (1)
  • Entity (8-81)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-33)
packages/db/src/repositories/DriverRepository.ts (1)
packages/db/src/interfaces/repositories.interface.ts (1)
  • IDriverRepository (41-41)
packages/db/src/entities/KeyMotor.entity.ts (2)
packages/db/src/entities/MotorDetails.entity.ts (1)
  • Entity (9-114)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-33)
packages/db/src/repositories/B3Repository.ts (1)
packages/db/src/interfaces/repositories.interface.ts (1)
  • IB3Repository (32-32)
packages/db/src/entities/Lap.entity.ts (2)
packages/db/src/entities/Driver.entity.ts (1)
  • Entity (14-28)
packages/db/src/entities/Telemetry.entity.ts (1)
  • Entity (8-81)
packages/db/src/repositories/ContactorRepository.ts (1)
packages/db/src/interfaces/repositories.interface.ts (1)
  • IContactorRepository (39-39)
packages/db/src/entities/MotorDetails.entity.ts (1)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-33)
packages/db/src/data-source.ts (1)
packages/db/src/index.ts (1)
  • AppDataSource (1-1)
packages/db/src/entities/Contactor.entity.ts (2)
packages/db/src/entities/MBMS.entity.ts (1)
  • Entity (8-196)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-33)
packages/db/src/entities/Battery.entity.ts (1)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-33)
packages/db/src/entities/BatteryFaults.entity.ts (2)
packages/db/src/entities/Battery.entity.ts (1)
  • Entity (8-127)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-33)
🔇 Additional comments (24)
packages/db/src/entities/Lap.entity.ts (1)

20-27: Confirm Lap repository logic matches UUID primary key

Lap uses id: uuid as the primary key (Lines 20–21), with timestamp and rfid as regular columns. That’s a sensible design for lap-level aggregates, but the PR description mentions updating the BaseRepository to use timestamp-based primary keys.

Can you double-check that:

  • ILapRepository / LapRepository treat id as the primary identifier (for find/delete/update methods), and
  • Any generic timestamp-based repository APIs don’t assume timestamp is the actual primary key for Lap?

If everything is already wired to use id correctly, the entity itself looks good.

packages/db/src/entities/Battery.entity.ts (2)

8-18: LGTM!

The hypertable configuration is appropriate for time-series battery telemetry data with monthly chunking and compression.


122-123: Verify the semantic correctness of populated_cells type.

The searches for populated_cells usage outside its definition in Battery.entity.ts returned no results. This suggests the field is either newly added in this PR or used in ways not readily searchable through standard pattern matching (e.g., dynamic property access, ORM query builders).

However, the field name populated_cells semantically implies a count—which should be an integer type. The current declaration uses float, which is inconsistent with that semantic meaning.

Verify the intended semantics of this field:

  • If it represents a cell count or discrete quantity, use int instead
  • If it represents a calculated ratio or percentage (e.g., 0.0 to 1.0 or 0 to 100), float is appropriate
packages/db/src/repositories/BatteryRepository.ts (1)

6-13: LGTM!

The repository follows the established pattern and correctly wires the Battery entity to BaseRepository.

packages/db/src/data-source.ts (1)

6-18: LGTM!

All 13 entities are properly imported and registered in the AppDataSource. The migration from TestTable to production entities is correctly implemented.

Also applies to: 26-40

packages/db/src/repositories/MBMSRepository.ts (1)

6-13: LGTM!

Repository implementation follows the standard pattern.

packages/db/src/repositories/LapRepository.ts (1)

6-13: LGTM!

Repository implementation follows the standard pattern.

packages/db/src/repositories/ContactorRepository.ts (1)

6-13: LGTM!

Repository implementation follows the standard pattern.

packages/db/src/repositories/DriverRepository.ts (1)

6-13: LGTM!

Repository implementation follows the standard pattern.

packages/db/src/repositories/TelemetryRepository.ts (1)

6-13: LGTM!

Repository implementation follows the standard pattern.

packages/db/src/repositories/BatteryFaultsRepository.ts (1)

6-13: LGTM! Clean repository implementation.

The repository correctly extends BaseRepository and implements the interface contract. This follows the established pattern across all repositories in this PR.

packages/db/src/repositories/B3Repository.ts (1)

6-10: LGTM! Consistent repository implementation.

The repository correctly follows the established pattern with proper base class extension and interface implementation.

packages/db/src/repositories/MPPTRepository.ts (1)

6-13: LGTM! Repository implementation follows the pattern.

Correctly implements the repository interface with proper TypeORM integration.

packages/db/src/repositories/ProximitySensorsRepository.ts (1)

6-13: LGTM! Consistent with repository pattern.

The implementation correctly extends the base repository and implements the interface.

packages/db/src/repositories/MotorDetailsRepository.ts (1)

6-13: LGTM! Repository implementation is correct.

Follows the established pattern with proper base class and interface implementation.

packages/db/src/repositories/TelemetryMetadataRepository.ts (1)

6-13: LGTM! Repository follows the pattern.

The implementation is consistent with the repository architecture established in this PR.

packages/db/src/entities/Driver.entity.ts (1)

20-27: LGTM! Field definitions are correct.

The entity fields are properly defined with appropriate column types and auto-managed timestamps.

packages/db/src/entities/MPPT.entity.ts (2)

8-24: LGTM! Hypertable configuration is well-designed.

The time-based partitioning with monthly chunks, compression strategy, and composite primary key on timestamp and rfid are appropriate for time-series telemetry data. The index on [rfid, timestamp] will efficiently support typical query patterns.


26-123: Verify that all MPPT sensor fields are always available.

All 32 MPPT sensor fields are defined as non-nullable (!: number). This means database inserts will fail if any sensor value is missing. In telemetry systems, sensors can fail, lose connection, or temporarily not provide readings.

Please verify that:

  1. All MPPT sensors (0-3) and their channels (0-1) always provide all readings
  2. The data pipeline guarantees complete data before database insertion

If partial sensor data is expected, consider making fields nullable by using nullable: true and ?: number.

Example for nullable fields:

-  @Column({ type: "float" })
-  mppt0_ch0_array_current!: number;
+  @Column({ type: "float", nullable: true })
+  mppt0_ch0_array_current?: number;
packages/db/src/repositories/KeyMotorRepository.ts (1)

1-13: Repository wiring looks good

The repository correctly extends BaseRepository<KeyMotor> and implements IKeyMotorRepository; constructor wiring is straightforward and consistent with the other repositories in this PR.

packages/db/src/entities/Contactor.entity.ts (2)

1-18: Well-structured hypertable configuration.

The entity setup follows best practices for TimescaleDB:

  • Monthly chunk intervals appropriate for telemetry data
  • Compression with rfid segmentation optimizes storage for per-device queries
  • Index on [rfid, timestamp] supports efficient lookups

26-180: Verify upstream telemetry guarantees all fields are always present.

The IContactorType in packages/shared/src/types.ts is defined with t.exact(t.type({...})), making all 50 fields required. In the database entity, all fields lack nullable: true, enforcing the requirement at the schema level. If any field is missing from an incoming telemetry packet, io-ts validation will fail and the record will not be inserted.

Confirm with your upstream telemetry source whether all contactor fields are guaranteed to be present in every packet. If fields can be missing or unavailable due to sensor failures or communication issues, consider making appropriate fields optional:

// Example: using t.partial for optional fields
const IContactorType = t.exact(t.intersection([
  t.type({ /* required fields */ }),
  t.partial({ /* optional fields */ })
]))

Alternatively, implement fallback/default values in the data ingestion pipeline to handle missing fields gracefully.

packages/db/src/entities/BatteryFaults.entity.ts (2)

1-18: LGTM: Consistent hypertable configuration.

The entity follows the same well-structured pattern as other hypertable entities in the codebase, with appropriate compression and indexing for battery fault telemetry data.


26-132: I need to investigate where BatteryFaults data originates and how it's validated before database insertion.

Now let me search for where BatteryFaults data is actually created/inserted in the codebase:

Let me search the codebase for where BatteryFaults data is actually created and inserted:

Based on my verification, the original review comment requests a verification check about nullable fields for battery fault data. However, I cannot find conclusive evidence in the codebase about whether all 35 fault/warning fields are guaranteed to always be present or if some may be missing during BMS communication failures. The type definitions require all fields, fake data always provides them, and the UI code expects all fields to be present. However, without access to actual data ingestion and persistence logic from the BMS, I cannot determine if the concern about resilience during offline scenarios is valid.

No issues identified requiring immediate changes.

The BatteryFaults entity correctly defines 35 boolean fields as non-nullable, which aligns with the strict TypeScript type definitions and fake data generation patterns used throughout the codebase. The current schema assumes all fault data fields are always provided by the battery management system.

If real-world BMS data proves to be incomplete or availability varies based on communication failures, making fields nullable would require coordinated changes across:

  • The entity definition
  • TypeScript type definitions in packages/shared/src/types.ts
  • Data transformation logic handling BMS telemetry
  • Query and display code in the client

This would be a larger architectural decision beyond the scope of this entity file alone.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/db/src/interfaces/repositories.interface.ts (1)

26-54: Consider adding JSDoc comments for the repository interfaces.

The 13 new repository interfaces are currently empty extensions of IBaseRepository<T>, which is appropriate if no custom methods are needed. However, consider adding brief JSDoc comments to document the purpose of each repository, especially if they will have domain-specific query methods in the future.

Example:

+/**
+ * Repository for managing B3 telemetry data.
+ */
 export interface IB3Repository extends IBaseRepository<B3> {}
packages/db/src/services/DatabaseService.ts (1)

15-15: Consider using structured logging instead of console statements.

The console.log and console.error statements are flagged by ESLint's no-console rule. For a library package, consider using a structured logging library (e.g., winston, pino) that allows:

  • Configurable log levels
  • Structured output formats
  • Consumer control over logging behavior

Alternatively, expose logging through dependency injection so consumers can plug in their own logger.

Example with a simple logger interface:

interface Logger {
  log(message: string): void;
  error(message: string, error?: unknown): void;
}

export class DatabaseService {
  constructor(private logger: Logger = console) {}
  
  async initialize(): Promise<void> {
    try {
      if (!this.dataSource.isInitialized) {
        await this.dataSource.initialize();
        this.logger.log("Database connection initialized successfully");
      }
    } catch (error) {
      this.logger.error("Error during database initialization:", error);
      throw error;
    }
  }
}

Based on learnings

Also applies to: 18-18, 26-26

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 373543d and 1be2214.

📒 Files selected for processing (8)
  • packages/db/src/entities/TestTable.entity.ts (0 hunks)
  • packages/db/src/index.ts (0 hunks)
  • packages/db/src/interfaces/repositories.interface.ts (1 hunks)
  • packages/db/src/repositories/TestTableRepository.ts (0 hunks)
  • packages/db/src/services/DatabaseService.ts (2 hunks)
  • packages/db/src/services/TestTableService.ts (0 hunks)
  • packages/server/src/controllers/TestTableController.ts (0 hunks)
  • packages/server/src/database/DatabaseManager.ts (2 hunks)
💤 Files with no reviewable changes (5)
  • packages/db/src/repositories/TestTableRepository.ts
  • packages/db/src/entities/TestTable.entity.ts
  • packages/server/src/controllers/TestTableController.ts
  • packages/db/src/index.ts
  • packages/db/src/services/TestTableService.ts
🧰 Additional context used
🪛 ESLint
packages/db/src/services/DatabaseService.ts

[error] 15-15: Unexpected console statement.

(no-console)


[error] 18-18: Unexpected console statement.

(no-console)


[error] 26-26: Unexpected console statement.

(no-console)

🔇 Additional comments (5)
packages/db/src/services/DatabaseService.ts (2)

36-38: Acceptable, but note this bypasses the service abstraction.

The rawDataSource getter exposes the internal DataSource for advanced operations. While this provides flexibility for migrations and complex queries, it bypasses the service layer abstraction.

Ensure that:

  1. Usage of rawDataSource is documented and limited to necessary cases
  2. Consider if specific methods could be added to DatabaseService instead of exposing the raw DataSource
  3. Consumers understand they're working outside the service abstraction when using this getter

1-2: Removal of testTableRepository is safe—no downstream code access detected.

Verification confirms the testTableRepository getter was cleanly removed from DatabaseService.ts with no references remaining in the codebase. No breakage risk.

packages/db/src/interfaces/repositories.interface.ts (2)

2-14: Verify that IBaseRepository interface changes accommodate Driver and Lap primary key patterns.

Entity files exist and are properly configured. However, the verification revealed an inconsistency:

  • 11 entities (B3, BatteryFaults, Battery, Contactor, KeyMotor, MBMS, MotorDetails, MPPT, ProximitySensors, Telemetry, TelemetryMetadata) follow a consistent pattern: @TimeColumn() timestamp as the time column with a composite key.
  • Driver uses @PrimaryColumn({ type: "text" }) rfid (text primary key, not timestamp-based)
  • Lap uses @PrimaryGeneratedColumn("uuid") id (UUID primary key, not timestamp-based)

If the IBaseRepository signature changes expect timestamp-based primary keys, Driver and Lap will be incompatible. Verify that the interface changes accept these alternative primary key strategies.


18-18: <!-- [scratchpad_start]
[task review_file_1/1 verification_3/4]
Repository found, continuing with verification

[observations]

  • Files exist: repositories.interface.ts, BaseRepository.ts, DatabaseService.ts
  • Multiple entity files present (B3, Battery, etc.)
  • Services directory exists

[pending]

  1. View IBaseRepository interface definition
  2. Check service calls to repository methods
  3. View entity definitions for primary key setup
  4. Compare interface signatures vs implementation signatures

[actions]
View interface definition and service/entity usage

#!/bin/bash

echo "=== IBaseRepository interface (lines 1-30) ==="
head -30 ./packages/db/src/interfaces/repositories.interface.ts

echo -e "\n=== DatabaseService calls to repositories ==="
cat ./packages/db/src/services/DatabaseService.ts | grep -A3 "\.findById\|\.update\|\.delete" | head -60

echo -e "\n=== Sample entity: B3.entity.ts (first 40 lines) ==="
head -40 ./packages/db/src/entities/B3.entity.ts

echo -e "\n=== Check for timestamp primary key in entities ==="
grep -h "timestamp\|rfid\|@PrimaryColumn\|@CreateDateColumn" ./packages/db/src/entities/*.ts | head -20
packages/server/src/database/DatabaseManager.ts (1)

1-1: Removal of TestTableService is safe—no downstream references detected.

Comprehensive verification confirms no code in the codebase references the removed testTableService getter or TestTableService import. The removal aligns safely with the TestTable feature retirement.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
packages/db/src/entities/Battery.entity.ts (1)

1-128: LGTM! Past review concerns have been addressed.

The entity structure is well-designed for time-series telemetry data. The composite primary key (timestamp, rfid) correctly supports multiple readings per device over time, and all previously flagged ID fields (bmu_alive, high_cell_voltage_id, high_thermistor_id, low_cell_voltage_id, low_thermistor_id) have been properly corrected to use integer type instead of float, resolving precision and indexing concerns.

packages/db/src/entities/KeyMotor.entity.ts (1)

1-35: LGTM! Past review concerns have been addressed.

The entity is now correctly structured for time-series data. The composite primary key (timestamp, rfid) at lines 20-25 properly allows storing multiple sensor readings per rfid at different timestamps, resolving the previously flagged issue that would have blocked time-series inserts.

🧹 Nitpick comments (5)
packages/db/src/entities/Driver.entity.ts (1)

1-8: Remove unused import.

The Index import from typeorm (Line 7) is no longer used after removing the redundant index decorator.

Apply this diff to clean up the unused import:

 import {
   Entity,
   Column,
   PrimaryColumn,
   CreateDateColumn,
   UpdateDateColumn,
-  Index,
 } from "typeorm";
packages/db/src/entities/Contactor.entity.ts (1)

27-180: Optional: reduce duplication across contactor groups

The array_*, charge_*, common_*, lv_*, and motor_* groups all have very similar shapes (bps_error, *_charge_current, contactor flags, precharger flags, etc.). Not required, but you could improve maintainability by modeling one “contactor group” structure (e.g., via an embedded entity or a helper type) and reusing it for each subsystem so changes to the shape don’t require editing ~50 lines.

packages/db/src/entities/Telemetry.entity.ts (2)

28-59: Verify GPS field types: consider integers for date/time components and flags.

Several GPS fields are typed as float but semantically represent discrete integer values:

  • Date/time components (gps_day, gps_hour, gps_minute, gps_month, gps_second, gps_year) typically range from 1-31, 0-23, 0-59, 1-12, 0-59, and year respectively
  • Flag fields (gps_additional_flags, gps_fix_status_flags, gps_validity_flags) usually represent bitmasks or enumerated values

Using int or smallint would be more space-efficient and semantically clearer. However, if the upstream GPS source provides these as floating-point values, the current typing may be intentional.

Please verify whether these fields should be integers. If so, apply this diff:

   // GPS Data
-  @Column({ type: "float" })
+  @Column({ type: "int" })
   gps_additional_flags!: number;
 
-  @Column({ type: "float" })
+  @Column({ type: "smallint" })
   gps_day!: number;
 
-  @Column({ type: "float" })
+  @Column({ type: "int" })
   gps_fix_status_flags!: number;
 
-  @Column({ type: "float" })
+  @Column({ type: "smallint" })
   gps_hour!: number;
 
   @Column({ type: "float" })
   gps_latitude!: number;
 
   @Column({ type: "float" })
   gps_longitude!: number;
 
-  @Column({ type: "float" })
+  @Column({ type: "smallint" })
   gps_minute!: number;
 
-  @Column({ type: "float" })
+  @Column({ type: "smallint" })
   gps_month!: number;
 
-  @Column({ type: "float" })
+  @Column({ type: "smallint" })
   gps_second!: number;
 
-  @Column({ type: "float" })
+  @Column({ type: "int" })
   gps_validity_flags!: number;
 
-  @Column({ type: "float" })
+  @Column({ type: "smallint" })
   gps_year!: number;

18-18: Consider reordering index for time-series query performance.

The composite index is currently ordered as ["rfid", "timestamp"]. For time-series workloads where queries typically filter by time ranges first (e.g., "all readings in the last hour"), placing timestamp first may improve query performance and better align with the compression order (timestamp DESC).

If time-range queries are more common than RFID-specific lookups, apply this diff:

-@Index(["rfid", "timestamp"])
+@Index(["timestamp", "rfid"])
packages/db/src/entities/MotorDetails.entity.ts (1)

59-60: Consider a more descriptive field name than id.

The generic name id is ambiguous in this context. Since this entity already has a composite primary key and references Tritium motor controllers (per the comment), consider renaming to clarify what this ID represents (e.g., controller_id, message_id, or similar).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1be2214 and 22dfe6b.

📒 Files selected for processing (12)
  • packages/db/src/entities/B3.entity.ts (1 hunks)
  • packages/db/src/entities/Battery.entity.ts (1 hunks)
  • packages/db/src/entities/BatteryFaults.entity.ts (1 hunks)
  • packages/db/src/entities/Contactor.entity.ts (1 hunks)
  • packages/db/src/entities/Driver.entity.ts (1 hunks)
  • packages/db/src/entities/KeyMotor.entity.ts (1 hunks)
  • packages/db/src/entities/MBMS.entity.ts (1 hunks)
  • packages/db/src/entities/MPPT.entity.ts (1 hunks)
  • packages/db/src/entities/MotorDetails.entity.ts (1 hunks)
  • packages/db/src/entities/ProximitySensors.entity.ts (1 hunks)
  • packages/db/src/entities/Telemetry.entity.ts (1 hunks)
  • packages/db/src/entities/TelemetryMetadata.entity.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/db/src/entities/B3.entity.ts
  • packages/db/src/entities/MBMS.entity.ts
  • packages/db/src/entities/MPPT.entity.ts
🧰 Additional context used
🧬 Code graph analysis (8)
packages/db/src/entities/Telemetry.entity.ts (2)
packages/db/src/entities/B3.entity.ts (1)
  • Entity (8-92)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-34)
packages/db/src/entities/ProximitySensors.entity.ts (2)
packages/db/src/entities/Telemetry.entity.ts (1)
  • Entity (8-82)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-34)
packages/db/src/entities/Contactor.entity.ts (2)
packages/db/src/entities/MBMS.entity.ts (1)
  • Entity (8-197)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-34)
packages/db/src/entities/TelemetryMetadata.entity.ts (2)
packages/db/src/entities/MotorDetails.entity.ts (1)
  • Entity (9-115)
packages/db/src/entities/Telemetry.entity.ts (1)
  • Entity (8-82)
packages/db/src/entities/MotorDetails.entity.ts (2)
packages/db/src/entities/KeyMotor.entity.ts (1)
  • Entity (8-35)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-34)
packages/db/src/entities/KeyMotor.entity.ts (2)
packages/db/src/entities/MotorDetails.entity.ts (1)
  • Entity (9-115)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-34)
packages/db/src/entities/Battery.entity.ts (2)
packages/db/src/entities/BatteryFaults.entity.ts (1)
  • Entity (8-133)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-34)
packages/db/src/entities/BatteryFaults.entity.ts (2)
packages/db/src/entities/Battery.entity.ts (1)
  • Entity (8-128)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)
  • Entity (9-34)
🔇 Additional comments (14)
packages/db/src/entities/TelemetryMetadata.entity.ts (1)

22-27: Composite primary key correctly implemented.

The entity now uses a composite primary key of (timestamp, rfid), which resolves the concern raised in the previous review. This design allows storing multiple telemetry packets for the same RFID across different timestamps, preventing primary key violations during ingestion.

The implementation is consistent with other hypertable entities in the codebase (e.g., Telemetry.entity.ts uses timestamp + rfid, and MotorDetails.entity.ts uses timestamp + rfid + motor_id).

packages/db/src/entities/Driver.entity.ts (2)

14-17: LGTM! Previous issue resolved.

The redundant @Index decorator has been removed, and the entity structure is now correct. The rfid field as a primary column is appropriately unique and indexed without requiring an additional explicit index.


19-26: LGTM! Standard entity pattern.

The column definitions follow standard TypeORM patterns with appropriate use of @CreateDateColumn and @UpdateDateColumn for automatic timestamp management.

packages/db/src/entities/Contactor.entity.ts (2)

1-25: Hypertable, PK, and index configuration look solid and consistent

The @Entity, @Hypertable, composite primary key (timestamp + rfid), and the extra @Index(["rfid", "timestamp"]) mirror the pattern used in TelemetryMetadata/MBMS and should work well for per‑RFID time-series queries while keeping Timescale happy with timestamp as the time column.

If you haven’t already, please double-check that the generated migration actually creates the hypertable and compression policy with these options (segmentby rfid, orderby timestamp DESC) and that query plans for typical WHERE rfid = ? AND timestamp BETWEEN ? AND ? look as expected.


27-180: Confirm ingestion/backfill assumptions for non‑nullable telemetry fields

All contactor/precharger fields are defined as non‑nullable booleans/floats with no defaults. That’s fine if every insert path always has a concrete value for every field (including any historical backfill), but it will cause insert failures if any field is ever legitimately “missing” or not present in some firmware versions.

Please confirm:

  • That your ingestion pipeline always populates all of these properties for every row, and
  • That you don’t expect schema drift (e.g., some fields appearing only on newer hardware/firmware).

If either of those isn’t guaranteed, consider marking such fields { nullable: true } or adding sensible DB defaults instead.

packages/db/src/entities/ProximitySensors.entity.ts (3)

1-18: LGTM! Hypertable configuration is well-structured.

The imports, entity metadata, and hypertable configuration are appropriate for a TimescaleDB time-series entity. The compression settings (segmenting by rfid, ordering by timestamp DESC) align well with typical time-series query patterns.


20-25: Composite primary key correctly resolves past critical issue.

The implementation now properly defines a composite primary key on (timestamp, rfid), which satisfies TimescaleDB's requirement that hypertable primary keys must include the time (partition) column. This allows multiple proximity sensor readings per RFID across different timestamps and is consistent with the pattern used in TelemetryMetadata.entity.ts and Telemetry.entity.ts.


27-38: Verify that all proximity sensors are always available.

All four proximity sensor columns are defined as non-nullable, meaning every insert must provide all four values. Please confirm that all sensors are guaranteed to be operational and transmitting data at all times. If sensors can fail, disconnect, or be temporarily unavailable, consider making these columns nullable to distinguish between "sensor read 0.0" and "sensor data unavailable."

For example, if sensors can be unavailable:

-  @Column({ type: "float" })
+  @Column({ type: "float", nullable: true })
   proximity_sensor_1!: number;

And adjust the TypeScript type to allow undefined:

-  proximity_sensor_1!: number;
+  proximity_sensor_1?: number;
packages/db/src/entities/Telemetry.entity.ts (2)

20-25: Composite primary key correctly addresses previous concern.

The entity now correctly defines both timestamp and rfid as primary columns, forming a composite key that properly supports time-series data with multiple readings per RFID. This resolves the issue raised in the previous review.


61-82: MPU sensor columns look good.

The MPU (Motion Processing Unit) columns are appropriately typed as float for continuous sensor measurements (acceleration, rotation, temperature). The structure is clean and consistent.

packages/db/src/entities/MotorDetails.entity.ts (1)

22-30: Primary key issue resolved—LGTM!

The composite primary key (timestamp, rfid, motor_id) now correctly allows multiple time-series records per motor. This addresses the critical issue flagged in the previous review where timestamp was excluded from the primary key.

packages/db/src/entities/BatteryFaults.entity.ts (3)

1-18: LGTM! Hypertable configuration follows established patterns.

The entity structure, hypertable setup, compression settings, and indexing strategy are consistent with other time-series entities in the codebase (Battery, TelemetryMetadata) and appropriate for telemetry fault data.


20-25: LGTM! Primary key structure is correct.

The composite primary key using timestamp and rfid matches the established pattern across other time-series entities and is appropriate for TimescaleDB hypertable partitioning.


28-132: The review comment is based on incorrect architectural assumptions.

The BatteryFaults entity uses TypeORM @Column decorators, but the codebase does not persist data through TypeORM. Telemetry data is stored in AWS DynamoDB via insertPacketData(), which stores the entire ITelemetryData packet as a nested object. Since DynamoDB is schemaless, the @Column decorators have no effect on actual storage constraints or defaults. The entity appears unused for persistence.

While the BatteryFaults data model design question remains valid (distinguishing "fault not present" vs. "fault status unreported"), the specific concern about TypeORM column defaults and inserts failing due to missing fields does not apply to this codebase's actual architecture.

Likely an incorrect or invalid review comment.

motor_id!: number;

@Column({ type: "float" })
active_motor!: number;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Verify float types for flags, counts, and IDs.

Several fields are typed as float but semantically appear to be integers:

  • error_flags, limit_flags (lines 54, 66): typically bitmasks
  • rx_error_count, tx_error_count (lines 84, 105): typically counters
  • serial_number, tritium_id (lines 87, 102): typically integer or string IDs
  • active_motor (line 33): possibly boolean or integer enum

Using float for these may introduce precision issues and semantic confusion. Please verify against the motor controller specifications or upstream data source to confirm the correct types.

Also applies to: 54-54, 66-66, 84-84, 87-87, 102-102, 105-105


🏁 Script executed:

#!/bin/bash
# Description: Search for similar entity definitions or data mappings that might clarify intended types

# Check if other entities use integer types for similar fields
rg -n -A2 -B2 --type=ts 'error_flags|limit_flags|error_count|serial_number' packages/db/src/entities/

# Look for any data transformation or mapping logic
rg -n -A3 --type=ts 'MotorDetails' packages/

Length of output: 35692


I need to view the complete MotorDetails.entity.ts file to verify all field decorators, particularly for active_motor (line 33) and tritium_id (line 102).

[/run_scripts]


🏁 Script executed:

#!/bin/bash
# Get the complete MotorDetails.entity.ts file to verify all float type annotations
cat packages/db/src/entities/MotorDetails.entity.ts

Length of output: 2445


Change float column types to integer for flags, counts, and IDs.

The review concern is substantiated. All seven fields are correctly identified as using float column types in the database, but their semantics are integral:

  • error_flags, limit_flags (lines 54, 66): Bitmasks should use int
  • rx_error_count, tx_error_count (lines 84, 105): Counters should use int or bigint
  • serial_number, tritium_id (lines 87, 102): IDs should use int, bigint, or text
  • active_motor (line 33): Status flag should use int or smallint

Test data generation consistently uses faker.number.int(), confirming integer intent. Update column type decorators from "float" to "int" (or "bigint"/"text" as appropriate per specifications).

🤖 Prompt for AI Agents
In packages/db/src/entities/MotorDetails.entity.ts around lines 33, 54, 66, 84,
87, 102, and 105, several columns are currently declared with the "float" type
but represent flags, counts, or IDs; update their @Column decorators to use
integer-appropriate types: change active_motor (line 33), error_flags (line 54),
and limit_flags (line 66) to "int" or "smallint" for flags; change
rx_error_count (line 84) and tx_error_count (line 105) to "int" or "bigint" for
counters; change serial_number (line 87) and tritium_id (line 102) to
"int"/"bigint" or "text" per ID size requirement; ensure TypeScript property
types remain numeric/string as needed and run/update migrations or schema sync
to reflect these type changes.

@burtonjong burtonjong merged commit 568fc61 into main Nov 27, 2025
7 checks passed
@burtonjong burtonjong deleted the move-to-timescale branch November 27, 2025 00:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants