Skip to content

Conversation

Jayesh445
Copy link

@Jayesh445 Jayesh445 commented Apr 18, 2025

Audit Fields Implementation Summary

This PR addresses Issue #766 by introducing audit fields to track user actions on encounters.

Changes Made

  1. Abstract Base Class Update

  • Added audit fields to AbstractEncounter class:

    • created_by_id
    • last_modified_by_id
    • filled_by_id
  1. Entity Relationships

  • Added ManyToOne relationships with User entity
  • Configured lazy loading for performance
  • Added JPA annotations for column mappings
  1. Database Updates

  • Created migration script V1_354__AddAuditFieldsToTables.sql

  • Added audit columns to:

    • encounter
    • program_encounter
  • Added performance indexes for audit fields

  1. Service Layer

  • Updated services to handle audit field population:

    • EncounterService
    • ProgramEncounterService

Summary by CodeRabbit

  • New Features
    • API responses now expose Created By, Last Modified By and Filled By for encounters and program encounters; these fields are auto-populated on create/update (including via visit schedules).
  • Security
    • Row-level access controls added for the new audit fields.
  • Performance
    • Indexes added to improve lookups on audit fields.
  • Tests
    • New unit test(s) validating audit field population.
  • Chores
    • Database migration to add and initialize audit fields.

Copy link

coderabbitai bot commented Sep 15, 2025

Walkthrough

Adds createdBy, lastModifiedBy, and filledBy audit fields to encounter and program_encounter: DB migration (columns, indexes, RLS policies), domain model associations, services/controllers populate and serialize these fields from the current user, and tests to validate audit population.

Changes

Cohort / File(s) Summary
Database Migration
avni-server-api/src/main/resources/db/migration/V1_353__AddAuditFields.sql
Adds created_by_id, last_modified_by_id, filled_by_id to encounter and program_encounter (IF NOT EXISTS); creates indexes; adds RLS policies on encounter for the three fields.
Domain Model
avni-server-data/src/main/java/org/avni/server/domain/AbstractEncounter.java
Adds lazy many-to-one User associations createdBy and lastModifiedBy with getters/setters; getters annotated @JsonIgnore.
Services: Encounter
avni-server-api/src/main/java/org/avni/server/service/EncounterService.java
On update via VisitSchedule sets lastModifiedBy to userService.getCurrentUser(); on creating a new empty encounter initializes filledBy, createdBy, and lastModifiedBy to the current user.
Services: ProgramEncounter
avni-server-api/src/main/java/org/avni/server/service/ProgramEncounterService.java
Multiple save/update paths now set audit fields from userService.getCurrentUser() (on update: lastModifiedBy; on create: createdBy/lastModifiedBy; createEmptyProgramEncounter sets filledBy to null and created/lastModified to current user).
Controllers: Encounter
avni-server-api/src/main/java/org/avni/server/web/EncounterController.java
On creation sets createdBy, lastModifiedBy, and filledBy to current user; serialized response now includes createdBy and lastModifiedBy alongside filledBy.
Controllers: ProgramEncounter
avni-server-api/src/main/java/org/avni/server/web/ProgramEncounterController.java
Resource processing/serialization updated to include lastModifiedBy and createdBy (in addition to existing filledBy/audit fields).
Tests: Service Unit
avni-server-api/src/test/java/org/avni/server/service/ProgramEncounterServiceTest.java
New unit test verifies audit fields (createdBy, lastModifiedBy, filledBy) are populated with current user on save; uses Mockito to stub repository and user service.
Tests: Controller Integration
avni-server-api/src/test/java/org/avni/server/web/ProgramEncounterControllerIntegrationTest.java
Formatting-only change (end-of-file newline); no functional/test behavior changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as Client
  participant EC as EncounterController
  participant ES as EncounterService
  participant US as UserService
  participant DB as Database

  rect rgba(230,245,255,0.6)
  Note over C,ES: Create Encounter
  C->>EC: POST /encounters
  EC->>US: getCurrentUser()
  US-->>EC: User
  EC->>ES: createEncounter(payload)
  ES->>ES: set createdBy/lastModifiedBy/filledBy = User
  ES->>DB: INSERT encounter(..., created_by_id, last_modified_by_id, filled_by_id)
  DB-->>ES: OK
  ES-->>EC: Encounter
  EC-->>C: JSON (includes createdBy, lastModifiedBy, filledBy)
  end

  rect rgba(255,245,230,0.6)
  Note over C,ES: Update Encounter via VisitSchedule
  C->>EC: PUT /encounters/{id}
  EC->>US: getCurrentUser()
  US-->>EC: User
  EC->>ES: updateEncounter(id, changes)
  ES->>ES: set lastModifiedBy = User
  ES->>DB: UPDATE encounter SET last_modified_by_id=...
  DB-->>ES: OK
  ES-->>EC: Encounter
  EC-->>C: JSON (updated audit fields)
  end

  Note over DB: RLS enforces created_by_id/last_modified_by_id/filled_by_id policies
Loading
sequenceDiagram
  autonumber
  participant C as Client
  participant PC as ProgramEncounterController
  participant PS as ProgramEncounterService
  participant US as UserService
  participant DB as Database

  rect rgba(235,255,235,0.6)
  Note over C,PS: Save ProgramEncounter
  C->>PC: POST /programEncounters
  PC->>US: getCurrentUser()
  US-->>PC: User
  PC->>PS: save(payload)
  PS->>PS: associate individual, process observations
  PS->>PS: set createdBy/lastModifiedBy/filledBy = User (or filledBy = null for createEmpty)
  PS->>DB: INSERT/UPDATE program_encounter(..., audit fields)
  DB-->>PS: OK
  PS-->>PC: ProgramEncounter
  PC-->>C: JSON (includes filledBy, createdBy, lastModifiedBy)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

I hopped through rows and added names,
Marked who made changes, who filled the frames.
Created, modified, a tidy trail,
RLS guards the burrow without fail.
Indexes hum — queries set sail. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title accurately and concisely describes the primary change: adding the audit fields created_by, last_modified_by, and filled_by to the encounter and program_encounter tables. It directly reflects the migration and related model/service/controller updates in the changeset and is neither vague nor noisy.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e68807c and e4a647f.

📒 Files selected for processing (1)
  • avni-server-data/src/main/java/org/avni/server/domain/AbstractEncounter.java (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • avni-server-data/src/main/java/org/avni/server/domain/AbstractEncounter.java

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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: 8

🧹 Nitpick comments (1)
avni-server-api/src/main/java/org/avni/server/web/ProgramEncounterController.java (1)

187-188: Guard against null audit users in resource serialization

Confirm addUserFields is null-safe; otherwise guard to avoid NPEs when these fields are unset.

Optionally:

-        addUserFields(programEncounter.getLastModifiedBy(), resource, "lastModifiedBy");
-        addUserFields(programEncounter.getCreatedBy(), resource, "createdBy");
+        if (programEncounter.getLastModifiedBy() != null)
+            addUserFields(programEncounter.getLastModifiedBy(), resource, "lastModifiedBy");
+        if (programEncounter.getCreatedBy() != null)
+            addUserFields(programEncounter.getCreatedBy(), resource, "createdBy");
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f8467ca and d08311b.

📒 Files selected for processing (8)
  • avni-server-api/src/main/java/org/avni/server/service/EncounterService.java (2 hunks)
  • avni-server-api/src/main/java/org/avni/server/service/ProgramEncounterService.java (4 hunks)
  • avni-server-api/src/main/java/org/avni/server/web/EncounterController.java (2 hunks)
  • avni-server-api/src/main/java/org/avni/server/web/ProgramEncounterController.java (1 hunks)
  • avni-server-api/src/main/resources/db/migration/V1_353__AddAuditFields.sql (1 hunks)
  • avni-server-api/src/test/java/org/avni/server/service/ProgramEncounterServiceTest.java (1 hunks)
  • avni-server-api/src/test/java/org/avni/server/web/ProgramEncounterControllerIntegrationTest.java (1 hunks)
  • avni-server-data/src/main/java/org/avni/server/domain/AbstractEncounter.java (2 hunks)
🔇 Additional comments (5)
avni-server-api/src/main/java/org/avni/server/web/EncounterController.java (1)

286-287: LGTM: expose createdBy/lastModifiedBy in resource

Serialization parity with ProgramEncounter is good. Just ensure addUserFields tolerates nulls.

avni-server-api/src/test/java/org/avni/server/web/ProgramEncounterControllerIntegrationTest.java (1)

44-44: No functional change

EOF newline only. Nothing to do.

avni-server-api/src/main/java/org/avni/server/service/EncounterService.java (1)

157-158: LGTM: update lastModifiedBy on schedule changes

Appropriate place to capture modification.

avni-server-api/src/main/java/org/avni/server/service/ProgramEncounterService.java (1)

128-129: LGTM: touch lastModifiedBy on schedule updates

Correct audit behavior.

avni-server-data/src/main/java/org/avni/server/domain/AbstractEncounter.java (1)

68-74: LGTM: JPA mappings for createdBy/lastModifiedBy

Lazy ManyToOne with explicit join columns matches the migration.

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.

1 participant