feat(sync): implement Delta-Sync API and update clients to support offline-first workflow

Added `/ping/sync` endpoint with timestamp-based Delta-Sync functionality to efficiently support offline-first clients. Extended `PingApi` and frontend clients (`PingApiClient`, `PingApiKoinClient`) with `syncPings`. Updated repository, service, and controller logic for sync handling, including new JPA query `findByCreatedAtAfter`. Adjusted test doubles and completed unit tests for backend and frontend alignment. Documented sync approach and API usage.
This commit is contained in:
2026-01-17 12:22:16 +01:00
parent 59568a42d8
commit 351fe7a672
15 changed files with 190 additions and 62 deletions
@@ -41,7 +41,7 @@ import java.time.Instant
@ContextConfiguration(classes = [TestPingServiceApplication::class])
@ActiveProfiles("test")
@Import(PingControllerTest.PingControllerTestConfig::class)
@AutoConfigureMockMvc
@AutoConfigureMockMvc(addFilters = false) // Disable security filters for unit tests
class PingControllerTest {
@Autowired
@@ -140,4 +140,34 @@ class PingControllerTest {
assertThat(json["status"].asText()).isEqualTo("up")
assertThat(json["service"].asText()).isEqualTo("ping-service")
}
@Test
fun `should return sync pings`() {
// Given
val timestamp = 1696154400000L // 2023-10-01T10:00:00Z
every { pingUseCase.getPingsSince(timestamp) } returns listOf(
Ping(
message = "Sync Ping",
timestamp = Instant.ofEpochMilli(timestamp + 1000)
)
)
// When & Then
val mvcResult: MvcResult = mockMvc.perform(get("/ping/sync").param("lastSyncTimestamp", timestamp.toString()))
.andExpect(request().asyncStarted())
.andReturn()
val result = mockMvc.perform(asyncDispatch(mvcResult))
.andExpect(status().isOk)
.andReturn()
val body = result.response.contentAsString
val json = objectMapper.readTree(body)
assertThat(json.isArray).isTrue
assertThat(json.size()).isEqualTo(1)
assertThat(json[0]["message"].asText()).isEqualTo("Sync Ping")
assertThat(json[0]["lastModified"].asLong()).isEqualTo(timestamp + 1000)
verify { pingUseCase.getPingsSince(timestamp) }
}
}