Setting Up the Rule Repository
This page is for the developer who adds the Rule Repository to an application. It explains, in plain terms, what has to be in place before your users can work with rules, in what order to do it, and what each setting decides. The code itself is in the developer reference, linked from each step.
For the full technical reference, with code for every step, see the Implementation Guide's Rule Repository section and its Implementation Checklist.
The Rule Repository is made of a few parts that work together:
- The repository's server library (
CodeEffects.Rule.Repository). It answers every request the repository's screen sends, keeps all records, checks what each user may do, and writes the activity log. It works with any .NET application that can use .NET Standard 2.0 libraries.
- A database connection library (
CodeEffects.Rule.Connection, with CodeEffects.Rule.Connection.SqlServer for SQL Server or CodeEffects.Rule.Connection.Postgres for PostgreSQL). It is how the repository and Audit reach the database.
- The database. Your own SQL Server 2012 (or later) or PostgreSQL 14 (or later) database. Nothing is stored anywhere else, and nothing is hosted by Code Effects.
- The screen (the
@codeeffects/repository and @codeeffects/editor packages for the browser). It draws the grids, dialogs and rule editors on your page and sends every request to your server.
- One address on your server that receives the screen's requests and hands them to the server library.
- Your source objects, brought into the repository by your application. Users write rules against them.
Step 1: Create the Database
- Download the database scripts for your database type (SQL Server or PostgreSQL) from the Code Effects portal. They come as a zip archive.
- Run the scripts in the order of their numbers. The first one,
00001.Database.sql, creates every table. Each later script is a numbered update, such as 00002.Name.sql, and is run once, in order, when a new release needs it.
- Give your application write access to this database, and nobody else. The database also holds the key that signs the repository's security tokens, so whoever can change the database could change that key.
The libraries never change the database themselves. Each script records its number in the database, and each library knows which number it needs. Call Context.CheckDatabase(..) once when your application starts: it tells you the database's current version, the version the library needs and, when the database is behind, which scripts to run. Your application decides what to do with the answer, for example stop with a clear message or log a warning and continue.
See Context and SchemaCheckResult.
Step 2: Connect to the Database
Create one database provider for your database: the DbProvider class of the SQL Server or the PostgreSQL connection library, with your connection string and, optionally, the database schema to use (dbo and public by default). Pass the same provider to every call your application makes to the repository and to Audit.
See IDbProvider.
Step 3: Bring In Your Source Objects
Users can only write rules against source objects your application has synchronized into the repository. Call Context.SyncSources(..) with your source objects, at startup, from an administration screen, on a schedule or as part of a deployment. See Synchronizing Sources.
Step 4: Add the Repository to a Page
- Add the files of both browser packages to your application: the scripts
codeeffects.editor.js and codeeffects.repository.js, and the stylesheets of each (the common file and either the light or the dark theme). The repository needs the editor's files because every rule it shows is a Rule Editor.
- On the page, place one empty element where the repository should appear.
- When the page loads, call
$repo.init(..) with that element's ID and a function that sends each of the repository's requests to your server's address (Step 5) and hands the answer back.
The repository draws everything else itself. You can also set which grid opens first, the editor's display options, and how messages are shown. See codeeffects.repository.js and CSS Styles.
Step 5: Answer the Repository's Requests
Add one address to your server that receives the repository's requests. For each request:
- Build a configuration for the signed-in user (Steps 6 and 7).
- Pass the configuration, your database provider and the request to
Context.GetResponse(..).
- Send its answer back to the page.
When something fails, the library throws a RepositoryException. Log it with your own error handling and send back its ResponseJson, which holds a general message and a control number, never the details of the failure. A request refused for lack of permission throws RepositoryPermissionException, which you may want to log as a warning.
Protect this address as you protect the rest of your application:
- Require your application's sign-in. The repository has no sign-in of its own. Without yours, anyone who can reach the address can read and change rules.
- Accept only JSON requests, and limit their size. The repository refuses requests over 3 MB itself; your server should refuse much larger ones before they reach it.
- Do not allow other web sites to call it with the user's sign-in (no permissive cross-origin settings).
- Show the repository's messages as text, never as markup, if you show them yourself. They can contain names and descriptions that users typed.
The repository adds its own protection on top: every request carries a security token tied to the signed-in user, and the screen gets it automatically.
See Context, RepositoryException and RepositoryPermissionException.
Step 6: Tell the Repository Who the User Is
The repository has no list of users of its own. It records the user your application names on every change, and shows that user's name in the grids and the activity log.
- The user's ID (
CurrentUserId) is required on every request. Always take it from your application's sign-in, never from anything the browser sends. An ID the repository has never seen is simply a new user, so a mistake here creates a user rather than an error.
- The user's name (
CurrentUserName) is what everyone sees. When it changes in your application, it changes in the repository on that user's next visit. A user without a name is shown as "- no name -". The ID itself is never shown.
- The user's type (
CurrentUserType): a person (the default), an AI agent acting on its own, or a service. Only a person can make versions live, take them offline, approve, decline or delete. Whatever an agent or a service saves always waits for a person's approval.
- An AI agent acting for a person (
CurrentAgentId and CurrentAgentName). Every change made through the agent then records both the person and the agent.
See Configuration.
Step 7: Decide What Each User May Do
Your application gives the repository a set of permissions with every request. The repository has no roles; you map your own roles to permissions.
- The access mode decides how the list is read: view only (the default) lets the user see the source objects, source versions, rules and rule versions and nothing else; all except allows everything but the permissions you list; only these allows exactly the permissions you list.
- The permission list names what is allowed or denied: 40 permissions, grouped by object, such as creating rules, making versions live, approving, running tests, seeing evaluations, or using the AI features.
- Some permissions need others. Updating a draft, for example, needs the permission to see drafts. With all except, a denied permission also denies everything that needs it. With only these, the list must be complete, or every request fails.
Context.ValidatePermissions(..) lists what is missing, so you can check your role mappings in your own tests.
The screen disables what the user is not allowed to do, and the server refuses it as well. See Permissions for what users see, and Configuration for the members.
Step 8: Choose the Optional Settings
All of these are set on the configuration you build for each request. Leave any of them out to keep the default.
| Setting |
What it decides |
Notify |
A function the repository calls after an approval is requested, granted or declined, and after a rule version or a source version is made live or taken offline. Use it to send emails or messages to the right people. |
UiXml or UiXmlFile |
A translation of the repository's screen text. Context.GetDefaultUiXml() gives you the English original to translate. |
Limits |
Request limits: the largest request (3 MB), the largest single value (1 MB), the most filters (50), the most options in a list (1,000) and the most test runs at once (8). |
Agents |
What AI agents may do beyond their permissions: how many tests they may run per request, per hour and at once, whether their test runs are recorded in the activity log, and whether they may read the items of your data sources. |
Assistant |
The language models that power the AI Assistant and the AI Rule Editor. Without at least one model, the AI features do not appear. Here you also set the most steps per answer, whether users may attach files, and how long conversations are kept (90 days by default). |
TypeResolver |
A function that finds a type named in a stored source object when your application cannot find it on its own. Most applications do not need it. |
See Configuration, NotificationDelegate, RequestLimits, AgentSettings and AssistantSettings.
Step 9: Load the Live Rules for Evaluation
When your application evaluates rules, it loads the live versions of the rules it needs from the repository, together with every rule they use:
- Without Audit, call
Context.GetRules(..) with a query that names the rules, or a source object and a rule type.
- With Audit, load them through Audit instead, so each evaluation is recorded against the exact versions that ran. See Setting Up Audit.
Only live versions are ever loaded. To run a different version, make it live in the repository. See Rule Storage in Rule Repository.