1. Not editable but deletable by the author
".write": "!data.exists() || (!newData.exists() && data.child('author') === auth.id)"
2. Liking/Upvoting
On the client, use a transaction which allows you to increment the value safely:
ref.transaction(function(currentValue) {
return (currentValue||0)+1;
}, function(error) {
if( error ) /* failed too many times */
else /* it worked */
});
Security is also straightforward:
".validate": "newData.isNumber() && newData.val() === data.val()+1"
2.5 Ensuring Unique Votes
I'm not sure what this means; the records can't be edited and presumably if they could, only the author would be able to do so; so I don't really understand "modified" in this context: "if the user hasn't modified this before? How would that work?"
To ensure votes are unique, you just store them by user ID. The user can remove their vote by deleting the record.
I'd recommend storing these in a separate path than the sparks and still maintaining a simple increment (the messages that are getting voted up/down) as you don't want to have to retrieve the entire list of voters each time you fetch the spark.
The security rules would look like so:
"votes": {
"$spark_id": {
"$vote": {
".read": "$vote === auth.id",
".write": "$vote === auth.id",
// to allow downvoting in addition to up or delete, just add -1 here
".validate": "newData.val() === 1 || newData.val() === null"
}
}
}
And now add a check to the validate rule for the increment:
".validate": "!root.child('votes').child($spark_id).child(auth.id).exists() && newData.isNumber() && newData.val() === data.val()+1"