#4 refactor frontend into something reusable