System architecture

Recommendations

This article describes how to maintain interface integrity both for end-users and developers.

Avoid creating unnecessary parameters in .conf files. If possible, avoid using path for internal purposes. If you need to change the location of any of the panel files, you can always replace it with a symlink.

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 "//" - you may find more nodes than you needed.

General notes

  • Make sure that a user knows what actions he should perform to resolve an issue if any. If additional operations are required, he should know those operations are and where to perform them. Ideally, the system should redirect him to configuration and get him back automatically. Should he has any questions about the system, he can find answers in the Documentation (or in a hint).
  • The system should try to resolve issues automatically. For example, if some data do not match, the system should resolve this issue ("rotate" already exists). If a required directory or file is not present, and we know their permissions, and default file's content, we need to automatically create them, etc.
  • In case of warnings, write the corresponding notification into a log file, and show banners to users.
  • Allow users with higher privileges to drill down to accounts of users with lower privileges.
  • All sections on the Dashboard should be arranged into columns.
  • Your code should be multi-threaded.
    1. Temporary query data should be stored in the XML session.
  • Isolate the panel's functions.
    1. Different functionality 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. You can specify the required attribute to forbid empty values.
    2. A value may become empty due to internal modifications. In this case, it should be considered valid.
  • Group operations (deletion, activation, suspension, etc.) are called for each element. If an operation cannot be performed, an exception should be generated. The operation will be performed for other elements. In case of errors, a user will see the list of elements for which the operation could not be performed.
  • Ignore attempts to delete objects that don't exist (do not generate exceptions).
  • Avoid code duplication.
    1. Avoid situations when several functions perform the same operations. Such operations should be grouped into separate functions and called by InternalCall to centrally change system behavior.
  • Functions that create any objects, should return their identifier in the elid tag. If several objects are created, several elid tags are returned.

Forms

For more information about XML documents, 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 may not 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 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 - min.
    • checkbox - possible values: on, off. If nothing is specified - 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 entered into the form fields.
  • Values for input fields i new object (a query with empty elid), that are entered using setvalues, should be formed automatically during the "Get" request if they were not passed as parameters. For example, if a value into the "Email" field after changing the Name field, the code may look like something like that:
if (ses.Has("Name") && !ses.Has("Email"))
  ses.NewNode("Email", ses.Param("Name") + "@host.com");
  • Password fields on integration forms with external systems (other panels: ip/dnsmanager, database servers, etc.) should have the password type. When displaying the form (the get request), the current value specified in the panel should be passed.

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 clipped word 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 "4/". The column with prop should display the total sum of the smallest object (for example, if we are talking about 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 "lamp" icon, it should stand first.
  • The maximum number of button groups - 8.
  • When describing a column containing a status, a text color must be specified.
    • red - error
    • yellow - warning
    • green - no errors

     

Toolbar buttons

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

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

  • 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 database reserved words for tables and fields
  • 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 are 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 A table name should be written in singular on the left and right from 2
  • Fields
    • Do not use prefixes in fields' names (indicating a type, size, etc.).
    • Type boolean - StringField длины 3. Values on/off (for checkbox compatibility). Class_mgr_db::BoolField
    • Do not use autoincrement fields (due to issues with MySQL data replication). Use Class_mgr_db::AutoIncrement
    • A filed referring to another table should have the same name as the table being referred to (if there are many links, a table name should be used as a prefix)
    • A filed containing a unique identifier, should be named id Class_mgr_db::AutoIncrement
    • A filed containing a unique name of the record should be named name
    • A filed containing an object's status: active/suspended, should be named active with possible values on/off. Class_mgr_db::BoolField
    • A filed containing access levels, should be named level, be an integer, and have values according to Namespace_mgr_access
    • Fields with passwords should have the Class_mgr_db::CryptedField type, which helps improve security (including SQL injections).

SQLite

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

Menu modules are located in the following order:

  • Product's sections
  • System state
  • Integrations
  • Settings
  • Help. The "Help" module should stand 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 - 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">не ограничено</msg>
  • If 0 cannot be used as a resource limit, validators can be used (the minimum value - 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 his users that he is allowed by his provider. When allocating a resource to a user, both user and reseller's limits should be checked (you need to sum up resource consumption by all users of that reseller).
  • If the limit is not specified, forbid users to use the resource.

New features of COREmanager that you can use in control panels

  • Notification bar (notifications are now displayed in the upper left corner of the web interface).
  • Navigation from lists (nestedlist). You can specify what list and filter will open when clicking a certain element in the table.
  • Restart the web-interface after the menu has been changed.
  • "New" buttons on the Dashboard.
  • Hints for buttons that are displayed when a user logs in to the control panel for the first time. Hints are helpful to get acquitted with the control panel.

System boot

  • handlers for basic functions are created.
  • additional library .so / .dll is uploaded. The library should register all the required components during upload, add supplemental libraries if needed. If the process fails, all the components are automatically deleted from the system.

Process handling

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

  1. getting a request, reading and analyzing its parametersGET and POST data are processed. Internal data representation is generated for quick access
  2. user authentication (an attempt to define a name of the user who made a request, and his user role)
  3. search a function by name (a function name is taken from the func parameter; if the parameter is not present, it is considered desktop)
  4. user authentication
  5. session xml is created (lang, func, binary, host)
  6. global event handlers are called (associated with action "*") before="yes"
  7. event handlers for the before="yes" are called
  8. function event handler is called
  9. event handlers for the after="yes" function are called
  10. global event handlers are called (associated with action "*") after="yes"
  11. completing the transaction (recording files, deleting temporary data, calling commit for databases)
  12. generating a reply in a required format (the format is specified in the out request)

User authentication

At this step, the system is trying to define a name of the user who has made a request and his/her 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 is checked ( <panel name> + "5") COOKIE must contain the following fields colon separated: theme name, language abbreviation, session id.
  2. User authentication based on data received from the client (authenticate is called).
  3. IP authenticationIn this case, we already know the username (it is specified in the configuration file), but we still need to call authenticate to define additional parameters.
  4. Trusted access authenticationSimilar to the previous step, but the username is the name of a local administrator.

If all the attempts fail, the session will be assigned the access level 0.