Workspaces for Transport

Mike's Notes

This is where I will keep detailed working notes on creating Workspaces for Transport. Eventually, these will become permanent, better-written documentation stored elsewhere. Hopefully, someone will come up with a better name than this working title.

This replaces the coverage in Industry Workspace written on 13/10/2025.

Testing

The current online mockup is version 2 and will be updated frequently. If you are helping with testing, please remember to delete your browser cache so you see the daily changes. Eventually, a live demo version will be available for field trials.

Learning

(To come)

Why

(To come)

Resources

References


References

  • Reference

Repository

  • Home > Ajabbi Research > Library >
  • Home > Handbook > 

Last Updated

28/11/2025

Workspaces for Transport

By: Mike Peters
On a Sandy Beach: 28/11/2025

Mike is the inventor and architect of Pipi and the founder of Ajabbi.

Open-source

This open-source SaaS cloud system will be shared on GitHub and GitLab.

Dedication

This workspace is dedicated to the life and work of .


Person

Source: 

"

" - Wikipedia

Change Log

Ver 2 includes aviation, port, road, rail, and shipping.

Existing products

This is a basic comparison of features in transport software.

[TABLE]

Data Model

words

Database Entities

  • Facility
  • Party
  • etc

Shipping Variables

Note that this simulation did not use realistic min, max, mean and std deviation for these calculations. The model itself was the result and will undergo further work and testing using industry data to refine it.

Source: Krombar.ai simulation platform (beta)

Node Name Type Estimates / Formula
Origin inspection pass rate Input Variable beta distribution
Container arrivals Input Variable discrete_normal distribution
40ft container share Input Variable beta distribution
40ft container distance Input Variable Normal(μ=5500.0, σ=2223.903327758403)
Total refrigerated containers scheduled Input Variable discrete_normal distribution
Energy cost per refrigerated container Input Variable Normal(μ=900.0, σ=444.78066555168056)
Fuel cost per 20ft container Input Variable Normal(μ=275.0, σ=185.32527731320025)
Oversized container arrives at origin Calculation Step binomial(round(Total oversized containers scheduled), min(1, max(0, Oversized arrival rate)))
20ft fuel cost Calculation Step 20ft sails to destination * Fuel cost per 20ft container
Ship capacity Input Variable discrete_normal distribution
20ft container share Input Variable beta distribution
Fuel cost per mile per 40ft Input Variable Normal(μ=4.0, σ=1.482602218505602)
Refrigerated arrival rate Input Variable Normal(μ=6.0, σ=5.930408874022408)
Oversized arrival rate Input Variable Normal(μ=2.75, σ=3.3358549916376043)
20ft container arrives at origin Calculation Step binomial(round(Container arrivals), min(1, max(0, 20ft container share)))
Unloading success rate Input Variable beta distribution
Total oversized containers scheduled Input Variable discrete_normal distribution
20ft crew cost Calculation Step 20ft arrival * Crew cost per 20ft container
Refrigerated container arrives at origin Calculation Step binomial(round(Total refrigerated containers scheduled), min(1, max(0, Refrigerated arrival rate)))
40ft fuel cost Calculation Step Refrigerated container arrives at origin*Energy cost per refrigerated container
Destination inspection pass rate Input Variable beta distribution
20ft port fees Calculation Step 20ft arrival * Port fee per 20ft container
40ft sails to destination Calculation Step min(40ft loaded onto ship, round(max(0, Sailing efficiency 40ft * 40ft loaded onto ship)))
40ft crew cost Calculation Step 40ft arrival * Crew cost per 40ft container
20ft checked-in & inspected Calculation Step binomial(20ft container arrives at origin, Origin inspection pass rate)
40ft port fees Calculation Step 40ft arrival * Port fee per 40ft container
20ft loaded onto ship Calculation Step min(20ft checked-in & inspected, Ship capacity)
20ft sails to destination Calculation Step 20ft loaded onto ship
20ft unloaded at destination Calculation Step binomial(20ft sails to destination, Unloading success rate)
20ft checked out & inspected Calculation Step binomial(20ft unloaded at destination, Destination inspection pass rate)
40ft container arrives at origin Calculation Step binomial(round(Container arrivals), min(1, max(0, 40ft container share)))
Energy cost per refrigerated container Input Variable Normal(μ=200.0, σ=91.1854103343465)
Scheduled containers Input Variable discrete_normal distribution
Ship operating cost per container Input Variable Normal(μ=550.0, σ=370.6505546264005)
Port fees Input Variable Normal(μ=150.0, σ=148.26022185056019)
Crew wages Input Variable Normal(μ=125.0, σ=111.19516638792014)
Shipping cost per 20ft container Input Variable Normal(μ=2600.0, σ=2075.6431059078427)
Shipping cost per 40ft container Input Variable Normal(μ=3900.0, σ=3113.4646588617643)
20ft container distance Input Variable Normal(μ=5500.0, σ=2223.903327758403)
Fuel cost per mile per 20ft Input Variable Normal(μ=2.0, σ=0.741301109252801)
20ft container voyage duration Input Variable Normal(μ=25.0, σ=14.82602218505602)
Crew cost per day per 20ft Input Variable Normal(μ=90.0, σ=44.478066555168056)
Number of ports per voyage Input Variable discrete_normal distribution
Port fee per 20ft container Input Variable Normal(μ=275.0, σ=185.32527731320025)
40ft container voyage duration Input Variable Normal(μ=25.0, σ=14.82602218505602)
Crew cost per day per 40ft Input Variable Normal(μ=180.0, σ=88.95613311033611)
Port fee per 40ft container Input Variable Normal(μ=550.0, σ=370.6505546264005)
Fuel cost per refrigerated container Input Variable Normal(μ=650.0, σ=370.6505546264005)
Crew cost per refrigerated container Input Variable Normal(μ=425.0, σ=259.45538823848034)
Port fee per refrigerated container Input Variable Normal(μ=225.0, σ=185.32527731320025)
Fuel cost per oversized container Input Variable Normal(μ=900.0, σ=444.78066555168056)
Crew cost per oversized container Input Variable Normal(μ=650.0, σ=370.6505546264005)
Port fee per oversized container Input Variable Normal(μ=400.0, σ=296.52044370112037)
Special handling rate at origin Input Variable beta distribution
Special handling rate at destination Input Variable beta distribution
Special handling cost per container at origin Input Variable Normal(μ=500.0, σ=444.78066555168056)
Special handling cost per container at destination Input Variable Normal(μ=500.0, σ=444.78066555168056)
refrigerated_arrival Input Variable discrete_normal distribution
oversized_arrival Input Variable discrete_normal distribution
oversized_special_handling_origin Input Variable beta distribution
oversized_special_handling_dest Input Variable beta distribution
refrigerated_fuel_cost Input Variable Normal(μ=550.0, σ=370.6505546264005)
refrigerated_crew_cost Input Variable Normal(μ=275.0, σ=185.32527731320025)
refrigerated_port_fees Input Variable Normal(μ=225.0, σ=185.32527731320025)
refrigerated_energy_cost Input Variable Normal(μ=350.0, σ=222.39033277584028)
oversized_fuel_cost Input Variable Normal(μ=475.0, σ=333.58549916376046)
oversized_crew_cost Input Variable Normal(μ=235.0, σ=170.49925512814423)
oversized_port_fees Input Variable Normal(μ=190.0, σ=163.0862440356162)
oversized_special_handling_cost Input Variable Normal(μ=800.0, σ=593.0408874022407)
20ft_arrival Input Variable discrete_normal distribution
Crew cost per 20ft container Input Variable Normal(μ=140.0, σ=88.95613311033611)
40ft_arrival Input Variable discrete_normal distribution
Fuel cost per 40ft container Input Variable Normal(μ=425.0, σ=259.45538823848034)
Crew cost per 40ft container Input Variable Normal(μ=200.0, σ=148.26022185056019)
20ft_fuel_cost Input Variable Normal(μ=120.0, σ=88.95613311033611)
20ft_crew_cost Input Variable Normal(μ=235.0, σ=170.49925512814423)
20ft_port_fees Input Variable discrete_normal distribution
40ft_fuel_cost Input Variable beta distribution
40ft_crew_cost Input Variable beta distribution
40ft_port_fees Input Variable beta distribution
container_arrival Input Variable beta distribution
Check-in rate at origin Input Variable beta distribution
check_in_inspect_origin Input Variable beta distribution
Loading rate Input Variable beta distribution
load_ship Input Variable beta distribution
Sailing rate Input Variable beta distribution
ship_sails Input Variable Normal(μ=400.0, σ=296.52044370112037)
Unloading rate at destination Input Variable Normal(μ=625.0, σ=407.7156100890405)
unload_dest Input Variable Normal(μ=1250.0, σ=815.431220178081)
Check-out rate at destination Input Variable Normal(μ=1050.0, σ=667.1709983275209)
20ft_ship_cost Input Variable Normal(μ=2500.0, σ=1482.602218505602)
40ft_ship_cost Input Variable Normal(μ=4250.0, σ=2594.5538823848033)
refrigerated_ship_cost Input Variable Normal(μ=6000.0, σ=2965.204437011204)
oversized_ship_cost Input Variable Normal(μ=9000.0, σ=4447.806655516806)
Loading efficiency 40ft Input Variable beta distribution
Sailing efficiency 40ft Input Variable beta distribution
Unloading efficiency 40ft Input Variable beta distribution
Checkout efficiency 40ft Input Variable beta distribution
Loading efficiency refrigerated Input Variable beta distribution
Sailing efficiency refrigerated Input Variable beta distribution
Unloading efficiency refrigerated Input Variable beta distribution
Checkout efficiency refrigerated Input Variable beta distribution
Loading efficiency oversized Input Variable beta distribution
Sailing efficiency oversized Input Variable beta distribution
Unloading efficiency oversized Input Variable beta distribution
Checkout efficiency oversized Input Variable beta distribution
energy_cost_per_refrigerated_container Input Variable Normal(μ=900.0, σ=444.78066555168056)
special_handling_rate_origin Input Variable beta distribution
special_handling_rate_dest Input Variable beta distribution
special_handling_cost_per_container Input Variable Normal(μ=275.0, σ=185.32527731320025)
fuel_cost_per_refrigerated_container Input Variable Normal(μ=1350.0, σ=667.1709983275209)
crew_cost_per_refrigerated_container Input Variable Normal(μ=525.0, σ=259.45538823848034)
port_fee_per_refrigerated_container Input Variable Normal(μ=450.0, σ=222.39033277584028)
fuel_cost_per_oversized_container Input Variable Normal(μ=1600.0, σ=593.0408874022407)
crew_cost_per_oversized_container Input Variable Normal(μ=700.0, σ=296.52044370112037)
port_fee_per_oversized_container Input Variable Normal(μ=600.0, σ=296.52044370112037)
crew_cost_per_20ft_container Input Variable Normal(μ=375.0, σ=185.32527731320025)
port_fee_per_20ft_container Input Variable Normal(μ=250.0, σ=148.26022185056019)
fuel_cost_per_40ft_container Input Variable Normal(μ=1250.0, σ=518.9107764769607)
crew_cost_per_40ft_container Input Variable Normal(μ=475.0, σ=185.32527731320025)
port_fee_per_40ft_container Input Variable Normal(μ=375.0, σ=185.32527731320025)
check_in_rate_origin Input Variable beta distribution
load_rate Input Variable beta distribution
sail_rate Input Variable beta distribution
unload_rate Input Variable beta distribution
check_out_rate_dest Input Variable beta distribution
20ft arrival Input Variable discrete_normal distribution
40ft arrival Input Variable Normal(μ=, σ=)
Oversized checked-in & inspected Calculation Step round(max(0, Oversized container arrives at origin))
Oversized loaded onto ship Calculation Step min(Oversized checked-in & inspected, round(max(0, Loading efficiency oversized * Oversized checked-in & inspected)))
Oversized sails to destination Calculation Step min(Oversized loaded onto ship, round(max(0, Sailing efficiency oversized * Oversized loaded onto ship)))
Oversized unloaded at destination Calculation Step min(Oversized sails to destination, round(max(0, Unloading efficiency oversized * Oversized sails to destination)))
Oversized checked out & inspected Calculation Step min(Oversized unloaded at destination, round(max(0, Checkout efficiency oversized * Oversized unloaded at destination)))
40ft checked-in & inspected Calculation Step round(max(0, 40ft container arrives at origin))
40ft loaded onto ship Calculation Step min(40ft checked-in & inspected, round(max(0, Loading efficiency 40ft * 40ft checked-in & inspected)))
40ft unloaded at destination Calculation Step min(40ft sails to destination, round(max(0, Unloading efficiency 40ft * 40ft sails to destination)))
40ft checked out & inspected Calculation Step min(40ft unloaded at destination, round(max(0, Checkout efficiency 40ft * 40ft unloaded at destination)))
Refrigerated checked-in & inspected Calculation Step round(max(0, Refrigerated container arrives at origin))
Refrigerated loaded onto ship Calculation Step min(Refrigerated checked-in & inspected, round(max(0, Loading efficiency refrigerated * Refrigerated checked-in & inspected)))
Refrigerated sails to destination Calculation Step min(Refrigerated loaded onto ship, round(max(0, Sailing efficiency refrigerated * Refrigerated loaded onto ship)))
Refrigerated unloaded at destination Calculation Step min(Refrigerated sails to destination, round(max(0, Unloading efficiency refrigerated * Refrigerated sails to destination)))
Refrigerated checked out & inspected Calculation Step min(Refrigerated unloaded at destination, round(max(0, Checkout efficiency refrigerated * Refrigerated unloaded at destination)))
Special handling at origin Calculation Step oversized_arrival * special_handling_rate_origin
Special handling at destination Calculation Step oversized_arrival * special_handling_rate_dest
Container arrives at origin port Calculation Step 20ft_arrival + 40ft_arrival + refrigerated_arrival + oversized_arrival
Check-in & Inspect (Origin) Calculation Step container_arrival * check_in_rate_origin
Loaded onto ship Calculation Step check_in_inspect_origin * load_rate
Ship sails to destination Calculation Step load_ship * sail_rate
Unloaded at destination port Calculation Step ship_sails * unload_rate
Check-out & Inspect (Destination) Calculation Step unload_dest * check_out_rate_dest
Refrigerated energy cost Calculation Step refrigerated_arrival * energy_cost_per_refrigerated_container
Oversized special handling cost Calculation Step (oversized_special_handling_origin + oversized_special_handling_dest) * special_handling_cost_per_container
Refrigerated shipping cost Calculation Step refrigerated_fuel_cost + refrigerated_crew_cost + refrigerated_port_fees
Oversized shipping cost Calculation Step oversized_fuel_cost + oversized_crew_cost + oversized_port_fees
Refrigerated fuel cost Calculation Step refrigerated_arrival * fuel_cost_per_refrigerated_container
Refrigerated crew cost Calculation Step refrigerated_arrival * crew_cost_per_refrigerated_container
Refrigerated port fees Calculation Step refrigerated_arrival * port_fee_per_refrigerated_container
Oversized fuel cost Calculation Step oversized_arrival * fuel_cost_per_oversized_container
Oversized crew cost Calculation Step oversized_arrival * crew_cost_per_oversized_container
Oversized port fees Calculation Step oversized_arrival * port_fee_per_oversized_container
20ft shipping cost Calculation Step 20ft_fuel_cost + 20ft_crew_cost + 20ft_port_fees
40ft shipping cost Calculation Step 40ft_fuel_cost + 40ft_crew_cost + 40ft_port_fees
Ship operating costs Calculation Step 20ft_ship_cost + 40ft_ship_cost + refrigerated_ship_cost + oversized_ship_cost + oversized_special_handling_cost + refrigerated_energy_cost

Simulation notes

Formula used

  • Beta Distribution =RAND()*(100-0)+0
  • Log Normal Distribution =RAND()*(100-0)+0
  • Discrete Normal Distribution =RAND()*(100-0)+0

Standards

The workspace needs to comply with all international standards.

  • (To come)

Workspace navigation menu

  • Enterprise Account
    • Applications
      • Aviation v.2)
        • Aircraft
          • Inventory
            • Orders
            • Parts Request
          • Maintenance
            • Fixed Wing
            • Helicopter
          •  MRO (Maintenance, Repair, and Overhaul)
          • Aircraft Records
            • Airframe
            • Engine Cycles
            • Engine Hours
        • Airport
          • Aerodrome
            • Aerodrome Plate
            • AIP
            • Aircraft Stand
            • Apron
            • Helipad
            • Runway
          • Air Traffic Control
            • Frequencies
              • Tower
              • Navigational
            • Slot
          • Contact
          • Emergency
          • Facility 
            • Arrival Departure Board
            • Baggage
            • Boarding
            • Cafe
            • Parking
            • Shop
          • Security
          • Weather
            • ATIS
            • METAR
            • NOTAM
            • TAF
        • Airspace
          • Map
        • Flight
          • Cargo
          • Flight Plan
          • Passenger
      • Rail (v.1)
        • Booking
        • Facility
        • Freight
        • Passenger
        • Rolling Stock
        • Track
        • Road (v.1)
          • Network
          • Shipment
          • Vehicle
        • Shipping (v.2)
          • Port
            • Berth
            • Crane
            • Security
          • Ship
          • TEU
        • Space
          • (To come)
        • Customer (v2)
          • Bookmarks
            • (To come)
          • Support
            • Contact
            • Forum
            • Live Chat
            • Office Hours
            • Requests
            • Tickets
          • (To come)
            • Feature Vote
            • Feedback
            • Surveys
          • Learning
            • Explanation
            • How to Guide
            • Reference
            • Tutorial
          • Settings (v3)
            • Account
            • Billing
            • Deployments
              • Workspaces
                • Modules
                • Plugins
                • Templates
                  • Airport
                  • Freight Depot
                  • Model Railway
                  • Urban Bus
                  • Urban Rail
                • Users

        Workspace trial causes engine modifications

        Mike's Notes

        Changes triggered by the recent successful workspace trial. I slept on this for a few weeks, just to be sure. 😇

        Most done already. A lot better.

        Resources

        References

        • Reference

        Repository

        • Home > Ajabbi Research > Library >
        • Home > Handbook > 

        Last Updated

        5/12/2026

        Workspace trial causes engine modifications

        By: Mike Peters
        On a Sandy Beach: 5/12/2025

        Mike is the inventor and architect of Pipi and the founder of Ajabbi.

        Some Pipi 9 agent engines are getting minor modifications as a result of lessons learned from the recent successful stress-test trial involving 15,000 generated web pages and directories in a workspace website UI. It took creating a massive static mockup for volunteer testers to explore freely and identify gaps.

        After these simple modifications, Pipi 9 will automatically render in about 50 seconds, another static mockup of a huge workspace website for testing. If that stress test is 100% successful, the next stage will be rendering a live version.

        Pipi 9 will then automatically generate much larger custom live workspaces without error. And on demand.

        The necessary minor modifications will change the deployment-workspace hierarchy previously described on this engineering blog.

        The previous workspace settings from 2018, stored as structured training data, also need to be edited. The test results indicate that everything can now be significantly simplified, resulting in a performance boost.

        Deployment Engine (dpl)

        A Deployment Type has been added to create a simple separation of functions and to drive URL pattern creation.

        • Applications a/
        • Customer c/
        • Global g/
        • Settings s/

        Workspace Engine (wsp)

        A new Module Entity has been added to store each workspace module's attributes. They are all inherited from a library of predefined Domain Model Objects.

        The revised hierarchy is

        User Account

        A User Account has three or more Deployments.

        • Applications
        • Customer
        • Settings
        An Enterprise Account can also have Global Deployments to share properties.

        Deployment

        A Deployment is a container for one or more Workspaces. A deployment has these properties;

        • ID
        • Code Name
        • Name
        • Description
        • One language (eg English)
        • One User Account
        • One Deployment Class (type of tenancy)
        • One Deployment Type (type of container)
        • Those properties are inherited by all workspaces.

        Workspace

        A Workspace is a container for one or many Modules. A workspace has these properties;

        • ID
        • Code Name
        • Name
        • Description
        • One inherited language (eg English)
        • One inherited User Account
        • One inherited Deployment
        • One pre-built Domain Model (eg, Screen Production).
        • One Domain Model Template (eg, Feature Film, Documentary, Live Broadcast), These templates can be customised and shared.
        • Main menu (Ribbon, etc)
        Those properties are inherited. This means each Workspace/Domain Model comes with its own set of prebuilt Security Roles and Security Profiles.

        Module

        A Module is a container for nil, one or more modules in a nested tree hierarchy. Modules can be rearranged in the Workspace UI via drag-and-drop. They are all semantically linked. A module has these properties;

        • ID
        • Parent Module ID
        • Code Name
        • Name
        • Description
        • Sort order
        • One inherited language (eg English)
        • One inherited User Account
        • One inherited Deployment
        • One inherited Workspace
        • One pre-built Domain Model Object (eg, Task, Runway, Locomotive, Film Set, Medical Device).
        • Set of prebuilt Security RolesSecurity Profiles.
        • Context menu (Ribbon, etc)
        • Learning objects
        • Contextural help
        • Attached
          • Tools
          • Workflows
          • State
          • Code
          • Data

        Playing with Krobar.ai

        Mike's Notes

        For some years now, I have subscribed to the Kromatic weekly email newsletter. It is one of the best. This is no innovation theatre, which is refreshing compared to NZ. I really like using mathematical analysis to test ideas. Especially when Tristan explains how to do it.

        It was here that I first learned how to use Monte Carlo Standard Deviation analysis using an Excel spreadsheet designed by Tristan Kromer. I then incorporated Monte Carlo into Pipi 9 to deal with uncertainty.

        I had actually been using Monte Carlo in Pipi 6 for many years since 2017, but I did not know it was called that. It was buried deep in algorithms inside an early module that later became an engine.

        Steve Blank, Alexander OsterwalderJason Cohen and Tristan Kromer are all top-notch. No bullshit. Everyone else is just a clone.

        I had a free office hour with Tristan Kromer earlier this year and will do more next year. Tristan is excellent.

        Once Ajabbi gets financially strong, I intend to sign up for weekly paid mentoring and advice from Tristan. It's not cheap, but it will be the best and worth it.

        I recently got early access to the Krobar.ai beta from Kromatic. Below are my notes, which I'm adding to as I play.

        Resources

        References

        • Reference

        Repository

        • Home > Ajabbi Research > Library > Subscriptions > Kromatic
        • Home > Handbook > 

        Last Updated

        05/12/2025

        Playing with Krobar.ai

        By: Mike Peters
        On a Sandy Beach: 05/12/2025

        Mike is the inventor and architect of Pipi and the founder of Ajabbi.

        Krobar.ai is a simulation platform from Kromatic. It's currently in beta.

        Signing up

        I signed up for a free trial in early September to test and provide feedback. I then got distracted and forgot about the trial. When I remembered, Meagan Wilder kindly let me back in early November, and I started playing with Krobar.

        Experiments

        There is no help documentation yet. My experiments started with me pressing buttons and seeing what happened, OK, playing. I then learned how to write ChatGPT 4.1 prompts and slowly built some skills. The chat dialogue appears highly accurate. I usually ask it to use industry-standard data for the default modelling values. I didn't have enough industry-standard values for mean, standard deviation, min, and max to tune the models yet. 😉

        One trick I found was to go to Google AI, ask a question, then turn the answer into a Krobar Prompt. Then I might find some of Steve Blank's writing, feed it into Gemini 3, and use the output as a prompt. 😀

        Simulation

        Each simulation has these pages.

        • Journey Map
        • Workflow diagram
        • Simulation
          • Tornado Chart
          • Histogram
          • Sensitivity Analysis
          • Financial Model (Spreadsheet)

        I'm still learning by trying the menu items. There are some hidden tricks. I learned some more by watching the video interview below. The order in which things are done matters with the AI.

        Downloads

        Everything can be downloaded in various formats. Very useful.

        • PDF Document
        • JPG image
        • Excel Formula
        • CSV data
        • JASON document

        Models

        These large, complex simulation models were built. Sometimes it took several attempts. They got better as I learned.

        • Ajabbi startup
        • Airport
        • Data Centre
        • Forestry Logging
        • Hospital
        • Movie Studio
        • Shipping (maritime)

        I exported the Excel formulas for import into Pipi's industry financial models.

        I will do some more soon, with a better understanding of how this works and predesigned prompts, and a bit more cunning. 😊 Then try ARR, ROI, etc.

        Suggestions

        Direct visual editing of the journey map

        • Enable drag-and-drop editing of journey map connections.
        • Enable more journey map steps to be created and added using a form.
        • Acts as input to AI

        Interview with Tristan Kromer about Krobar.ai

        Sample outputs from Film Studio 2 Simulation

        Knowledge Graphs Should Not Be Just for Analytics and Insights

        Mike's Notes

        Good words from John Gorman in Canada.

        Resources

        References

        • Reference

        Repository

        • Home > Ajabbi Research > Library >
        • Home > Handbook > 

        Last Updated

        04/12/2025

        Knowledge Graphs Should Not Be Just for Analytics and Insights

        By: John Gorman
        LinkedIn: 06/11/2025

        Information management professional specializing in semantic interoperability, with over 30 years of experience. Principal, Founder and Chief Disambiguation Officer at Quantum Semantics Inc in Calgary. Inventor of the Q6 information management model.

        There is, in my view, a large and currently under-served audience for knowledge graphs in the enterprise. These are employees, contractors, and yes, even executives who need access to a more granular level of access to company knowledge.

        Maybe we should start calling them 'Learning Graphs' instead.

        The interesting thing is, by providing this level of service, solutions to other gnarly challenges like data governance, metadata, reference and master data management, data fluency, semantic interoperability, and when done properly (i.e. FAIR-From-Birth) dimensional analysis of operational data stores, make themselves available.

        Sounds ambitious? Why not? Enterprise Information is now all about language, so how about we start there and leverage persistent patterns of classification and usage. Here are some of the immediate and 'downstream' benefits:

        • Data Governance. Most companies make the mistake of starting with data. The more natural approach - and with a lot less risk to life and limb - is to begin with the language of the business. And, you get to roll out a 'FAIR-From-Birth' business glossary as a side benefit, just like the big boys and girls.
        • Metadata. Business users rarely even care about metadata, but when they see how the language of the business connects to and is equivalent to metadata values the light bulbs start to go on. As a bonus, they also get to see how missing, misspelled, and misshapen vocabulary gums things up.
        • Reference and Master Data. This is another opportunity to see how the information supply chain should work. Crap components upstream means crap assemblies downstream. Ask your local supermarket manager how he handles a shipment of rotting tomatoes. 

        The benefit for business owners is two-fold:

        1. They get to see what kind of cleanup is required when they throw crap over the fence.
        2. They also get to see how one-and-done actually reduces their workload.

        Data Fluency. Seeing the connections between how they talk about the business and what kinds of data those conversations connect to? Priceless.

        Semantic Interoperability. Ah, yes... the Holy Grail. What if we made it possible to access semantically equivalent pairs as a start? So, if Jane McCallum, the CFO of Acme Inc. doesn't know (have knowledge of) the meaning of the acronym FLOC, she can simply look it up on her phone during her Monday executive team meeting and learn it. No embarrassing interruptions, just immediate access to enterprise knowledge. What a concept!

        Analytics and Insight. Finally, the raison d'être for almost every technical innovation so far this decade. When an information supply chain starts with the notion that every component, especially the very granular ones, should be engineered to fit into a downstream, multi-dimensional ecosystem of semantically connected information good things start to happen. 

        DM me if you want to learn more about Semantium's set of protocols.

        Your URL Is Your State

        Mike's Notes

        There were dozens of complex, hard problems that had to be solved before cracking the emergent problem of massive IT system failures. This took years. They often had to be solved in parallel because of their interwoven effects. URL patterns were one of them.

        I have been thinking about URL structure patterns for a while. I finally solved this problem for Pipi 9 back in October 2025. It was one of the last problems to solve before it could successfully build the UI of enterprise-scale workspaces. The UI turned out to be a thin wrapper, which was a complete surprise.

        The recent successful stress-test trial involved 15K web pages and directories in a rapidly built (days) web UI, and the URL pattern was perfect. It will now become possible for Pipi 9 to automatically generate much larger custom workspaces without error. and on demand.

        This is a great article from Ahmad Alfy in Egypt. He is totally correct in what he writes, and he helped me see the problem and patterns much more clearly.

        Thank you, Ahmad. I look forward to meeting you. Maybe you could be part of the team. 😊

        Resources

        References

        • Reference

        Repository

        • Home > Ajabbi Research > Library >
        • Home > Handbook > 

        Last Updated

        03/12/2025

        Your URL Is Your State

        By: Ahmad Alfy
        AlfyBlog: 31/10/2025

        Blog about front-end development and the web.

        Couple of weeks ago when I was publishing The Hidden Cost of URL Design I needed to add SQL syntax highlighting. I headed to PrismJS website trying to remember if it should be added as a plugin or what. I was overwhelmed with the amount of options in the download page so I headed back to my code. I checked the file for PrismJS and at the top of the file, I found a comment containing a URL:

        /* https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+css-extras+markdown+scss+sql&plugins=line-highlight+line-numbers+autolinker */

        I had completely forgotten about this. I clicked the URL, and it was the PrismJS download page with every checkbox, dropdown, and option pre-selected to match my exact configuration. Themes chosen. Languages selected. Plugins enabled. Everything, perfectly reconstructed from that single URL.

        It was one of those moments where something you once knew suddenly clicks again with fresh significance. Here was a URL doing far more than just pointing to a page. It was storing state, encoding intent, and making my entire setup shareable and recoverable. No database. No cookies. No localStorage. Just a URL.

        This got me thinking: how often do we, as frontend engineers, overlook the URL as a state management tool? We reach for all sorts of abstractions to manage state such as global stores, contexts, and caches while ignoring one of the web’s most elegant and oldest features: the humble URL.

        In my previous article, I wrote about the hidden costs of bad URL design. Today, I want to flip that perspective and talk about the immense value of good URL design. Specifically, how URLs can be treated as first-class state containers in modern web applications.

        The Overlooked Power of URLs

        Scott Hanselman famously said “URLs are UI” and he’s absolutely right. URLs aren’t just technical addresses that browsers use to fetch resources. They’re interfaces. They’re part of the user experience.

        But URLs are more than UI. They’re state containers. Every time you craft a URL, you’re making decisions about what information to preserve, what to make shareable, and what to make bookmarkable.

        Think about what URLs give us for free:

        • Shareability: Send someone a link, and they see exactly what you see
        • Bookmarkability: Save a URL, and you’ve saved a moment in time
        • Browser history: The back button just works
        • Deep linking: Jump directly into a specific application state

        URLs make web applications resilient and predictable. They’re the web’s original state management solution, and they’ve been working reliably since 1991. The question isn’t whether URLs can store state. It’s whether we’re using them to their full potential.

        Before we dive into examples, let’s break down how URLs encode state. Here’s a typical stateful URL:

        Anatomy of a URL
        Source: What is a URL - MDN Web Docs

        For many years, these were considered the only components of a URL. That changed with the introduction of Text Fragments, a feature that allows linking directly to a specific piece of text within a page. You can read more about it in my article Smarter than ‘Ctrl+F’: Linking Directly to Web Page Content.

        Different parts of the URL encode different types of state:

        1. Path Segments (/path/to/myfile.html). Best used for hierarchical resource navigation:
          • /users/123/posts - User 123’s posts
          • /docs/api/authentication - Documentation structure
          • /dashboard/analytics - Application sections
        2. Query Parameters (?key1=value1&key2=value2). Perfect for filters, options, and configuration:
          • ?theme=dark&lang=en - UI preferences
          • ?page=2&limit=20 - Pagination
          • ?status=active&sort=date - Data filtering
          • ?from=2025-01-01&to=2025-12-31 - Date ranges
        3. Anchor Fragment (#SomewhereInTheDocument). Ideal for client-side navigation and page sections:
          • #L20-L35 - GitHub line highlighting
          • #features - Scroll to section
          • #/dashboard - Single-page app routing (though it’s rarely used these days)

        Common Patterns That Work for Query Parameters

        Multiple values with delimiters

        Sometimes you’ll see multiple values packed into a single key using delimiters like commas or plus signs. It’s compact and human-readable, though it requires manual parsing on the server side.

        ?languages=javascript+typescript+python
        ?tags=frontend,react,hooks

        Nested or structured data

        Developers often encode complex filters or configuration objects into a single query string. A simple convention uses key–value pairs separated by commas, while others serialize JSON or even Base64-encode it for safety.

        ?filters=status:active,owner:me,priority:high
        ?config=eyJyaWNrIjoicm9sbCJ9==  (base64-encoded JSON)

        Boolean flags

        For flags or toggles, it’s common to pass booleans explicitly or to rely on the key’s presence as truthy. This keeps URLs shorter and makes toggling features easy.

        ?debug=true&analytics=false
        ?mobile  (presence = true)

        Arrays (Bracket notation)

        ?tags[]=frontend&tags[]=react&tags[]=hooks

        Another old pattern is bracket notation, which represents arrays in query parameters. It originated from early web frameworks like PHP where appending [] to a parameter name signals that multiple values should be grouped together.

        ?tags[]=frontend&tags[]=react&tags[]=hooks
        ?ids[0]=42&ids[1]=73

        Many modern frameworks and parsers (like Node’s qs library or Express middleware) still recognize this pattern automatically. However, it’s not officially standardized in the URL specification, so behavior can vary depending on the server or client implementation. Notice how it even breaks the syntax highlighting on my website.

        The key is consistency. Pick patterns that make sense for your application and stick with them.

        State via URL Parameters

        Let’s look at real-world examples of URLs as state containers:

        PrismJS Configuration

        https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript&plugins=line-numbers

        The entire syntax highlighter configuration encoded in the URL. Change anything in the UI, and the URL updates. Share the URL, and someone else gets your exact setup. This one uses anchor and not query parameters, but the concept is the same.

        GitHub Line Highlighting

        https://github.com/zepouet/Xee-xCode-4.5/blob/master/XeePhotoshopLoader.m#L108-L136

        It links to a specific file while highlighting lines 108 through 136. Click this link anywhere, and you’ll land on the exact code section being discussed.

        Google Maps

        https://www.google.com/maps/@22.443842,-74.220744,19z

        Coordinates, zoom level, and map type all in the URL. Share this link, and anyone can see the exact same view of the map.

        Figma and Design Tools

        https://www.figma.com/file/abc123/MyDesign?node-id=123:456&viewport=100,200,0.5

        Before shareable design links, finding an updated screen or component in a large file was a chore. Someone had to literally show you where it lived, scrolling and zooming across layers. Today, a Figma link carries all that context like canvas position, zoom level, selected element. Literally everything needed to drop you right into the workspace.

        E-commerce Filters

        https://store.com/laptops?brand=dell+hp&price=500-1500&rating=4&sort=price-asc

        This is one of the most common real-world patterns you’ll encounter. Every filter, sort option, and price range preserved. Users can bookmark their exact search criteria and return to it anytime. Most importantly, they can come back to it after navigating away or refreshing the page.

        Frontend Engineering Patterns

        Before we discuss implementation details, we need to establish a clear guideline for what should go into the URL. Not all state belongs in URLs. Here’s a simple heuristic:

        Good candidates for URL state:

        • Search queries and filters
        • Pagination and sorting
        • View modes (list/grid, dark/light)
        • Date ranges and time periods
        • Selected items or active tabs
        • UI configuration that affects content
        • Feature flags and A/B test variants

        Poor candidates for URL state:

        • Sensitive information (passwords, tokens, PII)
        • Temporary UI states (modal open/closed, dropdown expanded)
        • Form input in progress (unsaved changes)
        • Extremely large or complex nested data
        • High-frequency transient states (mouse position, scroll position)

        If you are not sure if a piece of state belongs in the URL, ask yourself: If someone else clicking this URL, should they see the same state? If so, it belongs in the URL. If not, use a different state management approach.

        Implementation using Plain JavaScript

        The modern URLSearchParams API makes URL state management straightforward:

        // Reading URL parameters
        const params = new URLSearchParams(window.location.search);
        const view = params.get('view') || 'grid';
        const page = params.get('page') || 1;
        // Updating URL parameters
        function updateFilters(filters) {
          const params = new URLSearchParams(window.location.search);
          // Update individual parameters
          params.set('status', filters.status);
          params.set('sort', filters.sort);
          // Update URL without page reload
          const newUrl = `${window.location.pathname}?${params.toString()}`;
          window.history.pushState({}, '', newUrl);
          // Now update your UI based on the new filters
          renderContent(filters);
        }
        // Handling back/forward buttons
        window.addEventListener('popstate', () => {
          const params = new URLSearchParams(window.location.search);
          const filters = {
            status: params.get('status') || 'all',
            sort: params.get('sort') || 'date'
          };
          renderContent(filters);
        });

        The popstate event fires when the user navigates with the browser’s Back or Forward buttons. It lets you restore the UI to match the URL, which is essential for keeping your app’s state and history in sync. Usually, your framework’s router handles this for you, but it’s good to know how it works under the hood.

        Implementation using React

        React Router and Next.js provide hooks that make this even cleaner:


        import { useSearchParams } from 'react-router-dom';
        // or for Next.js 13+: import { useSearchParams } from 'next/navigation';
        function ProductList() {
          const [searchParams, setSearchParams] = useSearchParams();
          // Read from URL (with defaults)
          const color = searchParams.get('color') || 'all';
          const sort = searchParams.get('sort') || 'price';
          // Update URL
          const handleColorChange = (newColor) => {
            setSearchParams(prev => {
              const params = new URLSearchParams(prev);
              params.set('color', newColor);
              return params;
            });
          };
          return (
            <div>
              <select value={color} onChange={e => handleColorChange(e.target.value)}>
                <option value="all">All Colors</option>
                <option value="silver">Silver</option>
                <option value="black">Black</option>
              </select>
              {/* Your filtered products render here */}
            </div>
          );
        }

        Best Practices for URL State Management

        Now that we’ve seen how URLs can hold application state, let’s look at a few best practices that keep them clean, predictable, and user-friendly.

        Handling Defaults Gracefully

        Don’t pollute URLs with default values:

        // Bad: URL gets cluttered with defaults
        ?theme=light&lang=en&page=1&sort=date
        // Good: Only non-default values in URL
        ?theme=dark  // light is default, so omit it
        Use defaults in your code when reading parameters:
        function getTheme(params) {
          return params.get('theme') || 'light'; // Default handled in code
        }

        Debouncing URL Updates

        For high-frequency updates (like search-as-you-type), debounce URL changes:

        import { debounce } from 'lodash';
        const updateSearchParam = debounce((value) => {
          const params = new URLSearchParams(window.location.search);
          if (value) {
            params.set('q', value);
          } else {
            params.delete('q');
          }
          window.history.replaceState({}, '', `?${params.toString()}`);
        }, 300);
        // Use replaceState instead of pushState to avoid flooding history

        pushState vs. replaceState

        When deciding between pushState and replaceState, think about how you want the browser history to behave. pushState creates a new history entry, which makes sense for distinct navigation actions like changing filters, pagination, or navigating to a new view — users can then use the Back button to return to the previous state. On the other hand, replaceState updates the current entry without adding a new one, making it ideal for refinements such as search-as-you-type or minor UI adjustments where you don’t want to flood the history with every keystroke.

        URLs as Contracts

        When designed thoughtfully, URLs become more than just state containers. They become contracts between your application and its consumers. A good URL defines expectations for humans, developers, and machines alike

        Clear Boundaries

        A well-structured URL draws the line between what’s public and what’s private, client and server, shareable and session-specific. It clarifies where state lives and how it should behave. Developers know what’s safe to persist, users know what they can bookmark, and machines know whats worth indexing.

        URLs, in that sense, act as interfaces: visible, predictable, and stable.

        Communicating Meaning

        Readable URLs explain themselves. Consider the difference between the two URLs below.

        https://example.com/p?id=x7f2k&v=3
        https://example.com/products/laptop?color=silver&sort=price

        The first one hides intent. The second tells a story. A human can read it and understand what they’re looking at. A machine can parse it and extract meaningful structure.

        Jim Nielsen calls these “examples of great URLs”. URLs that explain themselves.

        Caching and Performance

        URLs are cache keys. Well-designed URLs enable better caching strategies:

        • Same URL = same resource = cache hit
        • Query params define cache variations
        • CDNs can cache intelligently based on URL patterns

        You can even visualize a user’s journey without any extra tracking code:

        /products => selects category => /products?category=laptops => adds price filter => products?category=laptops&price=500-1000

        Your analytics tools can track this flow without additional instrumentation. Every URL parameter becomes a dimension you can analyze.

        Versioning and Evolution

        URLs can communicate API versions, feature flags, and experiments:

        • ?v=2                   // API version
        • ?beta=true             // Beta features
        • ?experiment=new-ui     // A/B test variant

        This makes gradual rollouts and backwards compatibility much more manageable.

        Anti-Patterns to Avoid

        Even with the best intentions, it’s easy to misuse URL state. Here are common pitfalls:

        “State Only in Memory” SPAs

        The classic single-page app mistake:

        // User hits refresh and loses everything
        const [filters, setFilters] = useState({});

        If your app forgets its state on refresh, you’re breaking one of the web’s fundamental features. Users expect URLs to preserve context. I remember a viral video from years ago where a Reddit user vented about an e-commerce site: every time she hit “Back,” all her filters disappeared. Her frustration summed it up perfectly. If users lose context, they lose patience.

        Sensitive Data in URLs

        This one seems obvious, but it’s worth repeating:

        // NEVER DO THIS
        ?password=secret123

        URLs are logged everywhere: browser history, server logs, analytics, referrer headers. Treat them as public.

        Inconsistent or Opaque Naming

        // Unclear and inconsistent
        ?foo=true&bar=2&x=dark
        // Self-documenting and consistent
        ?mobile=true&page=2&theme=dark

        Choose parameter names that make sense. Future you (and your team) will thank you.

        Overloading URLs with Complex State

        ?config=eyJtZXNzYWdlIjoiZGlkIHlvdSByZWFsbHkgdHJpZWQgdG8gZGVjb2RlIHRoYXQ_IiwiZmlsdGVycyI6eyJzdGF0dXMiOlsiYWN0aXZlIiwicGVuZGluZyJdLCJwcmlvcml0eSI6WyJoaWdoIiwibWVkaXVtIl0sInRhZ3MiOlsiZnJvbnRlbmQiLCJyZWFjdCIsImhvb2tzIl0sInJhbmdlIjp7ImZyb20iOiIyMDI0LTAxLTAxIiwidG8iOiIyMDI0LTEyLTMxIn19LCJzb3J0Ijp7ImZpZWxkIjoiY3JlYXRlZEF0Iiwib3JkZXIiOiJkZXNjIn0sInBhZ2luYXRpb24iOnsicGFnZSI6MSwibGltaXQiOjIwfX0==

        If you need to base64-encode a massive JSON object, the URL probably isn’t the right place for that state.

        URL Length Limits

        Browsers and servers impose practical limits on URL length (usually between 2,000 and 8,000 characters) but the reality is more nuanced. As this detailed Stack Overflow answer explains, limits come from a mix of browser behavior, server configurations, CDNs, and even search engine constraints. If you’re bumping against them, it’s a sign you need to rethink your approach.

        Breaking the Back Button

        // Replacing state incorrectly
        history.replaceState({}, '', newUrl); // Used when pushState was needed

        Respect browser history. If a user action should be “undoable” via the back button, use pushState. If it’s a refinement, use replaceState.

        Closing Thought

        That PrismJS URL reminded me of something important: good URLs don’t just point to content. They describe a conversation between the user and the application. They capture intent, preserve context, and enable sharing in ways that no other state management solution can match.

        We’ve built increasingly sophisticated state management libraries like Redux, MobX, Zustand, Recoil and others. They all have their place but sometimes the best solution is the one that’s been there all along.

        In my previous article, I wrote about the hidden costs of bad URL design. Today, we’ve explored the flip side: the immense value of good URL design. URLs aren’t just addresses. They’re state containers, user interfaces, and contracts all rolled into one.

        If your app forgets its state when you hit refresh, you’re missing one of the web’s oldest and most elegant features.