Repository: network β†’ DB β†’ UI

refresh() writes, observeAll() reads β€” that's the whole repository

With the DAO in place, the repository's job shrinks to almost nothing: refresh() fetches from the API, maps each response DTO to a WalkEntity, and calls upsertAll(). The walks property, meanwhile, is just dao.observeAll() exposed as-is (or piped through stateIn, from module 13, if a ViewModel wants it as a StateFlow). Network in one direction, UI out the other, the table sitting in between as the single source of truth.

The DTO-to-entity mapping happens at the repository boundary, and nowhere else. The API's response shape (whatever fields the server sends, possibly nested, possibly named differently) never leaks past the repository β€” only WalkEntity rows do. That's what lets the server's JSON shape change without touching a single composable.