System architecture

Recommendations

The article below provides a set of rules on how to maintain interface integrity both for end-users and developers.

Configuration

Avoid adding unnecessary parameters to .conf files. Avoid using path for internal purposes whenever possible. If you need to change the location of any of the panel files, replace it with a symbolic link.

XML

All functions of a control panel work with XML documents, which form replies for users (such XMLs are the only data source to form a reply). XML requirements:

  • the root element should be named doc
  • avoid using XPath starting with "//" as you may find more nodes than you needed

General notes

  • Avoid situations that confuse the user; if an issue occurs, the user should always know exactly what to do to resolve the issue. Whenever a situation arises that requires additional settings, they should always know where, how, and what settings they need to make. Ideally, the system should redirect the user to fill out the necessary settings and redirect them back automatically. If they have questions about the system's behavior, they should be able to quickly find the answer in the documentation (preferably in a hint).
  • Whenever possible, try to resolve problems automatically, without alerting the user. For example, if a data inconsistency is detected and can be resolved without question (rotate already exists), we fix it. If a required directory or file is missing, and we know what permissions it should have and what the default file contents should be, we automatically create it. And so on.
  • In case of warnings, write the corresponding notification into a log file, and show a bannner to the user.
  • Allow users with higher access levels to access accounts (even disabled) of users with lower privileges.
  • All sections on the Dashboard should be arranged into columns.
  • All code should be multithreaded.
    1. Temporary query data should be stored in the XML session.
  • Isolate the panel's functions.
    1. Different functionality features should be located in different files.
    2. Use unnamed namespace to hide module data structure.
  • Functions that are used for values check (check in metadata) should allow for an empty value of a parameter.
    1. To forbid empty values, use the required attribute.
    2. A value may become empty due to internal modifications. In this case, it should be considered valid.
  • All group operations (delete, enable, disable, etc.) are called for each individual element. If an operation cannot be performed, an exception is always thrown. This exception will be caught at a higher level, and the operation will continue for other elements. Ultimately, in the event of errors, the user will see a list of elements for which the operation could not be performed.
  • Ignore attempts to delete objects that don't exist (do not throw exceptions).
  • Avoid code duplication.
    1. Avoid situations where multiple panel functions perform same actions. Such actions should be combined into separate functions and called via internal calls to allow for centralized behavior modification. It is possible to protect such functions from being called directly from outside.
  • All functions that create any entities should return their identifier (by which they can be accessed) in the elid tag. If multiple entities are being created, multiple elid tags are returned.

Forms

For more information about XML documents, please refer to the article Description of forms.

  • Edit/Create functions should return a new element identifier in the id node, and a new name, if it differs from the identifier in the name node.
  • The confirm parameter (password confirmation) is not processed in the code, thus it may not be specified in API calls.
  • If an unlimited value can be specified in the form, it should have a placeholder with an "unlimited" message, handle an empty value, and set a large value automatically.
  • If element access is checked through get, you don't have to check it through set (get is always called before set).
  • Parameters checks should be specified in XML (@check and @checkargs). Values for slidercheckbox and select type fields are checked automatically. During set requests, the corresponding get request is also made.
    • slider an integer from the range [min,max]. If nothing is specified, considered as min.
    • checkbox possible values: on, off. If nothing is specified, considered as off.
    • select one of the values in the corresponding slist. If nothing is specified, the first value from the slist is taken after sorting.
  • Values that are returned in get requests should meet XML requirements.
    • If a developer didn't return values for slidercheckbox and select fields in the get request, the value will be set automatically (see above).
    • Parameters sent in the get request will replace values of the same-named fields, so a user will see the form with values already filled into the form fields.
  • Values ​​for input fields in new records (query with empty elid), filled via setvalues, should be generated automatically during a get request, unless they were passed as parameters.
  • Password fields for integrating the panel with external systems (other panels: IPmanager, DNSmanager, database servers, etc.) must be of the password type. When the form is displayed (a get request), the current value stored in the panel must be returned.

Lists

For more information about XML documents that describe a list, please refer to the article Description of lists.

  • A list heading should match the name of the list in the main menu (if a shortening was not used)
  • Use captions for props only upon agreement with a development manager.
  • Statistics should show a total sum. All indicators should show both figures, e.g. "3/40" rather than just "4/". The column with prop should display the total sum of the smallest object (for example, if it's an object's state "on/off").
  • Do not create columns without values.
  • Сomments, notes, etc. should be specified as hints to a corresponding image if the list contains prop; if prop is not present, they should be specified in a separate column in the form of a text.
  • If prop/xprop contains a "lightbulb" icon, it should stand first.
  • There should be no more than 8 groups of buttons per list.
  • When describing a column of a type containing a state, the text color must be specified.

    • red  error
    • yellow  warning
    • green  no errors

     

Toolbar buttons

  • Status change buttons (activate/suspend): place on the toolbar only the buttons that change only one state (the most important one), all other statuses can be changed via checkboxes on the element edit form.

Buttons are located in the following order (if you don't have any of them, skip it):

  • Add
  • Edit. If this button is present, default="yes" should be located after it. (Users may change it in the table settings form)
  • Delete
  • --separator--
  • Enable
  • Disable
  • --separator--
  • any other buttons that are not described below; you may set separators between groups of buttons if needed
  • --separator--
  • report buttons
  • --separator--
  • filter buttons
  • --separator--
  • "Go to" buttons (e.g. to another control panel, etc.)

Databases

  • Do not use DBMS reserved words as table and field names
  • Use upper-case keywords of the SQL language
  • Use the '_' symbol as a separator within words
  • Tables
    • Names of functions that output list contents should match table names (if possible)
    • Table and field names should be in lower-case
    • Table names should be written in the singular (E.g. server, not servers). Otherwise, external links will be formed incorrectly (see above).
    • A user table should be named as "users" (user is a reserved name in some databases)
    • Many2many tables are named with a "2" to the left and right of the "2" in the singular.
  • Fields
    • Do not use prefixes in fields' names (indicating a type, size, etc.)
    • For boolean type, string field of length is 3. Values: on/off values ​​(for compatibility with checkbox)
    • Do not use autoincrement fields (due to MySQL data replication issues)
    • A field referencing another table must have the same name as the referenced table (if there are multiple references, the table name should be used as a prefix)
    • The field containing the unique record identifier must be named id
    • The field containing the unique record name must be named name
    • The field containing the object's on/off state must be named active, with possible values ​​of on/off
    • The field containing the access level must be named level , be an integer, and accept values ​​according to the rules
    • Fields containing passwords must be encrypted. This increases data security (particularly against SQL injection)

SQLite

  • Databases are stored in etc catalog
  • The file name extension for a database is .db

Menu modules are located in the following order:

  • Product sections
  • System state
  • Integrations
  • Settings
  • Help. The "Help" module should be placed first on the list.

Text messages

This section will be updated as new precedents emerge.

  • Make sure the style of interface messages is consistent:
    1. Use upper-case hints without a dot at the end;
    2. Use messages from the common section for captions.
  • Unique identifiers should be written as "Id".
  • Short descriptions for buttons: ideally, their size should match the button's width. The maximum size is 1.5 of the button's width. You may use clipped words with a dot at the end. A hint should show detailed information about a toolbar button.
  • IP-addresses and other addresses should be written as follows:"IP-address" "MAC-address". Upper-case abbreviation with a hyphen.
  • Module names. A module name should fit a raw in the left-side menu. The text should be short enough to fit on one line in the main (side) menu. The maximum length of the title also depends on the width of the toolbar, i.e. the title and toolbar should fit on a 1280px wide screen.
  • A hint should contain a detailed description. For example, if the checkbox reads "Enable Spamassassin for domain", the hint should read the following: "Allow spam filtering using Spamassassin for the selected domain name". If a user is not familiar with Spamassassin, he can learn more about it in the hint. If the message is self-explanatory and no elaboration is required, write where and what the field is used for or rephrase its name in other words.
  • If the information you want to fit in the hint takes more than 5 lines, write a technical article about it (even if it is only a couple of paragraphs) and add a link to it in the “Useful links”.

Resource limits

  • An empty value is used for unlimited values. 0 means a resource cannot be used (it is not the same as an unlimited value). Use a placeholder to show clients that they can enter an unlimited value. Example:
 <field name="domainlimit">
     <input type="text" name="domainlimit" check="int" unlimit="" checkargs="0,"/>
 </field>
 ...
 <msg name="placeholder_domainlimit">unlimited</msg>
  • If 0 cannot be used as a resource limit, validators can be used (the minimum value is 1) helping users avoid misunderstanding.
  • Reducing limits. If a user consumed more resources that you want to allow, cancel this operation and generate an error message.
  • Overselling is allowed by default meaning that a reseller can allocate more resources to their users than they are allowed by the provider. When allocating a resource to a user, both user and reseller's limits should be checked (summing up resource consumption by all users of that reseller).
  • If the limit is not explicitly set, access to the resource must be closed.

Process handling

You can add custom handlers to every stage of query processing.

  1. Receiving a request, reading and parsing request parameters. GET and POST data are processed, and an internal data representation is generated for convenient and quick access.
  2. User authentication (an attempt to determine the name and access level of the user who sent the request)
  3. Searching a function by name (the function name is taken from the func parameter; if the parameter is missing, it is assumed to be desktop)
  4. User authentication
  5. Creating XML for the session (lang, func, binary, host)
  6. Calling global event handlers (those attached to the "*" action) before="yes"
  7. Calling event handlers for the selected function before="yes"
  8. Calling a function handler
  9. Calling event handlers for the selected function after="yes"
  10. Calling global event handlers (those attached to the "*" action) after="yes"
  11. Committing transactions (writing files, deleting temporary data, calling commit for databases)
  12. Generating a response in the required format (the format is specified via the out request parameter)

User authentication

At this step, the system is trying to determine the name of the user who has made a request and their user role. The authenticate basic function is responsible for user authentication. This operation is performed to check whether a certain user exists in the system or not.

  1. COOKIE check ( <panel name> + "5"). The COOKIE must contain the following fields, separated by a colon: theme name, language abbreviation, and session id.
    • saved sessions are uploaded from the /usr/local/mgr5/var/ispmgr.ses file (if it has not been uploaded yet). This file is written each time a session code is created, in case the panel terminates unexpectedly.
    • user verification (calling authenticate.<authorization method name>)
  2. User authentication based on data received from the client (authenticate is called).
  3. Authorization by IP. In this case, the username is already known (set in the configuration file), but calling authenticate is still necessary to determine additional parameters.
  4. Trusted access authentication. Similar to the previous step,except the username is the local administrator's username.

If none of the attempts are successful, the session is assigned access level 0.