# Business rules — ieb

Evidence date: 2026-10-13. Inspected revision: `main` at `193927fc`.

Rules below were read from code or config. They are not a signed business policy unless the provenance says **Documented**. Inferred rules are marked **Inferred**.

Secret values are omitted. Paths are relative to `Evolution Software Unified Framework/Evolution Software Unified Framework/`.

Tenant-specific exam moderation and Postbox folder rules that were traced in other repositories stay in `silicon_ark/ieb-inde-1` and `silicon_ark/ieb-inde-6`. This file records the rules this inspection actually read, including rules those snapshots do not yet contain.

## Identity and access

BR-001 — Framework user types are the five values in `pNums.UserType`: WebsiteUser 1, PowerUser 2, SuperUser 3, AdminUser 4, CustomUser 5. **Implemented.** `business/enums/pNums.cs`.

BR-002 — A normal sign-in succeeds only when a `pal_User` row matches the email, the encrypted form of the submitted password, and `isActive = 1`, and either the user's `customerCode` equals the current setup code or the user's `customerCode` is `EVOL-1`. The `EVOL-1` branch is commented "allow on all instances". **Implemented.** `core/Admin_SignIn.aspx.cs`.

BR-003 — One hardcoded email and password signs in an in-memory AdminUser for `EVOL-1` with `recId` -1 and `isSetup` true, without a database row. The same email literal is in `core`, `core-dev`, and every `core_custom/*/Admin_SignIn.aspx.cs` except PROP-1. **Implemented.** This is not in the readme. Human review is required. The secret is omitted.

BR-004 — After sign-in, a setup that is not a website goes to `/home`. A website setup goes to `Admin.aspx`. **Implemented.**

BR-005 — INDE-1 examination form and view: if the signed-in user type is below SuperUser and `examHandler.GetSubjectResourceRole` returns 0, the response redirects to `/pages/examinationauthoringandmoderation` and the request completes. SuperUser and above, including CustomUser, are not blocked by this comparison. **Implemented.** Commit `972cb4e`. Form rule also requires an existing item (`recId > 0`) and `isNew` false.

BR-006 — External moderator picklist options are active `pal_User` rows for the current setup `code`, displayed as `surname, name`. **Implemented.** Same form file.

BR-007 — Resource picklists include a "Select" item valued `0`. If the stored user id is not in the list, the control selects `0`. **Implemented.** `972cb4e`.

## Tenancy

BR-008 — Each tenant website is a `core_custom/{code}` site. The readme assigns product names only to INDE-1, INDE-2, INDE-4, INDE-5, INDE-6, INDE-8, and INDE-9. **Documented** for that list. INDE-8 and INDE-9 have no folder. **Implemented** absence.

BR-009 — The readme says INDE-4 Docs uses the INDE-2 user table, and INDE-9 uses the INDE-8 user table. **Documented.** No SQL in this inspection was read to prove the shared table. **Requires Confirmation.**

BR-010 — `customerCode` on the user is compared to setup `code` at sign-in (BR-002). Exam and moderator queries also filter `pal_User` by setup `code`. **Implemented** at the call sites that were read. A full authorisation matrix for canvases was not traced.

BR-011 — Where a `Web.config` contains two `website` keys, both are active entries. The later key is the one configuration APIs return. **Inferred** for the "last key wins" part. On INDE-2, INDE-4, INDE-5, and INDE-6 the later value is `IEB CRM`. The readme name for INDE-6 is Postbox. **Documented** versus **Implemented**. **Requires Confirmation.**

## Exam papers and subjects (INDE-1)

BR-012 — Lookup rows 4188 and 4189 are inserted as examination types "AET - June - Back-up" (`AETJ`, sequence 23) and "AET - November - Back-up" (`AETN`, sequence 24). **Implemented** in `core_custom/INDE-1/scripts/sql/insert_examination_type_lookups_backup_variants.sql`. Whether this script has been applied to `Framework_INDE-1` is **Unknown / Requires Confirmation**.

BR-013 — Duplicate `publ_ExaminationAuthoringandModeration` papers have a soft-delete script and a subject-name backfill script in the same `scripts/sql` folder (commit `bc7f1f2`). The predicates were not line-read. Applying them is an operational step, not something the website runs by itself. **Implemented** as scripts. Execution status **Unknown**.

BR-014 — A list script `list_duplicate_ExaminationAuthoringandModeration_papers.sql` is in the same folder. It was not executed.

BR-015 — Opening an examination surface ignores a session parcel that belongs to a different surface, and does not clear the active tab on postback. **Implemented.** `Canvas.aspx.cs` at `193927fc`.

BR-016 — Revision numbering was changed by one line in `bec948b`. The resulting sequence is **Unknown** beyond "a sequence fix was committed".

Unlink-moderator (`509c08f`), new-subject create (`7cdc9bc`), missing-info-on-open (`fd80a94`), long filenames (`bdc6799`), and the paper filter (`2997ebf`) are committed behaviour. The exact predicates were not extracted. They are features in `features.md`, not restated here as precise rules.

## Email queue

BR-017 — Postbox school-contact mail, IEB submissions mail, welcome mail, regional-moderator document mail, and regional-moderator report mail are inserted into the queue. They are not sent with `communication.SendAnEmail` on those paths. **Implemented.** `PostboxEmails.cs` at `38b1cbb`.

BR-018 — Queue priority for those Postbox calls is 5. Source module strings are `Postbox`, `WelcomeEmail`, `Postbox_RegModDocs`, and `Postbox_RegModReport`. **Implemented.**

BR-019 — A school-contact or submissions canvas with an empty recipient is skipped. **Implemented.**

BR-020 — Welcome queueing returns true even when `AddToQueue` returns `-1`. **Implemented.** The caller does not inspect the result.

BR-021 — Queue status values are Pending 0, Processing 1, Sent 2, Failed 3, Retry 4. **Implemented.** `xEmailQueue.EmailStatus`.

BR-022 — The processor selects only Pending rows, ordered by priority then `createdDate`. It does not select Retry, and it does not require `scheduledFor` to be due. **Implemented.**

BR-023 — On send failure the code increments `retryCount` in memory. If that count reaches `maxRetries` (default 3) it stores Failed. Otherwise it stores Retry and computes `scheduledFor = now + 2^retryCount` minutes. `UpdateStatus` then reloads the row and does not write `retryCount` or `scheduledFor`. **Implemented.**

BR-024 — **Inferred defect, requires confirmation.** Because BR-022 never loads Retry, and BR-023 does not persist the retry count, a failed message can remain Retry forever and will not be sent again by this processor. The status name implies a retry policy. The executable policy does not retry.

BR-025 — Default batch size is 20, the gap between batches is 5 seconds, and the gap after each send is 1 second. Sends inside one batch are started concurrently, so the 1 second delay does not order them. **Implemented.**

BR-026 — The Windows service is named `IEB Email Queue Processor` and defaults to every 2 minutes. **Implemented.** It is part of `INDE-6.sln` only.

BR-027 — No SQL script in the repository creates the queue table. Runtime saves use prefix `pal_`. **Inferred** table name `pal_EmailQueue` and log table `pal_EmailQueueLog`. **Requires Confirmation** that the tables exist in `Framework_INDE-6`.

## Mail, SMS, and clinical switches

BR-028 — SMTP send sets the process security protocol to TLS 1.2 or TLS 1.1 or TLS immediately before send. **Implemented.** `communication.cs`.

BR-029 — INDE-6 `DateFormat` is `yyyy-MM-dd hh:mm tt`. `defaultCulture` is `en-ZA` (the key is duplicated with the same value). **Implemented** in that `Web.config`.

BR-030 — INDE-6 Mediswitch app settings point at the QA gateway hosts. The live gateway `add` elements are inside a comment. **Implemented.**

BR-031 — INDE-6 `getCountriesFromWebService` is `0`. The country ASMX URLs are still in the file. **Implemented.**

BR-032 — SMS credentials are app settings `smsU` and `smsP`. Values omitted. SendEasy proxy classes exist under `business/Service References/send_easy`. Which business event still sends an SMS was not traced.

## Sales, purchases, tasks (framework enums)

These enums are the codes the framework will store if those modules run. They are not evidence that every tenant uses them. **Implemented** as `pNums`.

BR-033 — Sales status and purchases status share the same scale: Draft 1, AwaitingAcceptance 2, Accepted 3, Declined 4, Unpaid 5, PartiallyPaid 6, Paid 7, Overdue 8, Unallocated 9, Allocated 10, CapturedInXero 11. The enum names are spelled `SalesSatus` and `PurchasesSatus`.

BR-034 — Document types: Statement 1, Invoice 2, Quote 3, Receipt 4, CreditNote 5.

BR-035 — Task status: ToDo, InProgress, ToBeTested, ReleaseReady, Reopened, Closed, OnHold, InReview. Task priority: Blocker through Idea. Task type covers scoping of a new feature, a bug, or an enhancement.

BR-036 — Purchase-order status ids are in the 1536–1563 range (selecting products, placed, cancelled, received, confirmed, placed-and-paid, promotion expired, quote requested, quote submitted). Promotion status ids are 1540 Current, 1541 Expired, 1542 Draft. These look like surface lookup ids rather than a compact enum. **Inferred** from the numeric gap. **Requires Confirmation** that those lookup rows still exist.

BR-037 — Field validation types are Email, IdNumber, and ContactNumber. **Implemented** as `pNums.ValidationType`. The South African ID check itself was not re-read.

BR-038 — Inventory automation events named in the enum: quote accepted, stock pick picked, purchase order confirmed, goods receiving. **Implemented** as names only.

## Data prefixes

BR-039 — Framework configuration objects used by the sign-in and email queue are saved and loaded with table prefix `pal_`. **Implemented.**

BR-040 — Published examination rows referenced by the INDE-1 scripts use `publ_ExaminationAuthoringandModeration`. **Implemented** as script text.

## What was not promoted to a rule

- The full examination status email matrix. It lives in the other repository's documentation and was not re-read here.
- Google login. The web method exists; its acceptance rules were not read.
- PayGenius charges. Types exist; no charging rule was read.
- Per-tenant canvas security (`isRestricted`, surface permissions). Not traced. **Unknown / Requires Confirmation.**
