fix(timestamps) Store create and update times as timestamp with time zone #37

Open
araemer wants to merge 3 commits from timestamptz-create-update-date into stage
Owner

Fixes #24.

What

  • Migration 1792886400000-ConvertCreateUpdateDateToTimestamptz: converts create_date and update_date on the 16 zone-less AbstractEntity tables, plus user_passkey_challenge.created_at, to TIMESTAMP WITH TIME ZONE. Existing values are interpreted as UTC (AT TIME ZONE 'UTC', spelled out rather than current_setting('TimeZone')). Stage and production have always run in UTC, so no stored value moves. recipe_image, ai_recipe_import_log and user_session were already time-zone-aware. down() reverses the conversion.
  • Entities: AbstractEntity, AiRecipeImportLogEntity, UserSessionEntity and PasskeyChallengeEntity declare timestamp with time zone.
  • UTC sessions: AppDataSource and the integration data source connect with -c timezone=UTC (DB_SESSION_TIME_ZONE in src/utils/dateUtils.ts).
  • Mapper fix: mapBaseDtoToEntity no longer copies the client's createdAt / updatedAt onto the entity. TypeORM 0.3.27 writes those values on insert, and on update whenever they differ from the stored row, so clients could set their own timestamps (written in Node's zone). Update paths reload the entity after saving, so responses still carry both values.
  • Docs: ADR docs/adr/2026-10-25-utc-time-zone-aware-timestamps.md, docs/architecture.md.

No wire-format change; no contract or recipe-app change.

⚠️ Deployment order

This must be released to production before the database server's TimeZone is moved to Europe/Berlin. Rows written after the move but before this migration would hold Berlin wall-clock readings and be shifted by the conversion. After the migration, the server zone only affects how psql displays values.

On a local development database whose zone is Europe/Berlin, the migration shifts existing dev values by 1–2 hours. That's harmless.

Verification

  • npm run build: passes
  • npm test: 57 files, 622 tests passing
  • npm run test:integration: 45 tests passing (runs every migration, including the new one, into a fresh schema)
  • Checked the conversion round trip in PostgreSQL under a Europe/Berlin session: '2026-10-24 18:00' → 2026-10-24 20:00+02 → '2026-10-24 18:00'
  • Not run against the development database

🤖 Generated with Claude Code

Fixes #24. ## What - **Migration** `1792886400000-ConvertCreateUpdateDateToTimestamptz`: converts `create_date` and `update_date` on the 16 zone-less `AbstractEntity` tables, plus `user_passkey_challenge.created_at`, to `TIMESTAMP WITH TIME ZONE`. Existing values are interpreted as UTC (`AT TIME ZONE 'UTC'`, spelled out rather than `current_setting('TimeZone')`). Stage and production have always run in UTC, so no stored value moves. `recipe_image`, `ai_recipe_import_log` and `user_session` were already time-zone-aware. `down()` reverses the conversion. - **Entities**: `AbstractEntity`, `AiRecipeImportLogEntity`, `UserSessionEntity` and `PasskeyChallengeEntity` declare `timestamp with time zone`. - **UTC sessions**: `AppDataSource` and the integration data source connect with `-c timezone=UTC` (`DB_SESSION_TIME_ZONE` in `src/utils/dateUtils.ts`). - **Mapper fix**: `mapBaseDtoToEntity` no longer copies the client's `createdAt` / `updatedAt` onto the entity. TypeORM 0.3.27 writes those values on insert, and on update whenever they differ from the stored row, so clients could set their own timestamps (written in Node's zone). Update paths reload the entity after saving, so responses still carry both values. - **Docs**: ADR `docs/adr/2026-10-25-utc-time-zone-aware-timestamps.md`, `docs/architecture.md`. No wire-format change; no contract or recipe-app change. ## ⚠️ Deployment order This must be released to production **before** the database server's `TimeZone` is moved to Europe/Berlin. Rows written after the move but before this migration would hold Berlin wall-clock readings and be shifted by the conversion. After the migration, the server zone only affects how `psql` displays values. On a local development database whose zone is Europe/Berlin, the migration shifts existing dev values by 1–2 hours. That's harmless. ## Verification - `npm run build`: passes - `npm test`: 57 files, 622 tests passing - `npm run test:integration`: 45 tests passing (runs every migration, including the new one, into a fresh schema) - Checked the conversion round trip in PostgreSQL under a Europe/Berlin session: `'2026-10-24 18:00'` → `2026-10-24 20:00+02` → `'2026-10-24 18:00'` - Not run against the development database 🤖 Generated with [Claude Code](https://claude.com/claude-code)
TypeORM writes an entity's createDate and updateDate as given on insert, and on
update whenever they differ from the stored row, so a client could set its own
timestamps. Only the database writes both columns now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Converts create_date and update_date on every zone-less AbstractEntity table and
user_passkey_challenge.created_at to TIMESTAMP WITH TIME ZONE, interpreting the
existing values as UTC. Every database session now runs in UTC. Refs #24.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs(adr) Record time-zone-aware timestamps and UTC database sessions
All checks were successful
/ test (pull_request) Successful in 1m10s
/ contract_pin (pull_request) Successful in 2s
9685cf2779
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
All checks were successful
/ test (pull_request) Successful in 1m10s
/ contract_pin (pull_request) Successful in 2s
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin timestamptz-create-update-date:timestamptz-create-update-date
git switch timestamptz-create-update-date

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch stage
git merge --no-ff timestamptz-create-update-date
git switch timestamptz-create-update-date
git rebase stage
git switch stage
git merge --ff-only timestamptz-create-update-date
git switch timestamptz-create-update-date
git rebase stage
git switch stage
git merge --no-ff timestamptz-create-update-date
git switch stage
git merge --squash timestamptz-create-update-date
git switch stage
git merge --ff-only timestamptz-create-update-date
git switch stage
git merge timestamptz-create-update-date
git push origin stage
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
araemer/recipe-backend!37
No description provided.