# Business rules — react-php-tutorial

Evidence date: 2026-10-05. Revision: `master` `d10301a`.

No business-rules document exists in the source repository. Every rule below is **Inferred** from implementation unless the line says otherwise. Comments are quoted as author notes, not as confirmed policy.

No rule here was found as a **Documented** requirement.

## Who may act

**BR-001 — The routed screens do not ask who the person is.**  
`App.js` renders Sign In and Sign Up for any visitor who can open the bundle. **Inferred.**

**BR-002 — List and delete do not check a session, a role, or a token.**  
`listView.php` returns every mapped user row. `delete.php` deletes by the `id` query parameter. The session block in `signIn.php` is commented out, so even a successful login does not establish a server-side identity. **Inferred.**

**BR-003 — A user group is not enforced.**  
The only mention is a commented assignment of `$row['refUserGroupID']` to `$_SESSION['userGroup']`. **Inferred** that no group rule is active. Whether the column exists is **Unknown**.

## Account identity

**BR-004 — A person is a row in `user`, addressed by `username` in the login and sign-up scripts and by `id` in the delete script.**  
Columns the scripts actually read or write: `id`, `username`, `email`, `password`, `date_created`, `last_loggedin`. **Inferred** from SQL. There is no `CREATE TABLE` in git, so nullability, types, and unique indexes are **Unknown / Requires Confirmation**.

**BR-005 — Username or email is enough to block a second sign-up.**  
`signUp.php` selects `WHERE email = '$email' OR username ='$name'`. If `mysqli_num_rows` is greater than 0 it echoes `1` and does not insert. The check does not require both to match. **Inferred.**

**BR-006 — The duplicate response and the login response use `1` for opposite outcomes.**  
Sign-up echoes `1` when the person already exists. Sign-in echoes `1` when the password matches and `0` when it does not. **Inferred** from the two echo sites. The React code does not branch on either value.

**BR-007 — Sign-up does not require the password property to be present before it trims it.**  
The `isset` guard is `user_name` and `user_email` only. **Inferred.**

**BR-008 — The sign-up page treats only email and password as required. Name may be empty.**  
`SignUp.js` returns early when `email === ""` or `password === ""`. It does not test `name`. **Inferred.**

**BR-009 — The Add User modal treats name, email, and password as required in the browser.**  
Each `Form.Control` has the HTML `required` attribute. This is a different rule from BR-008, and the modal is not on a route. **Inferred.**

**BR-010 — Sign-in on the page treats name and password as required, and does not collect an email.**  
Empty string blocks the POST. **Inferred.**

**BR-011 — The server signs a person in only when both `user_name` and `user_password` are set and both match a stored row.**  
Comparison is `username = '$username' AND password='$password'` with the submitted characters. No hash, no expiry, no lockout count. **Inferred.**

**BR-012 — The Sign In form does not submit those property names.**  
The posted JSON is `JSON.stringify({ name, password })`. Combined with BR-011, that form does not reach the match query. **Inferred.**

**BR-013 — Password is stored as the trimmed request string.**  
`signUp.php` puts `user_password` into the `password` column through `Insertdata`. **Inferred.**

**BR-014 — After a failed password match, "user not found" and "wrong password" are different log strings.**  
If a later `SELECT` by username alone yields a row, the log text is `Login failed : Incorrect password`. Otherwise it is `Login failed : User not found`. Both paths echo `0` to the client. **Inferred.**

## Stamps and logs

**BR-015 — A successful password match sets `last_loggedin` to `NOW()` for every `user` row with that username.**  
`updateDate` runs `UPDATE user SET last_loggedin = NOW() WHERE username= '$name'`. It does not limit to one row. **Inferred.**

**BR-016 — A successful insert then sets `date_created` to `NOW()` the same way, after the INSERT rather than inside it.**  
`signUp.php` calls `updateDate("date_created", $name)` only when `Insertdata` is truthy. The INSERT column list is `email`, `username`, `password` only. **Inferred.**

**BR-017 — Every evaluated sign-in attempt is written to `tblloginuser`.**  
Fields passed: `strResult`, `strUsername`. Result text is one of `Login successful`, `Login failed : Incorrect password`, or `Login failed : User not found`. **Inferred.** The table definition is **Unknown**.

**BR-018 — `loguser` is a separate change log and is not written by the current endpoints.**  
`SaveLog` would store `refUser_id`, `log_key`, JSON `log_oldData`, JSON `log_newData`, and `timestamp` `NOW()`, using `$_SESSION['id']` as the actor. Nothing calls `SaveLog`. **Inferred.**

## Delete and edit

**BR-019 — Delete removes at most one row, matched only by `id`.**  
`DELETE FROM user WHERE id ='$id' LIMIT 1`. No "must be the signed-in user" rule. A missing `id` is still interpolated. **Inferred.**

**BR-020 — The delete script reports success when `mysqli_query` is truthy, including the author's message "User deleted."**  
Failure message is "Something wrong appened, please try again." **Inferred.** The SQL string is echoed before that JSON, so a client that parses the whole body as JSON will fail. **Inferred.**

**BR-021 — Edit does not change the database.**  
`EditUserModal` does not send a request. `update.php` has no code. **Inferred.**

**BR-022 — The unused update helper would change username and email, looked up by the old username, and would not change the password.**  
`updatetUser($username, $email, $oldusername)`. Author comment in the function: "this must be changed !!!". **Inferred** that this is not an active rule.

## Validation the screens do not share

**BR-023 — Server sign-up trims name, email, and password. The React forms do not trim.**  
**Inferred.**

**BR-024 — Email format is constrained only where the input type is `email`.**  
`SignUp.js` uses `type="email"`. `AddUserModal` uses react-bootstrap `type="email"`. `signUp.php` does not check email shape. **Inferred.**

**BR-025 — No maximum length, password policy, or allowed-character rule appears in PHP or in the components.**  
**Inferred.**

**BR-026 — Client error text is stored and not shown.**  
Both forms set `error` to `Fields are required` and never render it. **Inferred.**

## Data returned to the browser

**BR-027 — The list payload omits `password` even though the SELECT is `SELECT *`.**  
Only `id`, `username`, `email`, and `date_created` are copied into the JSON array. **Inferred.**

**BR-028 — Sign-in and sign-up responses are not a stable JSON contract.**  
Sign-in ends with `1` or `0` after `Insertdata` has printed the SQL. Sign-up always `var_dump`s the body first, then `1` for a duplicate or `0` plus a success object for an insert. **Inferred.**

**BR-029 — Debug output includes the SQL text.**  
`Insertdata` calls `print_r($sql)`. `delete.php` echoes the DELETE statement. `SelectData` echoes its SELECT and is unused by the endpoints. **Inferred.**

## Boundaries that are not rules in code

- No unique index is declared in this repository. BR-005 is an application check only. A concurrent second insert is **Unknown**.
- No retention rule for `tblloginuser` or `loguser`.
- No "tutorial only" or "do not deploy" statement. The localhost URL and the `root` account with an empty password are what the files contain, not a written environment policy.
