I would guess that this is highly dependent on the individual situation and goals. This might include the complexity of the configuration itself (how hard is it to replicate if files are lost), the scale of the deployment (1 or a few device(s) vs many), the application space (home, business, etc.), and so on.
The raw config files can be backed up easily, but these should only be restored to the same device that did the backup (there can be risks of things going wrong even when it is the same model but a different physical unit -- things like MAC addresses are sometimes stored in the config files, so the configs should be considered unique).
But, if you have many units with similar configs, the best way to handle this is to use UCI syntax to script those configs from the known default state. Deploying this can be done in a number of ways, including custom images with the UCI script to run on first boot, or things like ansible playbooks.
As for storage, whatever makes sense bsed on who needs to access your configs (and who shouldn't be able to)... be aware of things like passwords and keys that are stored there. Github is good if you're sharing it with others or any number of local or cloud storage options... it's very much depenedent on your situation and what is expected to be available when your routers are in a default configuration.
The raw config files can be backed up easily, but these should only be restored to the same device that did the backup (there can be risks of things going wrong even when it is the same model but a different physical unit -- things like MAC addresses are sometimes stored in the config files, so the configs should be considered unique).
You are right, some info make the configs unique and some are "secrets" (like wg keys, etc). I made a small program that allows me to declare those secrets in a separated yam file and "add" them to the config file using a template placeholder, for example:
Regarding MAC addresses, I found here in the forums some suggestions to create a service to rename interface names to predictable names based on their macaddrs. It is working great
Deploying this can be done in a number of ways, including custom images with the UCI script to run on first boot, or things like ansible playbooks.
This is hard. I made a script to build the images I need but so far only tested it on virtual machines. I have some scripts to create some small virtual machines so I can test my changes before applying them on my real infrastructure - I know I need to be conscious since my routers do not run x86, but many configs do not rely on the processor arch.
I think, at the end, I wanted to hear from other users how they approach this to check if I'm not doing things that re too unorthodox...
I run OpenWrt in KVM/QEMU managed by libvirt for educational and testing purpose, and just deploy a clean new VM provisioning its configuration with UCI defaults any time the previous VM becomes too deviated for the task.
That is similar to what I do, but I use VirtualBox. One thing that I would like to improve is the image build time: to create my playground I build 8 images to run in 8 different small VMs (1 core, 128MiB RAM). It is simple to do, I just run playgroud/play vm create --all and it does everything unassisted, but takes more than 15 minutes to build. I wonder, since I'm just changing static files most of the time, if I could cache some of the initial steps of the build - or maybe not build many different filesystems, only the one I'm going to use
It's wonderful that there's a method for managing multiple devices, but it seems like overkill for most practical scenarios. This approach requires running a server that the devices connect to, among other things. For me, the only acceptable solution must be capable of running directly on an OpenWrt device with no additional setup needed.
Configuration variables that can be customized in each device, at organization level or at group level
Versioning with possibility to rollback changes or recover deleted templates
The only catch is that it at this time it doesn't store the configuration which is pre-existing on the firmware, because it assumes that's shipped in the firmware itself and it can be recovered by resetting the firwmare and reconnecting the device to OpenWISP.
It does require to be self hosted on a server (recommended 2 GB of RAM minimum) and IMHO is worth it only after 10 devices or more, for anything less than that is probably not worth the effort and any simpler solution is going to be more than fine.
OpenWISP makes even more sense if your devices are dispersed geographically and you need a central point of management, because it provides an automation to create management tunnels using OpenVPN, Wireguard and soon the Zerotier integration will be ready too.
If you want to try it there's an online demo.
A battle tested ansible installer (ansible-openwisp2) is available on github, at the moment of writing I recommend looking for the instructions to install the development version which I regularly use in different projects and is close to be released officially in the coming months.