Here I've been attempting to detail my setup that I revised as of the end of 2021.

DHCP configuration -- This is done using isc-dhcp-server on Debian. I use the network range 192.168.0.x for my internal network, being fairly small. Dynamic DHCP assignments are restricted to the .16 - .127 range. I create host stanzas to store reservations, e.g.:

host sprinkhaan {
  hardware ethernet DC:53:60:F3:A7:FF;
  fixed-address 192.168.0.3;
}

I use option domain-search "phys.solasistim.net" to set up the default search domain for all DHCP clients.

DNS configuration -- This is done using BIND. All hosts receive 192.168.0.1 as their DNS server. This forwards to my ISP's DNS servers (Zen, who have been great so far). Using BIND I am able to create "split-horizon" DNS so that e.g. my Puppet server resolves to an internal IP when requested internally. The main zone file defines all hosts in phys.solasistim.net. (The original idea here was to draw a sharp distinction between physical and virtual hosts, but I've become less certain on this. Still, it's good to use a separate domain from the real solasistim.net.) The downside of this setup is that some duplication of the assignments is needed, specifically the fixed-address setup in dhcpd.conf needs to be essentially replicated in solasistim.zone. This doesn't actually matter much in practice because I don't add hosts very often.

PPP interface -- This is done using pppd and a Draytek Vigor 130. The provider file that I use for pppd is fairly standard. I based it on a useful post from a person called Ruben. The only real difference between the two configurations is that I do have to provide my real account password in chap-secrets.

Firewall configuration -- I use nftables. There's only one really notable thing that I do in nftables, which is a bit complicated, and that's clamp my TCP maximum segment size to my path MTU.

table inet filter {
    # ...
    chain forward {
        # ...
        tcp flags syn tcp option maxseg size set rt mtu
        # ...
    }
}

You can find more information on this at the nftables wiki. This problem manifests itself in strange ways with some web sites simply timing out when you attempt to connect to them, while most sites work fine. For instance lbc.co.uk and atlassian.net had this strict MTU requirement as of late 2021. There may also be other ways to address this. I know that setting MTU on clients also resolves the issue, but not all devices seem to respect the MTU setting when it's sent in DHCP. It may also be that setting mtu in /etc/network/interfaces will make a difference -- I have never tried this.

Interface configuration -- In /etc/network/interfaces, we create the regular ppp0 interface that is used for WAN access.

auto ppp0
iface ppp0 inet ppp
    provider zen

We create a bridge between two interfaces. One has a Wifi AP and one has a hardware switch.

auto br0
iface br0 inet static
    address 192.168.0.1
    bridge_ports eno2 eno3

The wifi AP and switch just use their standard Draytek firmware for configuration, which seems to work fine so far.

A few notes/updates: The Vigor 130 has a CLI interface that is accessible via telnet (I believe). This allows some more advanced operations to be performed. There were also some concerns about whether the Zen connection should be Annex A or Annex B. I think we eventually came to the conclusion that it should be Annex A. During the setup of the line, there were frequent connection drops, where the pppd log would read "Modem hangup". These eventually seem to have just gone away without further intervention on my part. I can only assume this was the "line training" phase that is much discussed on UK broadband forums.