2,834 procedures, one convention
V.E.T.S. keeps its application logic inside the database, and the name of every one of its 2,834 stored procedures tells you what it touches, who owns it, and whether you may change it.
This page is the map of that layer: the naming convention, the split it encodes, and six routes into the parts of the system it runs. Read the convention first. Individual procedures make much more sense once you can read their names.
What the first letter of an object name means
Every database object is named [scope][type][_Module_][Entity]. Scope is one letter: a for application, s for system. Type is three: tbl a table, tbv a secured view over one table, viw a multi-table or computed view, stp a procedure, fnc a function. So atbl_VETS_Animals holds animals, and sstp_TeamDoc_Inputs_SaveInput is the system procedure that writes a TeamDoc input. You know an object’s blast radius before you open it, provided the scheme actually holds.
Of 2,834 stored procedures, 1,548 are astp_ and 1,113 are sstp_. Those are the application and system procedures this page is about.
The same scheme runs through everything else: 712 atbl_ tables against 397 stbl_, 179 afnc_ functions against 68 sfnc_. In views the prefix also encodes security scope. atbv_ (600) and stbv_ (318) filter rows by tenant and permission; aviw_ (764) and sviw_ (350) join and compute without filtering; atbx_ (76) and stbx_ (34) cross tenant boundaries deliberately; arpt_ (109) aggregates for reporting. Which family a query reads from decides whether it is filtered at all. How the view layer enforces row and tenant filtering →
The convention is also shaped like a URL. astp_VETS_TeamDoc_Tasks_CreateAnimalTask maps onto /api/VETS/TeamDoc/Tasks/CreateAnimalTask without anyone inventing a translation, and so does every other name in the layer. It is already addressable.
Why nothing with an s in front of it ever gets edited
The split is not decoration. System objects are the foundation everything else sits on: the TeamDoc document store, the user and permission tables, the website generator. Every tenant and every feature reads the same stbl_, sviw_ and sstp_ objects, so a change to one of them is a change to all of them at once. Application objects are the veterinary product built on top, where a change stays inside the feature that owns it.
That produces one operating rule, and this layer is organised around it: you extend a sacred object by writing an application object that calls it, never by editing it. sstp_TeamDoc_Inputs_SaveInput is the clearest case. It is the single write path for TeamDoc content; features add behaviour by calling it, not forking it.
The database does not leave this to discipline. sstp_Database_VerifyDDLActionPermission receives the event type and the T-SQL command itself, and refuses the change unless your login holds a matching namespace grant in stbl_Database_Permissions, checked separately for create, alter and drop. That table currently holds two rows over a single namespace.
Changes that do get through are recorded rather than overwritten: stbl_Database_Versions holds 53,117 versions across 11,043 distinct objects. Recreating an object would throw that history away, which is why altering in place is the house rule.
Sacred is a discipline plus a guard, not a lock. The system layer can be changed. It just costs everybody at once.
Six ways into 2,834 procedures
Each route below is organised around the pattern its procedures share rather than a list of them. The list comes out of sys.procedures in one query; the pattern is the part that takes reading. They follow the order a request moves through the system, and most of them operate on one structure, the TeamDoc tree, where documents, tasks, pages and animals all live as nodes. The tree these procedures read and write →
Authentication & Permissions
Every request resolves who you are and what you may see before anything renders. Also where you find out that access is granted to a group and never to a login.
How a request proves who it is →
Website & Menu Generation
Every page, menu and piece of site chrome is assembled from the tree at the moment you ask for it. Nothing here is a static file, including the page you are reading.
How every page is assembled at request time →
Tasks & Patient History
Work, and the medical record it produces. Patient History is the one part of the system that stops being generic and handles each record type on its own terms, so the output reads like a medical record.
Where the platform deliberately stops being generic →
How a click becomes HTML
Most of the interface is assembled in SQL and delivered as markup rather than as data. A JavaScript function posts to MobileAJAX.aspx, which calls a stored procedure, which returns HTML as a string, which JavaScript writes into the page. No page reload anywhere in the sequence.
You can watch it happen here. The navigation underneath this article was not in the HTML your browser was served. BuildFooterNavForPage() posted this page’s key to MobileAJAX.aspx, sstp_TeamDoc_WebsiteGetFooterNav resolved the page’s root, collected the published pages grouped beneath it and returned the markup. Open your network tab and reload to see the round trip.
The reusable pieces are functions. Of the database’s 249 functions, 179 carry the afnc_ prefix and 28 of those are afnc_HTML_, each returning one fragment of markup that several procedures share. The animal card shows both the pattern and the constraint it runs into. afnc_HTML_AuthenticatedNow1Animal1 is a table-valued function that builds the card; afnc_HTML_AuthenticatedNow1Animal0 is a 970-character scalar wrapper whose entire body calls it and returns its ResponseHTML column. It renders nothing. The pair exists because T-SQL will not accept a multi-statement table-valued function where a scalar value is required.
Keeping markup next to the query means a change is one object away and a component stays identical everywhere. The cost: presentation lives in the database, so a front-end change is a schema change.
What runs when nobody is logged in
Housekeeping follows the same convention. sstp_Security_Maintenance_RevokeExpiredUsers finds users whose expiry date has passed, marks them expired and revokes their database access one at a time. sstp_Database_Maintenance_ApplyPermissions reapplies object-level permissions across the database and logs what it changed. astp_Automate_spHTTPRequest is the seam where the database makes outbound HTTP calls to external services.
None of this is a separate subsystem. It is the same naming scheme and the same split, applied to the parts of the platform no user ever sees.
Where to go next
The six pages above go into each part of this layer properly. If you are evaluating rather than building, the convention and the sacred split are the two things worth carrying away; everything else in the database is an application of them.
Start building against this layer →