In a typical ordering system, you might have two objects: orderForms and orderLines:
orderForms would have fields such as the time of order, delivery address, connection to buyer's account and so on.
Each orderLine would be connected to a single order form and each record would be the details of the item ordered, for example item name and price.
Usually, you allow a buyer to "create a new orderForm" and you flag this as a "draft" order - it's effectively a shopping basket. Once the buyer has added all the items (orderLines), you change the status of the orderForm to "in progress" or something like that and then no more changes can be made by the user.
This does not seem to work very well in knack because the user can reverse-engineer this very easily from the URLs, which are the way that record IDs are passed to the web forms.
For example, let's say I create an orderform which is assigned the knack record ID 58da5281e4dd89346adae61a. It is shown on my app home page in a table. The table shows "order forms connected to the current user", filtered by "status = draft". From this table, I can click "add items" which takes me to an edit form, an "add connected order lines to this order form" page.
When I navigate to this page, let's say I set to have a url of "add-items" (using that page's builder-set URL property), I will have in my browser something like this:
Now, let's say I finalise my order (change status from "draft" to "in progress"). It disappears from my "draft orders" table because of the filters, and now it appears on a different table: "order forms connected to the current user" and from that table, I might be able to open a read-only "details" page.
However, even though there is no way for me to click back to the add-items page in the builder, if I simply note the record ID - 58da5281e4dd89346adae61a - or even if I had just simply bookmarked the "add-items" page for that particular order - I can still go back to the add-items page and modify my order.
This appears to basically arise because knack tries to combine permissions to view objects with permissions to view the pages holding those objects. But what my experiment seems to prove is that this permission is set object-wide and never record-wide.
The workarounds I can think of are:
1) Somehow try to hide orderlines on the add-items page if the order form is "in progress". ie each orderline has a text equation that reads the "status" of the connected order form. Filter the orderline table for "orderlines with connected orderForm status of 'draft' only". Fine but doesn't work for the orderForm information because that's likely to be an editable header form on the add-items page...
2) Create separate objects, a "draft orders" object and a "in-progress orders" object. Every time an order is placed, copy from "draft" to "in-progress" and ensure the buyer has no permission to see "in-progress" orders. Really annoying workaround, as I have to manually map every field from "draft orders" to copy to "in progress orders" as a Record Rule and then manually update this rule every time I want to add a new field. This also doubles the number of records, in the absence of a feature to automatically delete old "draft" records.
We could really do with a small extension to the new Page Rules feature, which shows or hides views on a page based on user characteristics (eg user roles). But to solve my problem, we need to be able to hide views securely based on value of fields of the object which would otherwise be displayed on the page.
As someone relatively inexperienced with databases in general, am I missing something or is this a huge security flaw in knack for this application?