My understanding of your question is that at any point in time T, I can ask any of those nodes about that value associated with a given key, and get the same answer.
Similarly I should be able to update any key, on any server, and on my next read of another (or the same node) for that key see the New value (assuming no one else has updated it).
Worse, your program may actually require the ability to update numerous keys (add/delete/modify) atomically, perhaps dependent on the values or presence of other keys. Which is even harder, and vast manuscripts have been written on how to get that right on even a single computer with a single thread.
Importantly RAFT does not guarantee the above by itself. At best it is a way of getting multiple machines to agree on one version of history.
Dirty Reads, Missing Writes, and Data Mayhem
Imagine a scenario where consensus has been reached, you report back that the write was successful. You immediately attempt to read the value back. This time you read it back from another node, it responds with an old value. Why that node hasn't synchronised yet.
Another scenario where two programs write their values to two separate nodes. Both nodes race to get the majority to agree to their write. One will fail. One program re-attempts its write, the other writes to a different key. But, because there can only be one authentic history, they both still race to get the majority. This can effectively lock one node (and its programs) out of the update loop because it can't gain the majority quick enough.
Yet another scenario, a reader and two writers of the same key. The writers have written their values. The reader read the key, which value does the reader see: the old, or one of the two new values? It depends but it is now a race, each node that is asked may have a different answer.
Seriously these are not simple issues to overcome. Numerous big name distributed databases state explicitly that these scenarios will happen unless you specifically use a replicated master. Writes can only happen serially on the master, and replicas only serve up known historic versions. The readers are aware that they are reading old data. And writes call out specifically what data should not have changed for the write to be valid.
Before I get told that there are other solutions... Yes they exist. Are they simple to implement correctly? No. Even the big names get it wrong, frequently.
Do keep RAFT. It is a good idea for getting to a consistent state. It is also reasonably easy to implement correctly and has good recovery and degeneracy properties.
Now what is most important?
If everyone being on the same page is important, only serve up values which your machine knows have been seen by all the other nodes. Even if your log knows a newer value.
If instead reads only need to be consistent to a single time, have the user pick a point in time that is no newer than the newest majority confirmed log entry. Only serve up answers from then or before.
If dirty reads are fine, always serve the latest and greatest.
If losing no writes is important, funnel all writes via a single elected node. Similarly transactions should be handled by this writing node.
If transactions are pretty heavy weight in terms of calculation, number of reads and writes. Then pin the time when all reads where consistent and log what was read and any boundaries (ie. keys don't exist, value was non-existant or null). Ship that log + the writes to the elected transaction host (or become that elected host). The writers job is to verify that the world still looks okay, and then perform the writes, if anything has changed the whole transaction is rejected.
If losing writes is fine, don't even bother confirming that it is committed. Update the raft log and allow consensus to determine a correct history. If it was important to track the writes success, it will be successful if its raft log entry is ratified by the majority, and failed if its raft log entry was discard in favour of an alternate history.
Alternately just don't bother trying to make this a
Key/Value store and instead make it a
Key/Time/Writer/Value store and let the client sort out the fuss. Nothing is easier than shifting the burden to someone else - it is just not nice.
Your client code needs to be aware that the nodes in this swarm may become inconsistent for any number of reasons. This means some level of sense about the quality of each node from a read/write perspective. Most of them can answer old queries accurately, but only a few may have access to the latest updates, perhaps even fewer should be consulted for writing.
A simple metric is to semi-regularly check-in with each accessible node and ask for say the hashes of the last 100 log entries. Compare them. If most nodes have the same hashes then they are mostly in agreement and the nodes are stable. If one node has nothing in common it has de-synchronised. If many nodes are out of balance then there is trouble, don't trust anything.
You will need to test this system setup with multiple nodes. You'll have to address slow connections, split networks, and recovery while checking for transactional guarantees, dirty reads, and missing writes (to name a few) to get any confidence in this system as a reliable data store.
Seriously find yourself a dry textbook on database architecture and engine design. Others have been wrestling with these problems for 80+ years, go find their knowledge. It will at least tell you what the problems are, even if the solutions aren't readily evident.