Skip to content

fix: store work entry dates as ISO strings instead of epoch milliseconds#747

Open
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1778604304-fix-date-serialization-bug
Open

fix: store work entry dates as ISO strings instead of epoch milliseconds#747
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1778604304-fix-date-serialization-bug

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented May 12, 2026

Summary

Work entry dates were being stored in SQLite as epoch milliseconds (e.g., 1778544000000) instead of ISO date strings (e.g., "2026-05-12"). This corrupted CSV/PDF exports and API responses.

Root cause: Joi's date().iso() validator converts date strings to JavaScript Date objects. When sqlite3 binds a Date object, it calls .valueOf() producing an epoch timestamp in milliseconds.

Fix: Changed the Joi validation schema from Joi.date().iso() to Joi.string().pattern(/^\d{4}-\d{2}-\d{2}$/), which validates the YYYY-MM-DD format without converting to a Date object.

Additional fix: Enabled PRAGMA foreign_keys = ON in the database initialization so that ON DELETE CASCADE constraints actually work (SQLite has foreign keys OFF by default).

Before

CSV exports showed epoch timestamps instead of dates:
Before - CSV showing epoch timestamps

After

CSV exports now show proper ISO dates:
After - CSV showing proper dates

Review & Testing Checklist for Human

  • Create a work entry and verify the API response contains a date string like "2026-05-12" (not a number)
  • Export a client report as CSV and confirm dates appear as YYYY-MM-DD
  • Export a client report as PDF and confirm dates are human-readable
  • Delete a client that has work entries and confirm the work entries are also deleted (cascade)
  • Try submitting an invalid date format (e.g., 05/12/2026) and confirm it's rejected with a clear error

Notes

  • All 161 backend tests pass
  • Frontend lint and build pass
  • See ROOT_CAUSE_ANALYSIS.md for detailed bug documentation

Link to Devin session: https://partner-workshops.devinenterprise.com/sessions/608e673002f14154a9c03740d66cd851


Open in Devin Review

- Changed Joi date validation from date().iso() (which converts to Date
  objects) to string().pattern() (which preserves the YYYY-MM-DD string)
- This fixes CSV/PDF exports showing dates as epoch timestamps like
  1778544000000 instead of readable dates like 2026-05-12
- Also enabled PRAGMA foreign_keys in SQLite init to fix cascade deletes
- Added ROOT_CAUSE_ANALYSIS.md documenting the bug and fix
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Contributor Author

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 3 additional findings in Devin Review.

Open in Devin Review

Comment on lines +14 to +16
date: Joi.string().pattern(/^\d{4}-\d{2}-\d{2}$/).required().messages({
'string.pattern.base': '"date" must be a valid ISO date (YYYY-MM-DD)'
})
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🟡 Date regex accepts semantically invalid dates (e.g., month 13, day 32)

The regex /^\d{4}-\d{2}-\d{2}$/ only validates the YYYY-MM-DD format but does not validate that the date is semantically valid. It will accept strings like "2026-13-32", "2026-00-00", "2026-02-30" (Feb 30), etc., and store them in the database. The previous Joi.date().iso() would reject these because it parsed the string into a JavaScript Date object and verified validity. The error message '"date" must be a valid ISO date (YYYY-MM-DD)' is also misleading since the check doesn't verify it's actually a valid date. This applies to both workEntrySchema and updateWorkEntrySchema.

Prompt for agents
The regex /^\d{4}-\d{2}-\d{2}$/ only checks YYYY-MM-DD format but accepts impossible dates like 2026-13-32 or 2026-02-30. The fix correctly avoids Joi.date().iso() (which converts strings to Date objects), but should add a .custom() validator to verify the date is semantically valid. For example, after the pattern check, add a Joi .custom() call that parses the string with new Date(value + 'T00:00:00Z') and verifies the result is not NaN and round-trips back to the same string. This should be applied to both workEntrySchema (line 14) and updateWorkEntrySchema (line 23) in backend/src/validation/schemas.js.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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.

0 participants