fix: derive calendar days in the app timezone, not UTC - #32
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
5 tasks
The dashboard computed today/week/month via appDateBoundaries()
(Asia/Jerusalem) while every write path used
`new Date().toISOString().split("T")[0]` — the UTC day. lib/dates.ts was
imported by exactly one file.
Two bugs, very different blast radius:
1. Ad-hoc reports: `new Date(y, m, 1).toISOString().split("T")[0]` builds
LOCAL midnight of the 1st and serializes it as UTC, so east of
Greenwich the "first day of this month" preset resolved to the
PREVIOUS month's last day — 100% of the time, silently pulling an
extra day into every default report.
2. Timer/entry dates: a 2-3h nightly window (00:00-03:00 local) where a
new entry landed on yesterday. /api/timer/stop never rewrites `date`,
so it stayed wrong permanently.
All call sites now use appToday() / appDateBoundaries().startOfMonth,
including paid_at, the CSV import sample row, and the task overdue check.
The 12-month chart window moves off CURRENT_DATE (DB session clock) onto
the same app-timezone month start as the rest of the handler — verified
against prod: identical window, identical row count.
No migration, no change to existing rows.
nioasoft
force-pushed
the
fix/app-timezone-day-boundaries
branch
from
August 2, 2026 08:08
b165a58 to
390484f
Compare
nioasoft
added a commit
that referenced
this pull request
Aug 2, 2026
…k the UI/UX audit (#35) * chore: ignore local agent caches, security audits and logo artifacts Three classes of local-only files were sitting untracked in the working tree and would be swept in by any `git add .`: - .mimocode/ — another agent tool's local cache (~56MB) - docs/*security-audit*.html, docs/*security-review*.html — THIS REPO IS PUBLIC. The three reports enumerate findings with file:line evidence (SSRF surface, cron auth, upload handling, token storage) and embed local absolute paths. Committing them would publish a remediation roadmap to anyone. Keep local, share out-of-band. - public/logos/ + scripts/generate_html.py — logo exploration from the rebrand. Referenced by no code, and anything under public/ is served publicly; logo_data.json alone is ~2MB of base64. Nothing is deleted from disk — these stay locally, they just stop following the repo around. * docs: refresh CLAUDE.md and correct two wrong instructions in AGENTS.md CLAUDE.md: condensed to the non-obvious. Drops guidance that had gone stale — lib/db.ts initSchema() (removed from the codebase) and the "Prod TODO: set Vercel DATABASE_URL=clockbill_app" (done long ago). AGENTS.md was untracked and had drifted into actively harmful territory: - It opened with `docker compose up -d # PostgreSQL on :5432` and described a `clockbill-db` dev container. There is no local dev DB — .env.local points at the Neon dev branch. CI gets Postgres from GitHub Actions `services:`, not docker-compose.yml; nothing but AGENTS.md referenced that file. - It listed `npm run db:migrate` as the way to apply migrations. That is the one command CLAUDE.md forbids (drizzle journal out of sync) and it has caused a production outage. Replaced with the db:apply flow. Also documents the date/timezone traps found while fixing #32: derive calendar days via lib/dates.ts, never toISOString(); and `date` columns (OID 1082) deserialize as Date objects while typed `string`. Notes that the CI audit gate runs first, so a failure there makes every later step report `skipped` — which reads as "tests passed" but means they never ran. * docs: add the 2026-07-10 UI/UX audit Matches the existing docs/ convention (docs/product-ux-refresh/, docs/superpowers/plans/). The screenshots need -f because .gitignore blanket-ignores *.png; without them index.html renders with broken images. Verified the dashboard capture is an empty test account — no client names or amounts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
למה
הדשבורד מחשב גבולות today/week/month דרך
appDateBoundaries()ב-Asia/Jerusalem, אבל כל נתיבי הכתיבה השתמשו ב-new Date().toISOString().split("T")[0]— היום ב-UTC.lib/dates.tsנכתב בדיוק בשביל זה ויובא ע"י קובץ אחד בלבד.שני באגים, חומרה שונה לגמרי
1. דוחות — קרה 100% מהזמן⚠️
בונה חצות מקומית של ה-1 בחודש ומסריאל כ-UTC. ממזרח לגריניץ' זה היום האחרון של החודש הקודם:
כל דוח "החודש הזה" גרר בשקט יום מהחודש הקודם. 4 מופעים ב-
AdHocReportTab.2. תאריך רשומה/טיימר — חלון לילי
api/timer/startנרשם על היום ב-UTC, ו-api/timer/stopלא כותבdateבכלל — טיימר שמתחיל בין 00:00 ל-03:00 שעון ישראל נשאר על אתמול לצמיתות. עדיין לא נדפק בפרוד (drift 193/203 באפס) כי העבודה היא ביום.שינויים
api/timer/start,api/tasks/[id]/movetoISOString()→appToday()entries/page.tsxAdHocReportTab.tsxChargePaymentsPanelpaid_at— כסףentries/importtask-cardapi/dashboard/statsCURRENT_DATE(שעון ה-DB) →startOfMonthStrlib/dates.tsהוא Intl + Date טהור, לכן נטען גם בקומפוננטות לקוח. הבחירה ב-Asia/Jerusalemקשיח (ולא ביום המקומי של הדפדפן) מיישרת את ברירות המחדל עם הגבולות שהשרת מחשב.Test plan
npx tsc --noEmit→ 0npm run lint→ נקי (gate של zero-warning)npm test→ 73 קבצים, 0 נכשלוnpm run build→ עברtests/unit/app-today.test.ts— 17 assertions: שעון קיץ/חורף, חצות מקומית, סוף פברואר, מעבר DST ב-25.10, ו-startOfMonthשחייב להיות ה-12025-09-01), 203 שורות מול 203ללא מיגרציה. ללא שינוי בשורות קיימות.
נדחה בכוונה
types.setTypeParser(1082, v => v)ב-lib/db.ts—lib/db.ts:18-20דורס את הפרסר שלtimestamp(OID 1114) אבל לא שלdate(1082), ולכן עמודותdateחוזרות כאובייקטDateלמרות שהן מטופסותstring. כבר גרם לקראש (ההערה ב-app/api/reports/route.ts:530-537) ול-workaround ב-app/[locale]/entries/page.tsx:605. תיקון של שתי שורות שמחסל את כל הקטגוריה, אבל blast radius של כל route שקוראdate, והוא לא משפיע על משתמשים ישראלים (Vercel ב-UTC + דפדפן ב-UTC+3 מתקזזים). להרים כשיהיה משתמש ראשון ממערב ל-UTC.