Skip to content

feat: added timestamp fields (MR-78) - #260

Merged
miguelccodev merged 6 commits into
developfrom
mr-78--feat--timestamp-fields
Jun 3, 2026
Merged

feat: added timestamp fields (MR-78)#260
miguelccodev merged 6 commits into
developfrom
mr-78--feat--timestamp-fields

Conversation

@miguelccodev

@miguelccodev miguelccodev commented May 28, 2026

Copy link
Copy Markdown
Contributor

Changes

  • added created_at for newly created documents
  • added updated_at for updated documents
  • fix: reverted version changes
  • fix: added sugar coat for backwards compatibility of used class for iso date generation

How to test

  • run emulator
  • select poc language
  • open ftm dev
  • finish any level
  • observe created_at, updated_at properties in summary_data

Ref: MR-78

Summary by CodeRabbit

  • Chores

    • Enabled Java core library desugaring for broader runtime compatibility.
    • Updated IDE project configuration.
  • Enhancements

    • Added a schema version field to event payloads.
    • Adjusted event/session record handling: timestamps are now stored as created_at/updated_at, and payload validation now requires a non-empty collection identifier.

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a public payload schema_version, refactors the payload handler to populate created_at/updated_at/schema_version and tighten validation, enables Java core library desugaring in the app build, and updates IntelliJ Gradle IDE settings.

Changes

Payload metadata, SDK/desugaring, and IDE config

Layer / File(s) Summary
IDE Gradle settings
.idea/gradle.xml
Adds testRunner="CHOOSE_PER_TEST" and removes resolveExternalAnnotations.
Enable Java core library desugaring
app/build.gradle
Enables coreLibraryDesugaringEnabled and adds com.android.tools:desugar_jdk_libs:2.1.4 dependency.
Add payload schema_version field
app/src/main/java/org/curiouslearning/container/core/subapp/payload/AppEventPayload.java
Adds public String schema_version to AppEventPayload.
Handler: timestamp, schema and validation changes
app/src/main/java/org/curiouslearning/container/core/subapp/handler/DefaultAppEventPayloadHandler.java
Imports Instant; adjusts accepted-payload logging and validation (require non-empty normalized collection, drop timestamp requirement); for user_sessions_data writes created_at and schema_version; for summary_data initializes record earlier and sets created_at, updated_at, and schema_version on create/update paths.

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Possibly related PRs:

  • Suggested reviewers:

    • dz4va

Poem

🐰
I hopped through code with a curious cheer,
Gave payloads a version so schemas are clear.
Timestamps now blossom where records once slept,
Java desugared — new APIs adept.
Carrots in commits, the rabbit's code leap!

🚥 Pre-merge checks | ✅ 4 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Tests & Lint & Coverage ⚠️ Warning No tests added for modified DefaultAppEventPayloadHandler and AppEventPayload classes; no project linting configured or executed; no 70% coverage threshold enforced or verified. Add unit tests for DefaultAppEventPayloadHandler and AppEventPayload; configure and enable linting (Android Lint or checkstyle); establish and verify 70% code coverage for changed classes.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: added timestamp fields (MR-78)' accurately describes the main changes: adding created_at and updated_at timestamp fields to documents, and includes the required JIRA key (MR-78).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mr-78--feat--timestamp-fields

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.

@miguelccodev miguelccodev changed the title Mr 78 feat timestamp fields feat: added timestamp fields (MR-78) May 28, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (1)
app/src/main/java/org/curiouslearning/container/core/subapp/handler/DefaultAppEventPayloadHandler.java (1)

147-166: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve metadata when updating existing summary docs.

storeSummaryPayload updates an existing document with set(record) where record only contains cr_user_id, app_id, data, and updated_at. Since Firestore set(map) overwrites the whole document by default (no SetOptions.merge), the first update will delete metadata fields that createNewSummaryDoc initially writes: collection, created_at, and schema_version.

🛠️ Suggested fix
         Map<String, Object> record = new HashMap<>();
         record.put("cr_user_id", payload.cr_user_id);
         record.put("app_id", payload.app_id);
+        record.put("collection", payload.collection);
+        record.put(
+                "schema_version",
+                payload.schema_version != null && !payload.schema_version.trim().isEmpty()
+                        ? payload.schema_version
+                        : "unknown"
+        );

         query.get()
                 .addOnSuccessListener(querySnapshot -> {
                     if (!querySnapshot.isEmpty()) {
@@
                         Map<String, Object> mergedData =
                                 mergeData(existingDoc, payload);

                         record.put("data", mergedData);
+                        Object createdAt = existingDoc.get("created_at");
+                        if (createdAt != null) {
+                            record.put("created_at", createdAt);
+                        }
                         record.put("updated_at", Instant.now().toString());

                         db.collection(payload.collection)
                                 .document(existingDoc.getId())
                                 .set(record)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/src/main/java/org/curiouslearning/container/core/subapp/handler/DefaultAppEventPayloadHandler.java`
around lines 147 - 166, storeSummaryPayload currently overwrites existing
summary docs because it calls
db.collection(...).document(existingDoc.getId()).set(record) with a map that
lacks metadata; change this to merge the fields instead of replacing the
document by calling set with merge options so metadata written by
createNewSummaryDoc (fields like collection, created_at, schema_version) are
preserved; locate the call in DefaultAppEventPayloadHandler (method
storeSummaryPayload) and replace the plain set(...) with the Firestore set that
uses SetOptions.merge (or equivalent merge parameter) while still writing
updated_at and the merged data produced by mergeData.
🧹 Nitpick comments (1)
.idea/gradle.xml (1)

7-7: 💤 Low value

Consider removing or ignoring .idea/gradle.xml (testRunner preference)

.idea/gradle.xml is tracked and is not ignored by git. The repo also has .idea/.gitignore, but it ignores workspace.xml and modules.xml while gradle.xml (and some other .idea/* files) remain committed—suggesting this change is likely per-developer/auto-generated. If it’s accidental, remove it and update ignore rules; if the team intentionally wants a shared test runner setting, call out the intent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.idea/gradle.xml at line 7, The committed .idea/gradle.xml containing the
testRunner preference (option name="testRunner" value="CHOOSE_PER_TEST") appears
to be an IDE-specific, per-developer file and should be removed from version
control or explicitly curated; either remove the file from the repo and add
gradle.xml (and other non-shared .idea files) to the repository ignore rules, or
if this setting is intended to be shared, add a short note in the repo/team
guidelines explaining that option and why it must be versioned. To fix: delete
.idea/gradle.xml from the index (so it’s no longer tracked), update
.idea/.gitignore to include gradle.xml (and any other unintended .idea files),
and commit the ignore change, or conversely keep the file and add documentation
indicating the deliberate shared setting for testRunner.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@app/src/main/java/org/curiouslearning/container/core/subapp/handler/DefaultAppEventPayloadHandler.java`:
- Around line 147-166: storeSummaryPayload currently overwrites existing summary
docs because it calls
db.collection(...).document(existingDoc.getId()).set(record) with a map that
lacks metadata; change this to merge the fields instead of replacing the
document by calling set with merge options so metadata written by
createNewSummaryDoc (fields like collection, created_at, schema_version) are
preserved; locate the call in DefaultAppEventPayloadHandler (method
storeSummaryPayload) and replace the plain set(...) with the Firestore set that
uses SetOptions.merge (or equivalent merge parameter) while still writing
updated_at and the merged data produced by mergeData.

---

Nitpick comments:
In @.idea/gradle.xml:
- Line 7: The committed .idea/gradle.xml containing the testRunner preference
(option name="testRunner" value="CHOOSE_PER_TEST") appears to be an
IDE-specific, per-developer file and should be removed from version control or
explicitly curated; either remove the file from the repo and add gradle.xml (and
other non-shared .idea files) to the repository ignore rules, or if this setting
is intended to be shared, add a short note in the repo/team guidelines
explaining that option and why it must be versioned. To fix: delete
.idea/gradle.xml from the index (so it’s no longer tracked), update
.idea/.gitignore to include gradle.xml (and any other unintended .idea files),
and commit the ignore change, or conversely keep the file and add documentation
indicating the deliberate shared setting for testRunner.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 037c125a-edbe-4dd1-8ba1-f5b4b95dd8d8

📥 Commits

Reviewing files that changed from the base of the PR and between b6e3eb5 and f725d0b.

📒 Files selected for processing (5)
  • .idea/gradle.xml
  • .idea/misc.xml
  • app/build.gradle
  • app/src/main/java/org/curiouslearning/container/core/subapp/handler/DefaultAppEventPayloadHandler.java
  • app/src/main/java/org/curiouslearning/container/core/subapp/payload/AppEventPayload.java
💤 Files with no reviewable changes (1)
  • .idea/misc.xml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (2)
app/src/main/java/org/curiouslearning/container/core/subapp/handler/DefaultAppEventPayloadHandler.java (2)

45-48: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Update the shared validator if timestamp is no longer required.

Line 45 relaxes the handler-side checks, but WebApp.java still calls AppEventPayloadValidator.validate() first, and that validator rejects any payload with a blank timestamp. On the main path, clients that stop sending timestamp will still be dropped before handle() runs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/src/main/java/org/curiouslearning/container/core/subapp/handler/DefaultAppEventPayloadHandler.java`
around lines 45 - 48, The handler relaxed checks for timestamp in
DefaultAppEventPayloadHandler, but AppEventPayloadValidator.validate() still
rejects blank timestamps; update the shared validator so it no longer requires a
non-blank timestamp (or treats timestamp as optional) to match the handler
logic: modify AppEventPayloadValidator.validate() to skip or allow empty/null
payload.timestamp (and update any error messages/tests that assert timestamp
presence) so WebApp.java’s pre-validate step won't drop payloads before
DefaultAppEventPayloadHandler.handle() runs.

179-182: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Don't create a new summary document when the lookup fails.

Lines 179-182 treat any Firestore query error the same as “no existing record” and immediately call createNewSummaryDoc(). On transient failures, that can create a second summary_data document for the same (cr_user_id, app_id) pair; after that, limit(1) updates an arbitrary copy and the summary state diverges across duplicates.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/src/main/java/org/curiouslearning/container/core/subapp/handler/DefaultAppEventPayloadHandler.java`
around lines 179 - 182, The failure handler in DefaultAppEventPayloadHandler
currently treats any Firestore query error as "no record" and calls
createNewSummaryDoc; remove that call from the addOnFailureListener and instead
only log the error (or surface it to the caller) so new summary documents are
created exclusively from the addOnSuccessListener when the query returns empty
results. Update the listener attached to the Firestore lookup so
createNewSummaryDoc(db, payload, record) is invoked only in the success path
when no documents are found, and ensure addOnFailureListener(e -> { Log.w(TAG,
"...", e); /* propagate/return or handle error */ }) does not create new
documents.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@app/src/main/java/org/curiouslearning/container/core/subapp/handler/DefaultAppEventPayloadHandler.java`:
- Around line 162-167: The update path in DefaultAppEventPayloadHandler that
merges mergedData into record and writes to payload.collection for existingDoc
(document id from existingDoc.getId()) does not set schema_version, so summaries
retain stale/unknown values; modify that update block to set
record.put("schema_version", <the same source used by createNewSummaryDoc(),
e.g., payload.schemaVersion or whatever field createNewSummaryDoc uses>) before
calling .set(record, SetOptions.merge()) so both new and existing summary docs
have an up-to-date schema_version.

---

Outside diff comments:
In
`@app/src/main/java/org/curiouslearning/container/core/subapp/handler/DefaultAppEventPayloadHandler.java`:
- Around line 45-48: The handler relaxed checks for timestamp in
DefaultAppEventPayloadHandler, but AppEventPayloadValidator.validate() still
rejects blank timestamps; update the shared validator so it no longer requires a
non-blank timestamp (or treats timestamp as optional) to match the handler
logic: modify AppEventPayloadValidator.validate() to skip or allow empty/null
payload.timestamp (and update any error messages/tests that assert timestamp
presence) so WebApp.java’s pre-validate step won't drop payloads before
DefaultAppEventPayloadHandler.handle() runs.
- Around line 179-182: The failure handler in DefaultAppEventPayloadHandler
currently treats any Firestore query error as "no record" and calls
createNewSummaryDoc; remove that call from the addOnFailureListener and instead
only log the error (or surface it to the caller) so new summary documents are
created exclusively from the addOnSuccessListener when the query returns empty
results. Update the listener attached to the Firestore lookup so
createNewSummaryDoc(db, payload, record) is invoked only in the success path
when no documents are found, and ensure addOnFailureListener(e -> { Log.w(TAG,
"...", e); /* propagate/return or handle error */ }) does not create new
documents.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3c1b71fd-63f1-4bbe-adb9-91d4393454b2

📥 Commits

Reviewing files that changed from the base of the PR and between 962e190 and 21d03b9.

📒 Files selected for processing (1)
  • app/src/main/java/org/curiouslearning/container/core/subapp/handler/DefaultAppEventPayloadHandler.java

Comment on lines 162 to +167
record.put("data", mergedData);

record.put("updated_at", Instant.now().toString());

db.collection(payload.collection)
.document(existingDoc.getId())
.set(record)
.set(record, SetOptions.merge())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Persist schema_version on the summary update path as well.

Lines 162-167 only update data and updated_at. New summary docs get schema_version in createNewSummaryDoc(...), but existing docs never refresh it, so older records keep stale or "unknown" values even after newer payloads arrive.

Suggested fix
                         record.put("data", mergedData);
                         record.put("updated_at", Instant.now().toString());
+                        record.put(
+                                "schema_version",
+                                payload.schema_version != null
+                                        ? payload.schema_version
+                                        : "unknown"
+                        );
                         
                         db.collection(payload.collection)
                                 .document(existingDoc.getId())
                                 .set(record, SetOptions.merge())
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/src/main/java/org/curiouslearning/container/core/subapp/handler/DefaultAppEventPayloadHandler.java`
around lines 162 - 167, The update path in DefaultAppEventPayloadHandler that
merges mergedData into record and writes to payload.collection for existingDoc
(document id from existingDoc.getId()) does not set schema_version, so summaries
retain stale/unknown values; modify that update block to set
record.put("schema_version", <the same source used by createNewSummaryDoc(),
e.g., payload.schemaVersion or whatever field createNewSummaryDoc uses>) before
calling .set(record, SetOptions.merge()) so both new and existing summary docs
have an up-to-date schema_version.

@miguelccodev
miguelccodev merged commit 3da1f82 into develop Jun 3, 2026
1 check passed
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.

4 participants