Commit Graph

996 Commits

Author SHA1 Message Date
jubnl fdb12aed1e test(files): upload filters fail closed on an excluded or unresolvable type 2026-09-22 01:21:57 +02:00
jubnl fc49c0c768 refactor(tokens): async DB-touching methods; the auth token handlers await them 2026-09-22 01:21:29 +02:00
jubnl 4700bb38a5 test(server): suites await the methods earlier sweep groups made async 2026-09-22 01:16:50 +02:00
jubnl 7940b7ff84 refactor(auth, files): async DB-touching methods; transactions through UnitOfWork 2026-09-22 01:08:22 +02:00
jubnl 4df2d83137 refactor(notifications, place-photos, backup): async DB-touching methods; transactions through UnitOfWork 2026-09-22 00:22:11 +02:00
jubnl fac181f45b chore(plugins): drop gate-only asyncs; observe the scheduler's rejection; async event-sink stub 2026-09-22 00:12:56 +02:00
jubnl 5d590ca5b1 chore(server): db-call-graph --sync stops its transitive walk at an async callee 2026-09-22 00:04:19 +02:00
jubnl e28dc6de28 refactor(plugins): async DB-touching methods; transactions through UnitOfWork 2026-09-22 00:00:53 +02:00
jubnl e413308227 refactor(llm-parse, mcp-shared, oauth, place-shadow, route-usage, storage, todo, trip-invite): async DB-touching methods; transactions through UnitOfWork 2026-09-21 23:27:01 +02:00
jubnl bb390a5407 chore(server): db-call-graph --unawaited lists calls to async methods whose result is used without await 2026-09-21 22:55:02 +02:00
jubnl 7daf98cf70 test(oauth): controller suite awaits the async service 2026-09-21 22:41:35 +02:00
jubnl aa587e2fb6 refactor(budget, common, day-notes, days): async DB-touching methods; transactions through UnitOfWork 2026-09-21 22:39:11 +02:00
jubnl 8bdc730b20 test(server): suites await the methods Task 1's forced edits made async 2026-09-21 21:54:19 +02:00
jubnl d73215f7f6 chore(server): lint rule refusing a Promise used as a plain value, and the misses it found 2026-09-21 21:39:39 +02:00
jubnl 953e2526bb refactor(atlas, school-holidays, settings): async DB-touching methods; transactions through UnitOfWork 2026-09-21 21:23:10 +02:00
jubnl f6c17938c3 test(doc-sync): unit suites await the methods the async sweep made async 2026-09-21 21:11:01 +02:00
jubnl 8de5171a8e fix(server): observe every promise the async sweep left unobserved (timer, handshake, plugin-runtime test) 2026-09-21 21:04:19 +02:00
jubnl 0cf99a9939 refactor(realtime, systemNotices, addons, airports, audit, categories, permissions, query-helpers, tags, transit, trip-membership): async DB-touching methods; transactions through UnitOfWork 2026-09-21 20:48:03 +02:00
jubnl 27d044f9e8 chore(server): promise safety net and sweep tooling for the async migration 2026-09-21 19:01:38 +02:00
jubnl ef184ec7c2 test(server): ORM suites open the schema snapshot; RESET_TABLES derived from the schema 2026-09-21 18:12:07 +02:00
jubnl f4fe27a3f8 fix(db): dialect helpers dispatch on the platform; lint gate for the repository layer 2026-09-21 18:12:07 +02:00
jubnl d7c7afea1b test(server): coverage's uncovered-file pass goes through the SWC transform 2026-09-21 11:06:42 +02:00
jubnl 2c7a5fcda6 test(server): websocket suites boot on the migrated schema snapshot 2026-09-21 11:03:16 +02:00
jubnl f0c6cd18b3 test(db): coverage ratchet entries for the ORM foundation 2026-09-21 11:01:44 +02:00
jubnl 418bd1c6b5 fix(test): route MikroORM's dynamic imports through vitest from the setup file, not the ORM config 2026-09-21 10:35:16 +02:00
jubnl 2bc9e927be test(server): snapshot harness keeps the legacy id semantics 2026-09-21 10:22:18 +02:00
jubnl e846c91a16 test(server): integration suites boot on the migrated schema snapshot 2026-09-21 10:13:40 +02:00
jubnl d7f39916d5 feat(db): request-context and unit-of-work helpers for the ORM, with concurrency tests 2026-09-21 10:01:36 +02:00
jubnl 443dc35c03 fix(db): repositories mirror the statement's column set and guard their row types 2026-09-21 09:54:15 +02:00
jubnl 229f4890df feat(db): snake_case entity shape and the first three repositories (Days, DayNotes, Trips) 2026-09-21 09:39:40 +02:00
jubnl 479e2cb0a5 test(db): dialect helper refuses malformed column references and day counts 2026-09-21 09:27:05 +02:00
jubnl 5691f966af feat(db): dialect helper is the one place SQL functions are spelled 2026-09-21 09:19:47 +02:00
jubnl 565f72740b test(db): createTestOrm binds an ORM to a suite's own SQLite handle 2026-09-21 09:17:17 +02:00
jubnl 9ca9ca9644 feat(db): discover entities from an explicit list instead of a glob 2026-09-21 08:50:56 +02:00
jubnl 4ba43d6cd5 feat(db): DbTimestampType keeps DATETIME columns as the CURRENT_TIMESTAMP text 2026-09-21 08:50:56 +02:00
jubnl 57decad494 Merge remote-tracking branch 'origin/dev' into feat/orm 2026-09-20 21:45:48 +02:00
jubnl 70e970453e migrations + seeders 2026-09-20 21:38:32 +02:00
jubnl 55ad55e90b rename entities 2026-09-20 20:05:18 +02:00
jubnl 7cd9ba3dcb fix date as string 2026-09-20 19:55:13 +02:00
Maurice be9a38e3b0 fix(accommodations): a second night on the day counts by its check-in
Two bookings on one day used to settle by whichever was seated last, because
the other night's stop carries no hour of its own. Its check-in counts now,
in the service and in the migration alike.
2026-09-20 18:48:26 +02:00
Maurice 417d0445b9 fix(roadtrip): seat the nights booked before this release where their check-in says
A booked night leads its day now, but the stops the bookings put on their
check-in day before this release sit last, and the backfill for older
bookings appended them too. Every trip planned before the change kept that
order until somebody edited the check-in.

A migration seats every night a booking owns by the same rule the service
applies: first, behind only a stop whose own clock is at or before the
check-in. The drawn roads follow the stops they were drawn after, by the
rules the service uses when it moves a night. Stops the traveller placed
themselves are not touched. Re-runnable.
2026-09-20 18:45:37 +02:00
Maurice a86e4b560a test(accommodations): a quiet edit still corrects a night the clocks contradict
Covers seatedByCheckIn with a check-in set, which the re-seat on a new
check-in no longer passes through, so the accommodations function ratchet
held.
2026-09-20 17:49:54 +02:00
jubnl 235ef31b11 Merge branch 'dev' into feat/orm 2026-09-20 17:28:02 +02:00
Maurice cd769d9993 fix(roadtrip): a booked night holds its check-in and heads its day
A hotel entered under Days with a check-in at ten was reached at a quarter
past twelve in road trip mode. Two things: the schedule read the check-in
as a floor that held nothing once anything before it set the clock, and
the server seated the night last unless something pinned later pulled it
forward, so two stops without an hour stood ahead of it.

The check-in now pins the night the way its own time would, in the plain
schedule and in the daily window, where a check-in the drive cannot make
is the conflict a missed pin is. The night is seated first on its day;
only a stop with a clock at or before the check-in stays ahead of it, and
the stops without one follow. A new check-in seats the night afresh, a
change of notes leaves a dragged night where it is.

A day that is nothing but its booked night stands among the days now,
with the hotel and its check-in, instead of at the foot of the rail under
"only X so far", which read as the hotel missing from the road trip.

The client puts a stop the server seated at the front where the server
put it, rather than appending it to draw second until the next reload.
2026-09-20 17:26:50 +02:00
jubnl e48b6e6990 base entities 2026-09-20 17:02:52 +02:00
github-actions[bot] b98787f836 chore: bump version to 4.3.0 [skip ci] 2026-09-20 13:56:50 +00:00
Maurice 9731407694 feat(notices): document sync joins the release notice as a fourth, wide card
Paperless-ngx, Papra, Nextcloud, OpenCloud and Synology Drive are a headliner
of this release and were missing from the notice. The card runs across the row
under the three upright ones, picture beside the text, so the panel keeps its
height: the wordmark without its API pill, the two-way arrow, and the five
stores as tiles. The panel's grid row is capped at the panel's height, so a
short viewport scrolls the left column instead of clipping the support buttons
on the right. The headline counts four, the intro and the card texts are
shorter, and the Dawarich card drops its last sentence, in all 23 languages.
The release e2e test asks with the bundle version, as the client does.
2026-09-20 14:58:33 +02:00
Maurice 8f6ed02cff fix(notices): hand the release notice only to a bundle built for the running version
After an update the service worker keeps serving the previous bundle until
the new one is installed. That shell announces the release layout too, so
the layout alone let it draw the notice with its own older texts and use it
up for the version now running with one click on X.

The bundle now sends the version it was built as (client/package.json, baked
in by define), and the server compares it with its own before it hands a
notice with a release block over. A shell of another version is told nothing
and gets the notice after the reload, from the bundle that can draw it. This
holds for every update, not only the one that introduced the parameter.
2026-09-20 14:28:45 +02:00
Maurice 31239f3687 fix(ssrf): connect over every address a name resolves to, IPv4 first
The guard resolved a name to one address and pinned the socket to it. On a
dual-stack name whose AAAA came first that was an IPv6 many hosts cannot
reach on 443, and the request sat until the caller's timeout while the A
record would have answered at once. OIDC discovery, Dawarich, AirTrail, the
photo providers, a self-hosted router or Nominatim and the model endpoints
all ride this path.

The name is now resolved to every address it has, each one is checked, and
one blocked address blocks the name. The whole checked list goes to the
socket, IPv4 ahead of IPv6, where Node walks it itself and moves on after
its attempt timeout. Redirect hops do the same per hop. A caller that still
names one address gets exactly the old behaviour.
2026-09-20 13:54:31 +02:00
Maurice ed18c37903 fix: the findings of the final 4.3.0 audit
Every file the release touches was read once more, and what survived an
independent check against the code is fixed here, with a test for each.

Data and credentials
- A document sync connection edited to a new address no longer carries the
  stored token along: a blank form under another origin is refused, the same
  rule the probe route already had. Dawarich and AirTrail testConnection send
  the stored key only to the host it was stored for.
- The key rotation script now covers document_connections.secrets and
  trip_document_links.webhook_secret, which it had skipped.
- Turning a booked night into a pause in the road trip popup asks first and
  says that the booking and its expense go with it. Deleting a place says the
  same when a night is booked there, on the desktop and on the phone.
- A moved version marker over unchanged bytes no longer replaces the TREK file
  and its attachments; a real revision carries the attachments over.

Planner
- A drop in the day plan names the row it lands ahead of in the full day, so a
  hidden hotel stop no longer shifts it one slot early; the store sorts before
  it splices. Via re-anchoring, the booked-night guard and the sidebar's day
  membership read the stored day, the index space the server uses.
- A hotel stop placed mid-day re-pins the road trip vias of that day, and the
  booking session receives the new stop order too. The Public API and the iCal
  feed list a booked hotel once. A plugin can no longer write a stay against
  another trip's day.

Road trip and map
- The route overview paces its requests to the public routers and retries a
  rate limit, and it says which legs it could not route instead of quietly
  reporting a shorter trip. A click on a via handle no longer drops a second
  via; handles hide when zooming out. Read-only members cannot edit the driving
  limits. The phone shows a way back when no day is picked and prints the night
  drive departure in the chosen clock format.

Integrations and search
- Google transit keeps conventional trains when the train chip is on.
  TREK_PLACES_ENABLED=false stops the details and enrichment calls too, and
  accepts the whole boolean family. A caller-supplied description no longer
  lands in the instance-wide enrichment cache. Nominatim searches carry a
  timeout. An OSM place id is checked for shape before it reaches Overpass.
- Dawarich puts a stay on the trip whose dates hold it, the Atlas hand-off
  knows what the Atlas already shows, and a host change with a new key clears
  the old instance's state.
- Document sync: a webhook address pasted by hand works on the token alone,
  deleting a connection unregisters its subscriptions, Nextcloud under a
  sub-path connects, Synology answers a name collision before uploading and
  verifies a move into the bin, Paperless titles are capped at 128 characters,
  a DNS failure reads as unreachable rather than as a policy verdict, videos
  from the store are accepted like uploads, and remote_missing has a way out.
  Conflict buttons only for the owner, a refused choice is reported, a refused
  credential gets a Reconnect button, disconnecting asks first on the desktop
  as it does on the phone, and the folder picker no longer spins forever.

Release
- The server holds the release notice back from a bundle that cannot draw it,
  so the previous shell served from the service worker cache after an update
  no longer shows bare keys and no longer lets a click use the notice up.
- Import into an existing list gets the same body limit as a new list. Chat
  images say when the limit is reached and the new controls are translated.
  The transit backend switch reports a failed save. The Helm chart carries the
  Amap credentials in its Secret; the shipped templates document the Places
  API and Amap variables and the Overpass default. The wiki follows.
2026-09-20 13:54:31 +02:00