Chapter 1

Codebase structure and quality

Nokio is not a monorepo. It is nine sibling GitLab projects under one workspace folder. Five surfaces run in production. Four are empty or a scaffold. Two eras of code coexist: extend the newer patterns; contain the older god files.

Static review of structure, typing, tests, conventions, and secret hygiene. No runtime load testing. Quality scores are 1–10 maintainability judgments, not delivery-readiness.

Workspace map

RepositoryRoleMaturityScore
backendSystem of record API — Express, Sequelize/MySQL, Redis, OpenSearch, Socket.IO, in-process cronsProduction4.5
web-appConsumer web — Next.js 14 App Router, NextAuth, React Query, CSS ModulesProduction6
mobile-app-newiOS / Android — React Native 0.74, Redux Persist + React Query, DetoxProduction5.5
aws / imdb_jsonIMDb S3 → Lambda → Step Functions preprocessProduction (manual ops)7
data-ingestionPython Excel → admin API scripts (new releases, upcoming, pick of the week)Ops scripts4
nokio-batch-job-appIntended NestJS batch workerScaffold2
data-servicesIntended data servicesEmpty stub0
recommendation-servicesIntended recommendation serviceEmpty stub0
devopsIntended ops templatesEmpty stub0

Default branches on the main apps: develop (staging), main (production). Hosts from docs and CI: API app.nokioapp.com / staging-app.nokioapp.com; web nokioapp.com / staging-webapp.nokioapp.com. GitLab deploy jobs also reference api.nokio.com.

How the pieces connect

mobile-app-new HTTP + Socket.IO web-app HTTP only data-ingestion Excel → admin API aws / imdb_json S3 diffs backend · Express /api MySQL · Redis · OpenSearch · Socket.IO · cron

Solid lines are live request paths. Dashed line is daily IMDb diff ingest from S3 into API cron.

Two eras of code

Folders exist for routes → services → repositories → models. Legacy code skips that and talks to helpers and Sequelize from the route file. New work should land on Era B. Growing Era A files is the highest-cost change pattern in the workspace.

Era B — extend

  • backend/src/routes/web/* with ~48 DTOs, express-validator, cache middleware
  • Repositories on a few hotspots (~14 files)
  • Web React Query key factories (~52 hooks) + OpenAPI model classes
  • Feature flags; generated TypeScript clients on web and mobile

Era A — contain

  • movies.ts 2227 LOC, admin.ts 2180 LOC
  • 10 helper ↔ service basename collisions (user, movie, review, …)
  • Mobile Movie_DEPRECATED still routed (~20 files)
  • Fire-and-forget in-process crons; silent empty catches

Quality dimensions

DimensionScoreNotes
Client structure (web)7App Router, RQ key factories, CSS Modules
Typed API contract7OpenAPI → generated schema + model classes + override layers
Auth / secrets hygiene2Tracked secrets, weak hashing, JWT without DB revalidation
Backend layering4Folders exist; enforcement does not
Error handling / UX3~28 web contexts return null on query error
Automated tests2Backend 2 files; web 4; mobile utils + Detox auth
Duplication control3Eight copies of useContactActionMutation on mobile

Repository notes

backend — 4.5 / 10

About 435 TypeScript files under src, ~114 route files (~44k LOC), ~68 services, ~49 helpers, ~110 models, ~269 migrations, 2 test files. Fourteen files exceed 1,000 lines. TypeScript is strict in tsconfig, but production build is SWC only — there is no tsc gate in CI. README still says PostgreSQL; code uses MySQL.

Central defaultErrorHandler is a good baseline, undermined by empty catches, helpers that return e, and health endpoints that can leak raw errors.

web-app — 6 / 10

~495 TSX files, ~51% "use client", ~219 CSS modules, ~39 Storybook stories, 4 tests, zero App Router error.tsx. Strengths: prefetch + HydrationBoundary, OpenAPI models, virtualized lists, Husky pre-push (lint + tsc + test). Weaknesses: silent error UX, dual HTTP stacks that disagree on Authorization (Bearer / JWT / raw token), module-level mutable token state on the API client, NEXTAUTH_SECRET || "your-secret" fallback.

mobile-app-new — 5.5 / 10

~573 TSX + ~109 leftover JS files. Dual token storage (Redux Persist whitelist and AsyncStorage). Mid-migration: Redux for session/UI, React Query for server data. God screens (e.g. StoryContainer ~789 LOC). Folder typo Dashboad. Detox coverage of auth/onboarding is the strongest automated product net in the workspace. APNs private key is git-tracked.

aws / imdb_json — 7 / 10

Streaming Lambdas (imdb_splitimdb_diffimdb_merge) with the best architecture README in the workspace. No in-repo IaC (manual AWS setup). Handlers often return err instead of throwing, which weakens Step Functions failure semantics.

data-ingestion — 4 / 10

Three near-duplicate Excel processors. Env-based JWT, retries, gitignored env files. No requirements.txt, no tests, sample Excel committed, README has machine-specific absolute paths.

Stubs

nokio-batch-job-app is still a Nest “Hello World”; readFile only logs the path. data-services, recommendation-services, and devops contain README + gitignore only. Azure pipeline templates elsewhere still reference a devops template repo that is empty here. Recommendations in this product are user-to-user rows, not a separate ML service — the empty recommendation repo should not be mistaken for a missing production dependency.

Critical security findings

Treat as P0 before feature work Secret values are not reproduced in this report. Rotate and purge, then scrub git history as needed with the ops owner.
FindingWhereSeverity
Secrets tracked in git (env file with live-looking SendGrid / FCM / DB values)backendCritical
APNs signing key trackedmobile-app-newCritical
Password hashing: PBKDF2, 1 SHA-1 iteration, 128-byte keybackend/src/models/user.tsCritical
JWT strategy does done(null, payload) — no MySQL reload of the userbackend/src/config/passport.tsHigh
Public festival route reads req.user.id without mounting JWT authfilmFestivalPublic.tsHigh
Fire-and-forget cron jobs without await/catchhelpers/cron.tsHigh

Testing posture

RepoAutomated netGap
backend2 unit filesRoutes, cron, admin, chat uncovered
web-app4 files (mostly utils)Auth, API, React Query, pages uncovered
mobile-app-newUtils Jest + Detox authHome / Movie / Circles / Festival thin
aws / imdb_jsonLocal harness onlyNo CI tests
data-ingestionNone

Clients have process (pre-push tsc/test) without enough coverage for those gates to catch domain bugs.

Working agreements for new code

DoDo not
Add API endpoints under routes/web with DTOs and validatorsGrow movies.ts / admin.ts
Share React Query hooks and key factoriesCopy useContactActionMutation into another screen
Render recoverable error UI / error.tsxreturn null on isError
Keep .env* and signing keys out of gitCommit credentials “for convenience”
Run tsc in backend CI; await/catch cronsAssume an SWC build equals type safety
Document MySQL as the system of recordTrust the README’s PostgreSQL mention
Previous Overview Next Technical architecture