# Technical documentation — VivaInnovations (Vivlia)

Evidence date: 2026-09-29.

Inspected: `dev` at `71b4967` (application) and `master` at `37b1a24` (HEAD). Credential values and key material are omitted.

## Repository layout on `dev`

329 tracked files.

```text
VivaInnovations (git root on dev)
  README.md, CONTRIBUTING.md, CHANGELOG.md, RDSA.md, _README_old.md
  package.json, yarn.lock, tsconfig.json, tsconfig.base.json
  codegen.yml, .graphqlconfig.yml, config-overrides.js
  bitbucket-pipelines.yml, sonar-project.properties, deploy.sh, bugsnag-build.js
  .nvmrc                    contents: lts/*
  public/
  src/                      React application
  amplify/                  Amplify backend and team-provider-info.json
```

`src/` areas:

| Path | Role |
|---|---|
| `src/index.tsx` | `Amplify.configure(awsExports)` |
| `src/apollo.ts` | AppSync client, IAM credentials |
| `src/navigation/routes.ts` | Public, learner, and admin routes. Most screens are `React.lazy` |
| `src/containers/` | Screens listed in `features.md` |
| `src/components/` | Shared UI, including Ant Design wrappers |
| `src/contexts/` | Auth, network status, application providers |
| `src/hooks/` | `useAuthentication`, `useLocalStorage`, `useNetworkStatus` |
| `src/utils/` | Auth helpers, JWT role, filesystem, epub convert |
| `src/constants/index.ts` | Endpoints, Peach settings, chart seed, payment brands |
| `src/generated/` | GraphQL codegen output (large `graphql.tsx`) |
| `src/aws-exports.js` | Amplify outputs consumed by the client (present; values not copied here) |

`master` layout is `.gitignore` only.

`develop` layout adds `lerna.json` and `packages/{backend,everblue-ui,theme,web}` and does not match the root `src/` app.

## Languages and frameworks

| Item | Version on `dev` |
|---|---|
| Language | TypeScript 3.5 (`typescript` ^3.5.1). Lambdas are JavaScript CommonJS. |
| UI | React 16.8, `react-dom` 16.8, Ant Design 3, styled-components 4, styled-system 4 |
| App shell | `react-scripts` 3 via `react-app-rewired` and `customize-cra` |
| Data | Apollo Client 2, `aws-appsync` 3, `aws-amplify` 3, GraphQL 14 |
| Forms | Formik 1 |
| Tables | `react-table` 6.10.0 (README says the version is pinned) |
| Charts | bizcharts 3 |
| PDF | `react-pdf`, `@react-pdf/renderer`, Kendo React PDF, `pdfjs-dist` 2.6 |
| EPUB | `react-reader` |
| Animation | react-spring 8, react-lottie |
| Package manager | Yarn. Lockfile `yarn.lock`. |
| Node | README: >= 10. `.nvmrc`: `lts/*`. Pipeline does not pin a Node version beyond the custom image. |

`config-overrides.js` is the CRA escape hatch (Less, `babel-plugin-import`). `yarn start` and `yarn build` run `yarn generate` first (`graphql-codegen`).

## Auth

Cognito user pool and identity pool, resource name `vivliaa1cb2768`.

- Email username, email verification, MFA off, password length 8, refresh token validity 30 days.
- Hosted UI off. Third-party auth off. User-pool groups are not declared in `userPoolGroupList` (the list is empty). The post-confirmation function creates group `CONSUMER` at runtime.
- Identity pool allows unauthenticated identities.
- Post-confirmation trigger module: `add-to-group`.
- Front-end GraphQL auth mode: `AWS_IAM` with `Auth.currentCredentials()` (`src/apollo.ts`).
- AppSync `backend-config.json`: `defaultAuthentication.authenticationType` is `AWS_IAM`. `additionalAuthenticationProviders` is empty.
- `schema.graphql` has no `@auth` rules.

Role gating in the SPA is the first `cognito:groups` entry on the access token stored in `localStorage`. See business rule BR-006.

## Data

AppSync API name `vivlia`. Models (`@model`, DynamoDB via Amplify):

| Model | Notes |
|---|---|
| `User` | Profile, role, status, cart and transaction connections |
| `UserCartConn` | User, resource, optional voucher |
| `Resource` | Also `@searchable` |
| `Voucher` | Code, uses, expiry, price, subject flag |
| `ResourceVoucherConn` | Voucher to resource |
| `Transaction` | Peach reference, status, cost, user, voucher |
| `TransactionResourceConn` | Transaction to resource |
| `Unit` | Learning-material unit, connected to a `Resource` topic |
| `Faq` | Question, answer, status |
| `Annotation` | userID and resourceID are strings, not `@connection` |

Connections use Amplify `@connection`, the older directive name.

Enums are listed in `schema.graphql` and summarised in `business-rules.md`.

## Lambdas and HTTP APIs

| Function | Trigger | Behaviour of `src/index.js` |
|---|---|---|
| `vivliaa1cb2768PostConfirmation` | Cognito PostConfirmation | Loads modules from env `MODULES`. Shipped module `add-to-group.js` adds group `CONSUMER`. |
| `createUser` | API Gateway `createAdminUser`, path `/create-user`, auth role only | `adminCreateUser` then `adminAddUserToGroup`. Region hardcoded `eu-west-1`. |
| `disableUserAccount` | API Gateway `disableUserAccount` | `adminDisableUser`. Region hardcoded `eu-west-1`. |
| `makePayment` | API Gateway `makePeachPayment`, path `/make-payment`, auth role only | Decrypts the body. `makePayment` posts a Peach debit. `checkPayStatus` GETs Peach. |
| `sendEmail` | API Gateway `sendEmailApi`, path `/send-email` | SES `sendEmail`. The committed `api-params.json` sets the path `open: true` with auth and unauth both 0. |

`app.js` beside `createUser`, `disableUserAccount`, and `makePayment` is the Amplify Express sample (echo JSON). It is not the exported handler.

API Gateway auth stack file: `amplify/backend/api/APIGatewayAuthStack.json`.

CORS on the lambda responses inspected is `Access-Control-Allow-Origin: *`.

## Storage and hosting

- S3 bucket resource `vivliaResources` (`amplify/backend/storage/vivliaResources`).
- Hosting category `S3AndCloudFront`.
- `deploy.sh` publishes with `amplify publish -c`. A CloudFront invalidation command at the bottom of that script is commented.
- `src/containers/MyLibrary/signedUrls.js` constructs an AWS SDK client with `REACT_APP_AWS_ACCESS_KEY_ID`, `REACT_APP_AWS_SECRET_ACCESS_KEY`, and `REACT_APP_REGION`. Those variables are also written into `.env` by the pipeline and are documented in the README. Shipping long-lived IAM keys to the browser bundle is what this code does. **Requires Confirmation** that those keys are removed from the README, the pipeline, and any deployed bundle.

## Payments

`src/constants/index.ts` holds `PEACH_HOST`, `PEACH_ENTITY_ID`, `PEACH_HEADER_AUTH`, and `PEACH_ENCRYPT_KEY` (a public key). The matching private key is hardcoded in `amplify/backend/function/makePayment/src/index.js`.

The browser collects PAN, holder, expiry, and CVV, encrypts a JSON body, and the lambda decrypts it and forwards the card fields to Peach.

This document does not reproduce the key. **Requires Confirmation:** rotate the key, remove it from git history, and confirm whether card data is still allowed to touch this lambda. The lambda trusts `totalCost`, `peachUrl`, and `headerAuth` from the decrypted body.

## Email, analytics, monitoring

- SES, not Mailgun, in `sendEmail`. README still lists Mailgun under Services, owner `yatin@sov.tech`.
- Bugsnag packages are dependencies. `BUGSNAG_API_KEY` in `constants/index.ts` is the literal string `process.env.REACT_APP_BUGSNAG_API_KEY`, not the environment value. **Inferred** defect.
- Google Analytics via `react-ga` and `navigation/GoogleAnalytics.tsx`. README records a UA tracking id. The id is omitted here.
- CloudWatch is the documented log store for lambdas. No custom metrics code was reviewed.
- `bugsnag-build.js` is a source-map upload script. Whether the pipeline calls it: it is not in the pipeline script block that was read.

## Deployment

`bitbucket-pipelines.yml`:

- Image `sovtech/bitbucket-pipelines-node-aws:latest`.
- Build step size 2x. Installs Amplify CLI `5.2.0` and `graphql-codegen` CLI `1.7.0`.
- Runs `sh deploy.sh`.
- `yarn test:ci --coverage` is commented out.
- Semantic-release is commented out.
- Sonar step uses `sonarsource/sonar-scanner-cli:4.5` and `sonar-scanner`.
- `sonar.projectKey=VIVLIA`, `sonar.projectName=vivlia`, description "Monorepo for Vivlia Platform". The `dev` tree is not a monorepo. That description matches the older `develop` layout better than `dev`.

`deploy.sh` writes AWS credentials from `REACT_APP_AWS_ACCESS_KEY_ID` / `SECRET` into the Amplify provider config, and from `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` into `/root/.aws/credentials`. Region `eu-west-1`. Amplify environment name is `$STAGE`.

Bitbucket deployment environment names in the YAML: `test`, `staging`, `production`. These are not the same strings as the Amplify env names `dev`, `uat`, `staging`.

## Local development (documented)

README: clone `git@bitbucket.org:sovtech/vivlia.git`, `yarn`, copy `.env.example`, export it, `yarn start` at `http://localhost:3000`. No `.env.example` was in the `dev` root listing. **Discrepancy.** `amplify init` is documented for a personal environment. Existing Amplify env names in the README are dev, uat, and prod. The file has dev, uat, and staging.

`yarn test` uses `react-app-rewired test`. Twelve component tests live under `src/components/**/__tests__`. They cover layout primitives (loader, row, card, and similar), not cart, voucher, or auth rules.

Husky pre-commit: `tsc --noEmit` and lint-staged (Prettier on md, json, yaml, js, jsx). Pre-push: `yarn test:ci`.

## Security notes for reviewers

These are observations, not a penetration test.

1. RSA private key committed in `makePayment/src/index.js`. Public key committed in `src/constants/index.ts`.
2. README contains an AWS access key id and other integration secrets in a table. Omitted here.
3. Browser S3 signing uses the same style of access key via `REACT_APP_AWS_*`.
4. Card data is handled in the SPA and the payment lambda.
5. GraphQL schema has no `@auth`. Unauthenticated identities are enabled.
6. `createUser` and `disableUserAccount` take the user pool id and username from the request body.
7. `sendEmail` sends caller-supplied HTML to a caller-supplied address. The committed API Gateway path `/send-email` is `open: true`.
8. Lambda success responses allow origin `*`.

## Tests and quality gates

| Gate | State on `dev` |
|---|---|
| Unit tests in CI | Commented out |
| Pre-push tests | Husky `yarn test:ci` |
| Pre-commit typecheck | Husky `tsc --noEmit` |
| SonarQube | Pipeline step on branch `dev`, after the dev deploy |
| ESLint | `.eslintrc.json`. README says ESLint, not TSLint |
| Prettier | `.prettierrc` |

## `develop` technical note

Last commit `c2fc32d` (2020-08-27). Lerna packages include an Everblue UI kit with Storybook and a webpack backend. Do not deploy or document that tree as the current Vivlia app without a human decision. It is 51 commits apart from `dev` in the other direction.

## `master` technical note

`37b1a24` (2022-11-21) is a root commit. `git merge-base master dev` has no ancestor. Checking out the default branch does not build Vivlia.
