It's generally a good idea that you're trying to keep different mechanics modular, and expose public interface with information that these systems need.
However, quest and achievement mechanics (at least, how they're usually understood) are conceptually different: you don't get new dialog options because you unlocked some achievement, but you certainly will see new dialog options if you're on a certain quest (you didn't mention this scenario, but it usually exists). So, since the quest mechanic can affect the behaviour of dialogs and vice versa in a variety of ways, they need to be coupled closely. How exactly — depends on your exact goals and game architecture.
But if you're talking about achievements, statistics, user analytics and other mechanics that can't affect the gameplay in any way, you only need to pass information one way, and while achievements/stats/analytics need to have knowledge about NPC/Dialogs/Quests, the latter don't need to know about the former. So, as you suggested, I would expose a public interface with read-only access to all necessary data. Also, if your language has events, I would use them instead of public getters: that way, your achievement system can just subscribe to an event and then act on it, instead of constantly checking if the variables changed.