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.