# Technical documentation — skrmiish

Evidence date: 2026-10-03. Source: `git@bitbucket.org:overdrive/skrmiish.git`, `master` `5077fba` (2020-12-09).

This repository is a front end. It does not contain the API, a database schema, or infrastructure-as-code beyond one pipeline file.

## Stack

| Item | Evidence |
|---|---|
| Language | JavaScript (no TypeScript config found) |
| UI | React `^16.14.0`, React DOM `^16.13.1` |
| Build | `react-scripts` `3.4.3` (Create React App). Not ejected |
| Routing | `react-router-dom` `^5.2.0`, `BrowserRouter` in `src/index.js` |
| State | `@reduxjs/toolkit` `^1.1.0`, `react-redux`, `redux-saga` `^1.1.3`, `redux-persist` `^6.0.0` |
| HTTP | `axios` `^0.20.0` |
| Styling | `styled-components` `^5.1.1`, `@material-ui/core` `^4.11.0`, some global CSS |
| Charts | `recharts` in `Streamer/.../LineChart.js` |
| Motion | `framer-motion` on drawer menus |
| Images | `react-image-crop` on the profile crop modal |
| DOM helper | `jquery` in the accounts main tab scroller |
| Package manager files | Both `package-lock.json` and a README that tells developers to use Yarn. The pipeline runs `npm ci` |
| Node image for CI | `node:12` in `bitbucket-pipelines.yml` |
| App version | `0.1.0`, `"private": true` |

`@azure/identity` `^1.1.0` and `@azure/storage-blob` `^12.2.1` are declared. No import of `@azure` was found under `src/`. `crypto-js`, `victory`, `react-swipe`, and `swipe-js-iso` are declared. No import of those four was found under `src/`.

## Application structure

```text
public/                 index.html, manifest, icons
src/index.js            React root, Redux provider, router, toast, service worker
src/App.js              Routes and axios 401 interceptor
src/app/store.js        Persisted store and saga middleware
src/app/rootReducer.js  Slice map
src/ProtectedRoute/     Partner gate
src/sagas/              API side effects
src/features/slices/    Redux slices
src/features/SPA/       Public home
src/features/Accounts/
src/features/Profile/
src/features/ManageLeaderboards/
src/features/Streamer/
src/features/Toast/
src/lib/CustomHooks/
bitbucket-pipelines.yml
package.json
```

`SPA`, `Accounts`, `Profile`, `ManageLeaderboards`, and `Streamer` each contain their own `Navigation` and `MainGrid` copies (left drawer, main, right drawer). Provenance: **Implemented**.

Lazy-loaded pieces on the home page: login modal, sign-up modal, streamer modal, supporter modal, mobile nav overlay (`React.lazy` in `SPA.js`). `App.js` wraps routes in `Suspense` with a null fallback.

## Routes

| Path | Component | Guard |
|---|---|---|
| `/` | `SPA` | None |
| `/accounts` | `Accounts` | Logged in and `role === "Partner"` |
| `/profile` | `Profile` | Same |
| `/manageLeaderboard` | `ManageLeaderboards` | Same |
| `/streamer` | `Streamer` | Same |

Unknown paths do not have a `Route`. React Router 5 renders nothing for them inside the `Switch`. Provenance: **Implemented**.

Scroll resets to the top on pathname change (`ScrollToTop` in `index.js`).

## State

`configureStore` plus `redux-persist`:

- Key `root`, storage `localStorage`, reconciler `autoMergeLevel2`, blacklist empty (everything is persisted).
- DevTools on when `NODE_ENV !== "production"`.
- Saga middleware runs `rootSaga`, which `spawn`s one watcher per API area.

Slices include `auth`, `twitchToken`, `toast`, `supporterModal`, `streamerModal`, `streamerData`, `streamers`, `registerModal`, `payoutModal`, `payoutDetails`, `loginModal`, `leaderboards`, `creditModal`, `clearUrl`, `alerts`.

`auth` shape: `{ loggedIn, user, isStreamer, twitchUserObj, role }`.

## API surface called by the client

Base host, repeated in each saga rather than a shared config: `https://skmsapi-dev.azurewebsites.net`.

No `.env` file is in the repository. `REACT_APP_` variables were not found. Provenance: **Implemented**.

| Call | Method and path | Saga |
|---|---|---|
| Email login | `POST /api/v1/User/login` | `NormalLogin.js` |
| Twitch login | `POST /api/v1/User/login` | `LogInWithTwitch.js` |
| Register (all three flows) | `POST /api/v2/User` | `NormalRegister.js`, `RegisterAsSupporter.js`, `RegisterAsStreamer.js` |
| Update user | `POST /api/v1/User/{uuid}/update` | `UpdateUser.js`, also after avatar upload |
| Alerts | `GET /api/v1/User/{uuid}/alerts` | `Alerts.js` |
| Newsletter subscribe | `GET /api/v1/User/{uuid}/newsletter_subscribe` | `Subscribe.js` |
| List streamers | `GET /api/v1/Streamer` | `Streamers.js`, `GetStreamerData.js`, and a double-slash variant in `Leaderboards.js` |
| Update links | `POST /api/v1/Streamer/{uuid}/update_links` | `UpdateLinks.js` |
| Update bio | `POST /api/v1/Streamer/{uuid}/update_bio` | `UpdateBio.js` |
| Payout details | `GET` and `POST /api/v1/Streamer/{uuid}/payout_details` | `GetPayoutDetails.js`, `UpdatePaymentDetails.js` |
| Request payout | `POST /api/v1/Streamer/{uuid}/request_payout` | `RequestPayout.js` |
| Request feature | `POST /api/v1/Streamer/{uuid}/request_feature` | `MissingSomething.js` |
| List leaderboards | `GET /api/v1/Leaderboard` | `Leaderboards.js`. Also used by unsubscribe and subscription-check sagas |
| Create leaderboard | `POST /api/v1/Leaderboard` | `CreateLeaderBoard.js` |
| Upload image | `POST /api/v1/Image` with `{ data64, extension }` | `CreateLeaderBoard.js`, `UpdateProfilePicture.js` |

Request bodies differ in casing between flows (`logintype` versus `loginType`, `is_streamer` versus `isStreamer`, `signup_type` versus `signupType`). Provenance: **Implemented**.

A static token string is hardcoded on login and registration bodies in the sagas. It is a secret in source control. The value is not copied into this document. Several of those bodies also set `token` twice, so the Twitch access token does not survive as the property value (`LogInWithTwitch.js`).

`UpdatePaymentDetails.js` does `const { uuid } = yield select((state) => state.auth.user.uuid)`. Selecting a string and then destructuring it does not yield the uuid. The accounts screen also dispatches `email` on the action rather than `payload`. Provenance: **Implemented**.

## External services

| Service | Where |
|---|---|
| Twitch OAuth implicit grant | `TwitchButton.js`. `redirect_uri` is `https://master.d373v11reppwb7.amplifyapp.com/`. `response_type=token`. `scope=user_read`. `state` is the literal `{some_guid}` |
| Twitch Helix | `GET https://api.twitch.tv/helix/users` with Bearer token and `Client-ID`. A second function calls `https://api.twitch.tv/helix/user` (singular) and is not on the hook path |
| Azure Blob | Public image URLs under `https://skmwebsitemain.blob.core.windows.net/assets/Images/` |
| Azure static website | Pipeline destination `https://skmwebsitemain.z6.web.core.windows.net/` |
| Zendesk | Snippet commented out in `public/index.html` |

Google Material Icons are loaded from `https://fonts.googleapis.com/icon?family=Material+Icons` in `index.html`.

## Authentication

There is no server session in this repo. The client:

1. Receives a user object from the API and stores it in Redux.
2. Persists that state to `localStorage`.
3. Treats `loggedIn` plus `role === "Partner"` as the page guard.
4. Sends a static token field on some writes, not a bearer token, on the calls that were read.

Twitch uses the implicit flow. The access token is taken from the URL hash (`hash.split("=")[1].split("&")[0]`), which assumes the first parameter is the token. Provenance: **Implemented**.

401 handling is described in the PRD (open a modal, do not clear auth).

## Deployment

`bitbucket-pipelines.yml`:

- Image `node:12`.
- Branch `master` only.
- Step name "Deploy to Azure", deployment environment `production`.
- `npm ci` then `npm build` then `microsoft/azure-storage-deploy:1.1.1`.
- `SOURCE: build`.
- `DESTINATION: https://skmwebsitemain.z6.web.core.windows.net/`.
- `DESTINATION_SAS_TOKEN: $SASTOKEN`.

`package.json` scripts are `start`, `build`, `test`, and `eject` under `react-scripts`. The pipeline command is `npm build`, while the script name is invoked in normal npm use as `npm run build`. Provenance: **Implemented** in the YAML. Whether that pipeline command succeeds on Node 12 is **Unknown / Requires Confirmation**.

No Dockerfile, no Terraform, and no second environment file were found.

Local development, per the README: `yarn start`, then `http://localhost:3000`. The pipeline uses npm. Which command the team actually used is **Unknown / Requires Confirmation**.

## Background work, queues, storage, monitoring

- No job runner, queue, or cron in this repository. Sagas are in-browser.
- Browser storage is `localStorage` via redux-persist. No IndexedDB usage was found.
- Service worker registration is turned on (`serviceWorker.register()`).
- No application monitoring SDK was found. Redux DevTools are enabled outside production.
- Sonar project files named at task-creation time are not in `master`.

## Security notes visible in the tree

These are observations, not a pentest.

- A static API token is committed in saga source and sent on login and registration.
- The Twitch client id is committed in the OAuth URL and the Helix headers. Implicit-grant client ids are visible in the browser by design. The redirect `state` is not a generated value.
- The user object is persisted in `localStorage`.
- `console.log` of registration responses remains in `NormalRegister.js` and `RegisterAsSupporter.js`. The tip commit message says console logs were removed; these calls are still present.
- `authSlice.js` contains a commented signup body with a personal-looking email and a sample token string. It is not on the live hook path. It should still be treated as committed sensitive material.
- No captcha, rate limit, or CSRF measure exists in this front end. The API might add them. That is **Unknown**.

## Testing and development process

- `npm test` / `yarn test` maps to `react-scripts test`.
- No test, spec, Cypress, or TestSprite files were found.
- No contributing guide, changelog, or CI test step was found. The only pipeline step is the Azure deploy.
- Browserslist is the Create React App default (production: `>0.2%`, not dead, not Opera Mini).

## Build and runtime entry

`public/index.html` sets the title, a viewport with `maximum-scale=1`, and the Material Icons stylesheet. `manifest.json` still says `"name": "Create React App Sample"` and `"short_name": "React App"`.

`src/index.js` renders into `#root` with `React.StrictMode`.
