From 784664b2a46b32b6420065270e357cd2b64fcc7b Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Thu, 7 May 2020 00:09:31 +0000 Subject: [PATCH] --- devdocs/specs/core-workorder.txt | 234 +++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 devdocs/specs/core-workorder.txt diff --git a/devdocs/specs/core-workorder.txt b/devdocs/specs/core-workorder.txt new file mode 100644 index 00000000..8611279c --- /dev/null +++ b/devdocs/specs/core-workorder.txt @@ -0,0 +1,234 @@ +WORKORDER + +Lot's to go in here but for now this is holding my planning and thoughts until can set in stone: + + +## Copied over from client todo while testing / planning, probably outdated if you're reading this after May 2020 + +todo: PLANNING WORKORDER considerations: + QUESTIONS: + Why do I need to make a wo first before I can update it? (i.e. why did I make a CREATE route?) + still no idea after lot's of planning, answer is probably not needed at all + + How can I avoid concurrency issues? + concurrency check each record in graph, not entire workorder from top + + How to minimize data sent, make fast saves? + I'm leaning towards the tons of routes option, need to test it out + + PATCH, send all changes in graph in one go + most efficient, sends all changes in one go + if any part fails it all fails + requires second copy of wo for diffing + UPDATE (PATCH): Send only changes in whole graph from client with an OP (for "operation") flag at each level indicating to change that part or not, a flag? + WO (OP flag=no change, no concurrency token, basically empty but for the fields that hold the descendents that are changed) + woitem 0 (OP flag="Delete" and concurrency token, no other data with it, just the id and flag and ctoken) + woitem 1 (OP flag ="update", all fields as in a "put" operation, nothing left out, assumed all are changed) + woitem2 (OP flag="no OP", just a placeholder for children with changes) + labor 2 (OP flag = "update" with all data) + labor 3 (OP flag="delete" with concurrency token and nothing else) + labor 4 (OP flag="Add", with all PUT data) + issues with patch: + how to post a whole object leaving blank when so many fields will be required? + maybe we don't make them required at the object field annotation level but only at the db level and as a biz rule? + how to synchronize objects and id's? + i.e. reverse patch back again + for example, you add two woitems, save, you have two now that are not id'd and don't know which is which + server has to return something identifying which is which and assigned ID, plus it might add data back or change data due to rules or whatever + Maybe server sends back entire saved objects? + issues: + how to update client end with update back from server when saved (server will add id and may change fields or even add things) + + * TONS OF ROUTES: Update individual portions as seperate objects to their own routes sequentially + i.e. client traverses and diffs virgin copy and edited copy of wo + determines what's different, only sends an update for each object to it's own route as appropriate + on successful update fixes up the edited copy of that object + on all updates done, the edited copy becomes the virgin copy (or do we need 3 objects at one point in case of fail?) + + requires second copy of wo for diffing + goes over workorder, looks for changes, sends update for each object individually and patches up local from result + so if a workorderitempart has changed then it sends only that for update individually + Example routes: + Post: Workorder/1/WorkorderItem/2/Labor/4 {updated object} + WorkOrder/{woid} <-entire workorder, get for all, post for entire, put to update entire (not likely to use but?) + WorkOrder/{woid}/WorkorderItems <- all workorderitems, post to add new, put to update all as a collection + WorkOrder/{woid}/WorkOrderItems/{woitemid} <- CRUD single woitemid + WorkOrder/{woid}/WorkOrderItems/{woitemid}/Labors <- entire labor collection CRUD ops over all collection (also ADD new labor here (POST)) + WorkOrder/{woid}/WorkOrderItems/{woitemid}/Labors/{laborid} <- Crud on individual item + + This way is pretty solid, will result in a lot of routes but a lot of the code can be shared in the biz object, so for example if updating a labor or a collection of labor most code the same + Efficiency: + Since there is a route for every bit of the workorder the client can pick how high up to update based on diff check + so if only one single bit of a header has changed then only update that bit (or will it need the collection to not remove it? No because collection route is where you remove an item) + or if only a deeply nested labor has changed, just PUTS it to that exact route and udpates concurrency token on result + since the workorder is not really influenced as a whole by updates to portions this could work and be a bit less problematic than JSONPATCH which really seems to be a bit of a stretch + + +NOTE: can put part of the route in the controller, so for example if every route in that controller needs to identify a workorder then this kind of thing is possible, not sure if helpful or not yet: +[Route("api/campus/{campusId:int}/building")] +public class BuildingController : Controller { + //... + + [HttpGet] + [Route("{buildingId:int}")] // Matches GET api/campus/123/building/456 + public IActionResult GetBuilding ([FromRoute]int campusId, [FromRoute]int buildingId) { + //... validate campus id along with building id + } +} + + issues: + very chatty, could be slow + + PUT, update entire workorder on every save + Very easy to code, basically send it all and see what happens + Very clean, no need to worry about bits and pieces being tracked etc + issues: + not very efficient, needs to send entire graph on every save even if user just changed one character + + + How to support undo? + How to show what's dirty on form? + + + + BUSINESS RULES (v7) + In reality there are almost no business rules in v7 workorder graph. + Only serious one is woitempart requires serial if serialized + Rest are all related to length of fields, required fields, date order etc and only a few of those to boot + Looks like this is not an issue regarding v7 stuff at all + + + DEPENDENCIES + Workorder is not dependent on it's children for anything + WoItem is not dependent on any of it's children + In fact nothing in any part of the wo is dependent on anything else during normal ops + + CONCURRENCY + If the client updates part of the wo graph, only that exact record really needs dependency checking. + There *is* however business rules that might take hold but that's all at the server and not related to concurrency directly + For example, on any change to the wo graph the server has to see if the wo is still editable and hasn't been locked or user's rights changed + But that's not strictly concurrency related in teh sense that another user change the *same* record being updated + So, for v8 as long as it can handle a portional update to part of the graph and uses the concurrency of that exact record to check then it sidesteps a lot of multi-user scenarios + This was only an issue in v7 due to it using only the wo header itself as the source of concurrency checking which would *always* involve the whole graph in any change anywhere + + for example: + WOHEADER (concurrency id, dirty flag at client) + WOITEM (concurrency id, dirty flag at client) + woitempart (concurrencyid dirty flag at client) + woitemlabor (concurrencyid, dirty flag at client) + WOITEM (concurrency id, dirty flag at client) + woitemscheduser (own concurrency, dirty flag etc) + woitempart (concurrencyid dirty flag at client) + woitemlabor (concurrencyid, dirty flag at client) + + ROUTES + In light of dependencies and concurrency it is ideal if the server can handle updates to any portion of the graph independently + But, do we really want CRUD routes for every descendent of the workorder graph? (maybe, just not sure) + + + + TEST + Do a practical test of a mocked wo, woitem, woitemlabor or whatever, see how it would be updated, fetched concurrency checking etc + QUESTIONS: + How to do CRUD efficiently with a workorder and client? + + + PROPOSAL TO TEST: + Create enough of a graph to test, 3 layers two grandhild collections should be sufficient: + WO + WOITEMS + WOITEMLABORS + WOITEMPARTS + + CREATE (POST): + CreateFromxxxx routes (NO TEST REQUIRED) + POST accepts NEW workorder full graph (test) + RETRIEVE (GET): + Get(id) - simple get, just confirm entire graph comes across + GetByRelative(ayatype, id) (no test required) + + UPDATE (PUT?) + Test code tons of routes method detailed above + + SERVER + Server accepts graph at single WO POST route (since it's not a put) + UI + ui manufactures the return object with the OP fields by doing dirty tracking on changes + DELETE + Not much here except handling delete will be more intensive and sophisticated when have real data but for now if the graph deletes then that's enough + Test how to delete graph without ref. integrity errors + + + UI + Only send the bits that are altered to save bandwidth + All updates are technically a PATCH operation + Because it starts with a wo object provided by the server? + or is this even necessary now? + think Patch + CONCURRENCY: + if any part of the patch fails the whole patch fails + + idea: UI reflects tentativeness state of object: + The UI doesn't imply something is done by changing it fully until the save is completed. + This serves two purposes: + 1) user knows at a glance what isn't saved yet and will know it's waiting for save clearly, hopefully leading them to save more often, + 2) client doesn't need to track invisible shit behind the scenes, can more easily do patch updates right off UI source + + e.g.: + if deleted a row in parts, that row doesn't disappear but rather shows crossed out, maybe grayed out but still there until save to indicate it's tentative status + if added a row, shows green or something or bold or asterisk, (can style with css based on state) until saved + problems: + how to handle regular fields that are changed (that's a lot of field data to track for changes)? + Maybe client keeps a virgin copy of the original wo for comparison + periodically does a compare and flags differences on updates? + (this would also help to serve as an Undo maybe?) + + + + A biz object for each one? + probably need the parent for biz rules and shit so likely best to keep in one file + Controller - all in root controller or seperate controllers? + likely follows biz object decision + case 1714 re-rises the question about concurrency and mutiple editors of a workorder + Look into how independent changes can be from each other, i.e. is it safe to have two users editing two different woitems on a workorder? + This might make people happier. + Like, what exactly affects what else on a workorder. Do you save the whole wo to the route at once even though you just added a woitem or..? + If I code it to send the whole wo on a change to even a grandchild then that's heavy traffic for a minor change + - actually no, it's not really that heavy, even a fairly fat workorder will be way under 100kb, most probably under 1kb + should really only send the minimum data required to fulfil the change. + Maybe need two copies of wo at client so can tell what has changed and then only send that bit. + But then need routes to handle that? + Or can the wo route just accept a blank header with items hanging off it that have changed only? (like a patch?) + + Use foreign keys!! + Consider UI in this as well, will need to decide at least what is visible when + Workorder UI good ideas here: https://rockfish.ayanova.com/default.htm#!/rfcaseEdit/3475 + How to add items, like new woitem? + send to server get back new object? + lots of biz rules and stuff need to happen, want to minimize load at client + but lots of data back and forth is not ideal + maybe request a woitem and get it back? + what exactly needs to be processed in the wo when items are added / removed? + math / totalling? + simple calcs sb client doable + this will drive what has to happen. + Need to go over all wo features and factor them into this decision properly + The whole idea of a completed section of a wo and stuff, is that dropped due to TTM or still viable? + maybe can pick out the best new features of that which can be integrated into existing design rather than re-inventing the wheel + Here is an overview: https://rockfish.ayanova.com/default.htm#!/rfcaseEdit/3412 + How best to be able to service LoanUnits on a workorder? + Just make them Units with extra properties exposed if type of loaner? + This seems simplest, but what will it effect? + Hard to make them serviceable if they are an alternate table of source for what's being repaired as that breaks a lot of other code or adds exceptions + Customer is then who exactly because it's fundamental to a lot of wo functionality? + from a biz perspective isn't it like you are your own customer when you service your own equipment that you loan out? + Does Serial field need to be numeric, could it be text instead? + prompted by case 3428 saying that it's hard to deal with constant conversion to text for UI etc + plus, I'm thinking it opens door to textual scheme like appending -A or whatever to a wo. + or, is that a display issue? + Calling something "serial" implies it's unique but it isn't, maybe I should call it "number" instead or "ID" or something? + INFO: did a test workorder with ALL fields filled out heavily and one woitem, exported from db entire graph based on detailed report so every line was every item repeated + still only 84kb and it's a lot bigger than any typical wo in v8 would be as it will be far more efficient without having to repeat lines flatly + so I think size of object is a non-issue really from a practical standpoint. + +