Hey John, great question.
Basically, the networking is implemented using the standard Linux networking stack. Every interface- Wi-Fi, Ethernet (if connected), and cellular, gets its own unique IP address. Those IPs will change depending on the network connection: cellular addresses typically change if the device switches operators or reconnects, while Wi-Fi and Ethernet are more stable but will update when moving between networks.
You can absolutely connect directly to the device over SSH or HTTPS. In the Particle Console (console.particle.io), if you open your device, there’s a built-in remote SSH shell you can use. You can also run tailscale login/tailscale up on the device and link it to your own Tailscale account for secure mesh access from your desktop - that’s what I use most often. As ErwinE you can also connect using SSH over a local network (which is how I think all our devices do it!). Lastly, you can connect via ADB - check our developer docs (search adb) for details 
You can run anything over the cellular connection, rsync included. The default firewall isn’t currently enabled, so services like SSH are reachable if you configure them.
Yes, the applications list will allow you to deploy your own binaries. We have a large tutorial update publishing shortly that walks through multiple ways of pushing apps to the device.
As for running it as a gateway for a PLC - great use case. I use something similar here, running the device as a hotspot: Wi-Fi or Ethernet connects to the PLCs / local control boxes, and the device bridges traffic out over the cellular network, much like a phone’s personal hotspot. If you want Ethernet bridging, you can follow the tutorial linked in the docs; Wi-Fi hotspot works out-of-the-box.
Here is the instructions for this wifi hotspot mode: WiFi | Particle Developer
If you want more control, the simplest approach is to write a small script that listens for both the PLC-side network and the cellular interface coming up, then binds them together. When either side goes down, the script can tear down the binding so routing stays clean. It’s pretty straightforward to implement - just shout if you’d like an example.
Thanks!
Nick