Until now, when clients have requested new functionality for their organization management systems, Engaging has usually delivered by spinning out another console or port—ie, another multi-entry table or single-entry form/view. In retrospect, working this way was akin to web publications before the advent of content management systems, where each article would be coded up as a page; here, each functional console or port was another file. Over the years these have proliferated—Engaging systems, being well architected, tend to be longstanding—and as new techniques have come about there has been drift among them.
Recently we’ve brought the role-based Engaging method and structure to our current modern tech stack (Nuxt for the front-end, Directus for the back, Apollo for connecting them) to create the Engaging OS enterprise engine. When migrating existing systems to the new platform it has however been a daunting prospect to reproduce and maintain each of these myriad consoles and ports; what should really happen is that all but the most complex of them—and even those eventually—be somehow standardized and automated, produced centrally by a higher level of abstraction.
A first step
The first step on this path was figuring out, with ChatGPT’s help, how to detect all the various consoles rather than having to manually declare each of them in the parent component (necessary because while Nuxt does import components automatically, their names must be explicitly mentioned for this to happen, but in our case they are not explicitly mentioned, as they are coming in as a list from the user’s state). The solution used the import.meta.glob command in Vite, Nuxt’s compiler/builder. Suddenly the oft-forgotten declaration step when adding a new port or console was eliminated. What else could be automated? We were off to the races!
Six months later, Engaging OS’s AutoPort and AutoConsole are deployed and in use, and in retrospect it seems audacious to have referred to Engaging OS as a platform without them. Aside from migrating to the new tech stack, they represent the biggest architectural leap in Engaging OS’s development.
Mindbending meta-ness
AutoConsoles and AutoPorts are no longer coded but are composed—mindbending meta-ness coming up—in the Console and the Port ports. What does this require?
To compose an AutoConsole, all we need are two new fields: a Fields field to select the columns, and a Filters field to determine the rows.
Powerfully, the Fields selector accesses the entire schema, its pulldown listing the collection’s fields, with any relationship fields featuring carets that open up to display their related collection’s fields, and so on. This lets us traverse the entire schema and build an entity that, starting from the root collection, can comprise all corners of the enterprise. Such is the great delight of GraphQL, which enables spontaneous declarations of entities with a single query.
In Filters, building each condition also requires selecting a field the same way, but then comes an operator, such as "contains" or "equals", and a value to compare, which can be hard-coded or an environment variable. Of course, filters can be placed within And and Or groups and nested.
With these two fields we can very much sculpt the data displayed in a console. And because AutoConsoles are no longer coded but configured, it’s easy to just spin up another. In Directus there’s a feature similar to AutoConsoles that they modestly call Bookmarks, but for ports Directus only enables one view per collection; this is where Engaging OS picks up the baton that Directus so smoothly passes.
Control fields
Like AutoConsole, AutoPort has a Fields field, picked the same way. But unlike AutoConsole there is no Filters field, because only one entry is being displayed. Instead, it has:
- Virtual Fields, appearing only on this particular port
- Computed Fields, where any fields can be prefilled with a literal or environmental value based on a set of conditions
- Formula Fields, where the displayed value is a formula comprising other fields (like formula cells in a spreadsheet) but nothing is saved
- Relationship Field Filters, where the values of pulldowns are filtered by a set of conditions
- Field Display Conditionals, where fields appear based on a set of conditions
- Field Read-Only Conditionals, where fields are read-only based on a set of conditions
Together, these enable the replacing of many coded ports with configured ones.
What’s next
Importantly, manual ports and consoles are still available; there’s a respective AutoPort and AutoConsole boolean field to direct rendering either to the component or to auto-generate it. But we will keep developing AutoPort and AutoConsole until they can handle all previously individually-crafted counterparts. One way to achieve this is to enable embedding consoles within ports, as some important ports have tables of related items in them as well as the main item.
Beyond that, we’re going to set up Pages as a new collection comprising blocks that can be ports, consoles, or other content types to follow. Because Engaging OS keeps the user’s entire permissions structure loaded in state, any such page will tailor itself to each user. One place this is useful is on a homepage where users can perform some tasks immediately without heading to a dashboard.
Credit where due
About halfway through development we switched AI coding assistant from ChatGPT to Claude. Its artifacts interface, the actual responses, even the font and colors: all much better! Six months may seem like a long time, but two salient points: 1) Like most software, development followed the 80/20 Pareto rule, in that much of it was done in much less time but the final bits took longer. 2) There’s no way I the developer could have pulled this off within months instead of years without massive AI input.
Looking back however, I've seen at least one LLM choice that I unquestioningly followed which ended up increasing the workload, and if I’d been working unassisted would likely have chosen better. It was how filtering and other data is saved in JSON; we over-structured this, requiring complex retranslation for it to be usable within GraphQL, whereas if I had looked beforehand at how Directus saves this metadata we could have avoided this extra complication. But we’ll go back eventually and refactor this and any other over-complications.
One thing is for sure: thanks to LLMs, development as a whole is already going much much faster. The Advent of the Autos applies writ large.