# PRD — RGBC_ScoreCard (HR: People Development Tool)

Evidence date: 2026-10-05.

Source: `git@bitbucket.org:overdrive/rgbc_scorecard.git`, `master` at `c1c7ceb` (2026-08-04).

There is no separate requirements document in the repository. Requirements below were recovered from pages, SQL, and comments. Provenance is marked. A comment is not treated as the live rule when the code does something else.

## Product purpose

**Implemented.** The site title is **HR: People Development Tool**. Employees and managers complete structured reviews (a performance questionnaire tied to a job role, and a second questionnaire hardcoded as id `3`, labelled GPS on Home and Potential in the PDF). Submitting a review emails a PDF. HR is copied when a manager submits.

The repository and assembly are still named RGBC ScoreCard. What RGBC stands for is **Unknown / Requires Confirmation**.

## Users and roles

Login is Windows authentication plus a database user row. It is not ASP.NET Membership. See FR-001.

| Group (`mstUserGroupScoreCard.strUserGroup`) | What the code does | Provenance |
|---|---|---|
| `Admin` | Full menu. Home team grid is not filtered. Survey save is not locked by status | **Implemented** |
| `Dev` | Same menu and survey behaviour as Admin | **Implemented** |
| `RSM` | Menu reduced to Home and Logout. Home grid filtered to `scrUser.refManagerID` = the logged-in user. On an existing survey, Save is disabled when status is `Submitted` or the survey's `UserID` is not the logged-in user | **Implemented** |
| `User` | Same reduced menu. Home hides the team grid (`div1`) and `divReport`. Same survey Save lock as RSM. On questionnaire id `3`, Submit is disabled and **Send to Manager** is shown | **Implemented** |
| Anyone with `blnView` not true | Master page clears the content area and shows a view-rights message | **Implemented** |

`ScoreCard.aspx.vb` and `SalesCapabilities.aspx.vb` comment that user-group id `4` means RSM. That id is not defined in code. **Inferred. Requires confirmation.**

Peer reviewers (`refPeer1ID`, `refPeer2ID`, `refPeer3ID`) are commented out of team setup. A 2018 comment says the peer concept was removed. **Implemented** as removed from the save SQL. Whether the columns still exist in the database is **Unknown**.

## Main workflows

### Sign in

1. `Index.aspx` is the default document. It signs out Forms authentication, clears the session, and shows "session expired" when `?M=1`.
2. The user clicks Login. `LogginUser` reads `Request.LogonUserIdentity.Name`, upper-cases it, and looks up `mstUser.strDomainLogin` joined to `mstUserGroupScoreCard`.
3. On a match, session keys `USER`, `USERNAME`, `USERID`, and `USERGROUP` are set, a row is inserted into `mstUsageLog` with `strSystem = 'Forecast'`, and the browser goes to `Home.aspx`.
4. On no match, the page says access is controlled through Active Directory.
5. If `?OVERRIDE_USERNAME=` is present, that string replaces the Windows identity before the lookup.

`Admin.Master` sends a missing session to `Index.aspx?M=1` in a non-DEBUG build. In DEBUG it loads `SILICONOVERDRIV\pieter` (the domain string is missing the final E in OVERDRIVE).

### Self review from Home

During the configured season months (see BR-001), Home shows:

- A link to start a self performance review when `scrUser.refQuestionnaireID` is set: `PeopleBalanceSheetNew.aspx?UserID={self}&QuestionnaireID={job role}`.
- A link to start a self GPS review: `PeopleBalanceSheetNew.aspx?UserID={self}&QuestionnaireID=3`.
- If no job role is set, a message to ask HR. The GPS link is then also omitted.

Outside those months, the performance link is replaced by a message that names 1 April to 30 June. The GPS link is not set in that branch.

### Manager review from the team grid

Admin, Dev, and RSM see users who have a `scrUser` row and `refUserGroupSCoreCardID <> 0` (spelling as in the SQL). RSM sees only people whose `refManagerID` is themselves.

Each row shows the latest non-id-3 survey and the latest id-3 survey (`ROW_NUMBER` by `dtDate` then `SurveyID`). The performance cell adds ` - Self` or ` - Manager` from whether `UserID = RepID`.

If that latest review is inside the calendar-year season window, is not `Submitted`, and has a parseable date, the date becomes a link to `PeopleBalanceSheetNew.aspx?SurveyID=`. **New** links always start a new survey for that person.

### Complete a survey

1. Open `PeopleBalanceSheetNew.aspx` with `SurveyID` (edit) or `UserID` plus `QuestionnaireID` (new). Hidden fields keep those values across postback.
2. Questions load by category from `scrQuestion` (new) or `dwfScoreCard` (edit), active questions only on a new survey, ordered by `intOrder`.
3. Save requires an answer on every question. First save inserts `scrSurvey` with status `Draft` and the answer rows in one SQL transaction, then redirects to `?SurveyID=`. Later saves update answers, manager comments, and shared values.
4. Submit sets status `Submitted`, builds a PDF, emails it, and returns to Home with `surveyCheck=True`.
5. For questionnaire `3` and group `User`, Submit stays off. **Send to Manager** sets status `Ready For Review` and emails the manager using `sysQuery` id `62`. It does not attach the PDF.

### Maintain the question bank and team

Admin and Dev open Edit Questionnaires, Edit Surveys, Edit Team Setup, and Overall Performance. RSM and User do not see those menu items. The pages themselves do not repeat that check. A user who knows the URL still hits the master-page session and `blnView` check only.

## Integrations

| System | Direction | Trigger | Data | Auth | Failure |
|---|---|---|---|---|---|
| Active Directory / Windows identity | In | Login click and session rebuild | `DOMAIN\user` compared to `mstUser.strDomainLogin` | IIS Windows auth. How the site is bound in IIS is **Unknown** | Message "Insufficient Access" or the exception text |
| SQL Server | Read/write | Every page that queries | Users, surveys, questions, answers, email templates, logs | Environment connection strings. Database name **Unknown** | Exception text written to the page label on several screens; `WriteLog` on survey load/save/email |
| SMTP `10.0.0.17` | Out | Submit and Send to Manager | HTML body from `sysQuery` id 42 or 62, PDF attachment on submit | No credentials in the live `SmtpClient` constructor | Caught; logged to `stgSuperbowlLog`; submit still redirects Home |
| Local PDF folder `Reports/PDF` | Out | Submit, after render | `{employee}_{questionnaire}_{surveyId}_{yyyyMMdd}_PDT.pdf` | Process file permissions | Disk write failure is logged as a warning. The email can still attach the in-memory PDF |

Email addresses used in code:

- From: `administrator@rgbc.co.za`
- CC on submit when the logged-in user is not the employee (`RepID`): `hr@rgbc.co.za`
- To: manager email, and also the employee email when the questionnaire is not id `3`

Body text lives in the database (`sysQuery.memQuery`), not in git. The substitutions in code are `[ToName]` and `[SurveyID]` (submit) or `[ToName]` and `[UserID]` (alert; the value passed for `[UserID]` is the survey id).

## Constraints

- Answers are required for every question before save. Empty selection throws "Please select an answer for all questions before saving."
- Submit is refused in code when `SurveyID` is still 0: "Cannot submit — please Save the survey first."
- Send to Manager has the same guard.
- A new survey with no questions disables Save, Submit, and Alert and tells the user to ask HR.
- An edit whose questionnaire query returns no row disables those buttons and says the survey could not be loaded.
- `customErrors mode="Off"` and `trace` with `localOnly="false"` and `pageOutput="true"`. Errors and trace can be shown to the browser. **Implemented.** Whether that is intended in production is **Requires confirmation**.
- `requestValidationMode="2.0"`. Several pages set `ValidateRequest="false"` (help page). Input is passed through `db.CleanString` (quotes doubled) on the transactional insert path's comments are not all passed through `CleanString` on first insert of question text. See technical documentation. This is observed behaviour, not a security design statement.

## Functional requirements

### FR-001 — Sign in with a Windows identity

**Requirement.** A person already authenticated by Windows can open the tool only when `mstUser.strDomainLogin` matches that identity and the user has a ScoreCard group row.

**Who.** Any browser user who can reach the site.

**Trigger.** Login button on `Index.aspx`. Also `LogginUser` when Home or the survey page finds an empty session.

**Inputs.** `Request.LogonUserIdentity.Name`. Optional query `OVERRIDE_USERNAME`.

**Behaviour.** Upper-case the identity, `CleanString` it, select the user. Store the user row and ids in session. Insert `mstUsageLog` with system name `Forecast`. Redirect to Home. Otherwise show the Active Directory message and clear `Session("USER")`.

**Output.** Session established, or an error label.

**Validation.** No password check in this application. Membership settings in `Web.config` (length 6, 5 invalid attempts) are not used by `LogginUser`.

**Errors.** Exceptions are appended to the label, including stack trace.

**Evidence.** `Index.aspx.vb`, `SystemFunctions.LogginUser`, `Web.config`.

**Implementation.** Implemented.

**Confidence.** High.

**Conflict.** `OVERRIDE_USERNAME` lets the query string choose the domain login. **Requires confirmation** that this is still allowed. The usage-log system name `Forecast` does not match this product. **Inferred** leftover from another module.

### FR-002 — End a session from the menu

**Requirement.** Logout returns to `Index.aspx`, which clears the session.

**Who.** Any signed-in user. Menu text is `Logout:` plus the display name.

**Trigger.** Menu navigation.

**Behaviour.** `Index.aspx` `Page_Load` calls `FormsAuthentication.SignOut()` and `Session.Clear()`.

**Evidence.** `Admin.Master`, `Mobile.Master`, `Index.aspx.vb`.

**Implementation.** Implemented. Windows authentication can still present the same identity on the next Login click. The application does not log the user out of Windows.

**Confidence.** High.

### FR-003 — Show the home dashboard

**Requirement.** After login, show the person's name, last GPS date, last performance-review date, and start links. Managers see a team grid.

**Who.** Signed-in user. Grid visibility depends on group (see users table).

**Trigger.** `Home.aspx` load.

**Inputs.** `Session("USER")`. Optional `surveyCheck=True`.

**Behaviour.** Last GPS is `MAX(dtDate)` from `scrSurvey` where `QuestionnaireID = 3` and `RepID = UserID =` the person. Last self performance review is a grouped read of `scrSurvey` where `QuestionnaireID <> 3` and `RepID = UserID`. The SQL has no `MAX` in the select list; it groups by status and survey id. Which row returns is **not defined** in the SQL. **Requires confirmation** against the database.

**Output.** Labels and, for RSM, a grid parameter `refManagerID`. Admin and Dev leave the parameter at `-1` (all rows). User hides the grid.

**Evidence.** `Home.aspx.vb`, `Home.aspx` `sdsUser`.

**Implementation.** Implemented.

**Confidence.** High for the grid. Medium for the self-review date query, because of the missing aggregate.

### FR-004 — Limit new self reviews to a season

**Requirement (comment, 2019-05-20).** Users can start a PDT only from 1 April through 30 June.

**Implemented behaviour.** The gate compares `DateTime.Now.Month` with the month numbers in `My.Settings.dtSeasonStart` and `dtSeasonEnd`. Those settings are `01-01` and `12-31`. Every month passes. The refusal text still says 1 April to 30 June of the computed year.

**Evidence.** `Home.aspx.vb` lines around the 20190520 comment. `Web.config` settings `dtSeasonStart`, `dtSeasonEnd`.

**Implementation.** The April–June rule is **not** what the committed settings enforce. **Requires confirmation** of the intended window. See BR-001.

**Confidence.** High that the code and the comment disagree.

### FR-005 — Capture a PDT survey

**Requirement.** A reviewer answers every active question on a questionnaire, can save a draft, and can submit.

**Who.** The signed-in user. RSM and User cannot save when the loaded survey is `Submitted` or was created by someone else (`dwf`/`scrSurvey.UserID`). Admin and Dev are not locked that way. The "not in `vieSCRManager`" redirect to Home is commented out, so a survey id that fails the view check is still loaded for RSM and User.

**Trigger.** Home links or survey-list link. Save and Submit buttons.

**Inputs.** Query or hidden `SurveyID`, `QuestionnaireID`, `UserID` (the employee / `RepID`). Radio answer per question. Optional comment, GPS comment, manager comments, shared values.

**Behaviour.** See the workflow above. Status values written by this page: `Draft`, `Submitted`, `Ready For Review`.

**Outputs.** Rows in `scrSurvey` and `dwfScoreCard`. Redirect to the saved survey or to Home.

**Validation.** All radios selected. Survey context (questionnaire id and rep id) required on first save. Submit and alert require a survey id.

**Errors.** Message label plus `WriteLog` on save failure. Load failure message depends on whether a survey id was present.

**Evidence.** `PeopleBalanceSheetNew.aspx.vb`.

**Implementation.** Implemented, including the TASK-001 transactional first save and hidden-field context.

**Confidence.** High.

### FR-006 — Score the survey on screen

**Requirement.** Show a running total and a per-category average.

**Behaviour.**

- Maximum score is `question count * 3` when `strOptionType = 'Range3'`, otherwise `question count * 6`. The query groups by option type. A questionnaire with both types can return more than one row; `getRow` uses one of them. **Requires confirmation** of which row SQL Server returns.
- Displayed actual score is the sum of selected values over that maximum (`n/max`).
- Each category contributes `round(sum of answers / question count, 1)`.
- The header score (`strScore` / `lblSurveyTotal`) is the average of those category scores, rounded to 2 decimals. It is filled when categories are bound on an existing survey.

**Evidence.** `PeopleBalanceSheetNew.aspx.vb` `Page_Load`, `Category_ItemBound`, `reCategories_PreRender`.

**Implementation.** Implemented.

**Confidence.** Medium, because mixed option types and the `getRow` of a grouped query are ambiguous.

### FR-007 — Email a PDF when a survey is submitted

**Requirement.** Submit marks the survey submitted and emails a People Development Tool PDF.

**Who.** The signed-in user who can press Submit. Group `User` on questionnaire `3` cannot.

**Trigger.** Submit, after confirm dialog "Are you sure you want to submit the Survey to HR?"

**Behaviour.** Status `Submitted`. PDF from embedded report `RGBC_ScoreCard.PeopleBalanceSheetReport.rdlc`. Parameters include date, employee, region, manager, score, actual score, score label, manager comments. Score label is `Performance Score:` unless questionnaire id is `3`, then `Potential Score:`. File name `{lblUser}_{questionnaire name}_{surveyId}_{yyyyMMdd}_PDT`. Email as in Integrations. CC `hr@rgbc.co.za` when the logged-in user is not `RepID`.

**Errors.** PDF and SMTP failures are logged. The redirect to Home still runs after `sendEmail()` returns. A failed email does not roll back `Submitted`.

**Evidence.** `btnSubmit_Click`, `sendEmail`, `createPDF`.

**Implementation.** Implemented.

**Confidence.** High.

### FR-008 — Notify the manager on a GPS self review

**Requirement.** A user on questionnaire `3` can alert their manager instead of submitting to HR.

**Trigger.** **Send to Manager**, confirm "Are you sure you want to Alert your Manager".

**Behaviour.** Status `Ready For Review`. Email body from `sysQuery` id `62`. To the manager only. No PDF. No HR copy. Then Home.

**Evidence.** `btnAlert_Click`. Comment dated 2021-11-11.

**Implementation.** Implemented for group `User` and questionnaire `3` (button enabled). Other groups keep the button hidden or disabled from the new-survey branch (`btnAlert.Visible = False` when not that case). On edit of questionnaire `3` by a User, the button is shown and enabled.

**Confidence.** High.

### FR-009 — Maintain questionnaires and questions

**Requirement.** An administrator can filter questions and add or edit them.

**Who.** Menu is Admin and Dev only. The page does not check the group.

**Inputs.** Questionnaire, question text, category, category description, option type, order, comment flag, active flag.

**Behaviour.** Insert or update `scrQuestion`. Then set `strCategoryDescription` on every question with the same `strCategory` (not limited to the questionnaire). Option dropdown offers only `Range6`. Last user is the session display name.

**Validation.** Required-field validator on option type. Order is `Convert.ToInt32` with no range check in code.

**Evidence.** `Questionnaire.aspx.vb`, `QuestionEdit.aspx`, `QuestionEdit.aspx.vb`.

**Implementation.** Implemented.

**Confidence.** High.

**Note.** Commit `857df91` says range 3 and 10 were removed. The editor matches that for new questions. Existing `Range3` rows can still be displayed by the survey page.

### FR-010 — Assign a job role and a manager

**Requirement.** HR links a user to one questionnaire (job role) and one manager.

**Who.** Menu Admin and Dev.

**Behaviour.** Edit loads `scrUser`. Save updates or inserts `UserID`, `refQuestionnaireID`, `refManagerID`, `strLastUser`. New-user dropdown lists `mstUser` rows that are not yet in `scrUser`. Job-role lists exclude the questionnaire named `Potential`. Team list shows `WARNING! Job Role / Questionnaire not set up` when the role has zero questions. Export writes an HTML table as `.xls`.

**Evidence.** `TeamSetup.aspx.vb`, `TeamSetupEdit.aspx.vb`, team SQL in `TeamSetup.aspx`.

**Implementation.** Implemented. Peer fields are commented out.

**Confidence.** High.

### FR-011 — Search past surveys

**Requirement.** Filter surveys by questionnaire, salesperson (`RepID`), reviewer (`UserID`), and date range. Default dates are the first of the current month through today. Ignore-dates checkbox skips the range. Grid links to `PeopleBalanceSheetNew.aspx?SurveyID=`.

**Score column.** `SUM(intAnswer) * 100 / (count * 6 when option type is Range6, else count * 3)`, shown with a percent sign.

**Evidence.** `Survey.aspx`, `Survey.aspx.vb`.

**Implementation.** Implemented. Menu Admin and Dev.

**Confidence.** High.

### FR-012 — Show overall performance for three April-based years

**Requirement.** A grid of potential and performance scores for the current year, last year, and the year before, with filters and an Excel export.

**Behaviour.** Potential rows are `QuestionnaireID = 3`. Performance rows are `QuestionnaireID <> 3`. Each year window is 1 April through the next 1 April, using `GETDATE()`. Category average is `SUM(intAnswer) / COUNT(questions)`, then those category scores are summed and divided by 6. Missing data displays `N/A`.

**Evidence.** `OverallPerformance.aspx`.

**Implementation.** Implemented for Admin and Dev menu. The data source connection is `SuperbowlConnectionStringDEV`, not the connection used by Home. **Requires confirmation** that this report is supposed to use the DEV database.

**Confidence.** High on the SQL. The business meaning of dividing by 6 is **Inferred** (six categories). It is not read from the questionnaire.

### FR-013 — Show rating help

**Requirement.** Home and the survey page link to `HelpPeopleBalanceSheet.aspx` in a new window.

**Behaviour.** `PerformanceDefinitions.jpg` and `PotentialDefinitions2.jpg` are rendered. `PotentialDefinitions.jpg` and `PerformancePotentialGrid.jpg` are commented out. The code that would hide images for group `User` is commented out, so every group sees the same images.

**Evidence.** `Home.aspx`, `PeopleBalanceSheetNew.aspx`, `HelpPeopleBalanceSheet.aspx`.

**Implementation.** Implemented as a static image page.

**Confidence.** High.

### FR-014 — Use a mobile master page on a phone browser

**Requirement.** A mobile user-agent loads `Mobile.Master` instead of `Admin.Master`.

**Behaviour.** `setMasterPage` matches a long user-agent pattern or `Request.Browser.IsMobileDevice`. `Mobile.Master` has the same menu items as `Admin.Master`, and the same group hiding in `ApplyMenuForUserGroup`. `Mobile/Default.aspx` does not redirect (the redirect is commented out). `51Degrees.mobi.config` is present. Whether 51Degrees changes routing was not found in page code.

**Evidence.** `SystemFunctions.setMasterPage`, `Mobile.Master`, `Mobile/Default.aspx.cs`.

**Implementation.** Implemented as a master-page switch. A separate mobile workflow was not found.

**Confidence.** Medium.

## Removed or leftover behaviour

| Item | Status |
|---|---|
| New Score Card and New Sales Capabilities menu items | Commented out in `Admin.Master` since the 2017 People Balance Sheet note |
| Peer reviewers on team setup | Commented out. 2018 comment says removed |
| `PeopleBalanceSheet.aspx`, `zPeopleBalanceSheet.aspx`, `sandbox.aspx` | Present. Not linked from the current menu |
| HR Report (wip) | Menu text only. No URL |
| Brand QF jobs, promo log, fiscal helpers | Defined, no caller in pages |
| Hardcoded login `RGBC\MAANIE` | Removed in `60534ed` |

## Non-requirements (not evidenced)

Hosting URL, production server name, database name, who may use `OVERRIDE_USERNAME`, and whether the April–June window should be restored are **Unknown / Requires Confirmation**.
