I have a custom data flow, where I feed my views directly out of Ground:DB instance on the client, and directly out of server mongo sources on the server in SSR. Data is delivered over methods (except when there is hydration data), with a custom (and relatively stupid) syncing algorithm (it just grabs new pages of data on component mount, and throws away anything no longer on the server). I don’t bother with pub/sub for performance and scale concerns, and because of that I don’t do any of the fancy syncing with Ground:DB. In order to deliver separate mongo sources in different contexts (server/client) I put all that in a package.
The only caveat I found with it is that there is a slight delay from when the app starts and Ground:DB is really ready to go (but only sometimes). You also have to be aware of the limitations of mini-mongo - such as there is no text index client side, but that’s normal for isomorphic queries, and not specific to Ground:DB. Everything else about it works normally.
I also do a kind of pattern - I call it a connector pattern. Basically, any kind of data container is a connector - withTracker, withState, etc. I set those all up in a folder called “connector” and reuse those all over. They can even be set up to use a Provider for efficiency, though I usually skip this step. (I suppose this is just the “container” pattern renamed, but now it also contains hooks built on useTracker, so I’ll keep using the label.). These are all functions which are used to wrap a component (or used by a component in the case of hooks). I try to make these fairly generic, so they can simply be reused where ever I need them. The data package I described above has a utility function, which let’s me pass a set of functions like a query, a collection, a tracked function, etc, and then it does all the glue to make SSR, data over methods, data hydration, offline first, etc. all work with very little effort at the connector level. I’m going to release that package fairly soon.