Skip to content

Architecture Overview

Status: Audit v0.1 (2026-05-09). Every claim cites a source.

1. At a glance

Property Value Source
Framework Nuxt 2.18.1 (Vue 2.7.16) package.json:67 (nuxt), :84 (vue)
Rendering mode SPAssr: false nuxt.config.js:2
Module system CommonJS-leaning ESM, Babel-compiled nuxt.config.js:325-330 (Babel config); no "type": "module" in package.json
Language JavaScript only No tsconfig.json or *.ts files outside node_modules
Bundler Webpack 4 (bundled with Nuxt 2) package.json:113 (webpack: ^4.46.0)
Type checking None No TS, no vue-tsc, no Flow
Package manager Yarn 1 (classic) yarn.lock header: yarn lockfile v1
Node version target 20.x (assumed) Dockerfile:4 (node:20.18.3-slim); no engines field in package.json
State management Vuex 3 (non-strict) package.json:104; store/index.js:1 (export const strict = false)
Routing Nuxt 2 file-based routing pages/ directory; nuxt.config.js:227-243
HTTP client @nuxtjs/axios nuxt.config.js:250; package.json:? (transitive via @nuxtjs/auth)
Auth @nuxtjs/auth v4 (local strategy) package.json:24; nuxt.config.js:285-311

The web client is a single-page application — the framework is being used for routing, code-splitting, and dev tooling, but no server-side rendering occurs at runtime. This is consequential for SEO, observability, and how environment variables are exposed (see seo-and-metadata.md, security.md).

For the breadth of the product surface this SPA serves, see ../19-feature-inventory.md — the feature → page → component → backend-endpoint map. Headline: 14 major surface areas (auth + onboarding, account/team, content planner, editor in 6 variants, content creation incl. AI, library/templates/media, brand kit + AI brand assets, social-account management, dashboards in ~10 sub-sections, billing, network features, chat, settings, public/marketing). This breadth is the core product value; it is also the multiplier on every operational-maturity gap (see enterprise-readiness.md).

A second, independent React 18 / MobX-State-Tree application lives at polotno-editor/. It is built with Parcel into polotno-bundle.{js,css} at the repo root, then imported by editor pages in the main Nuxt app as a regular ES module. See ./build-and-deploy.md and the existing project doc ../06-polotno-integration.md for the integration pattern.

2. Source structure

Top-level directories under repo root:

api/             Nuxt server middleware (Express handlers — NOT the backend API)
assets/          CSS/SCSS/images processed by webpack
components/      Vue components (auto-imported by Nuxt; 161 .vue files)
constants/       Provider/plan/path constants
data/            Sitemap data
helpers/         Pure utility functions (helper.js, circleNetworkHelper.js, mixins/, models/)
layouts/         Page layouts (default, error, fourOhOne, onBoard, someliNetwork, specialOffer)
middleware/      Nuxt router middleware (axios.js, redirect.js, appendUrl.js, etc.)
mixins/          Vue mixins (only onboardingNavigation.js)
pages/           File-based routes (84 .vue files)
plugins/         Nuxt plugins (19 files; 14 wired in nuxt.config.js)
services/        Service-layer modules (only circleNetworkService.js)
static/          Static assets served verbatim
store/           Vuex modules (root + 7 feature modules + api.js + onboarding.js + modules/sitemap.js)
polotno-editor/  Independent React 18 + MobX-State-Tree app (separate package.json, separate build)

Data sources for the directory listing: find . -maxdepth 1 -type d; per-folder file counts via find <dir> -type f | wc -l.

The structure is organized by Nuxt convention (pages/, components/, layouts/, middleware/, plugins/, store/) rather than by feature. There are no feature folders (e.g., no features/billing/ or domains/posts/); related pages, components, and store modules are co-located only by Nuxt naming convention, not by domain.

3. Code volume

Measurement Value Source
Total Vue + JS LOC (excluding node_modules, .nuxt, dist, polotno-editor) 159,530 lines find pages components layouts plugins helpers store middleware mixins constants api -type f \( -name '*.vue' -o -name '*.js' \) \| xargs wc -l
Vue (.vue) LOC alone 154,779 lines Same command, -name '*.vue' only
Number of pages 84 find pages -type f -name '*.vue' \| wc -l
Number of components 161 find components -type f \| wc -l
Number of layouts 6 ls layouts/
Number of plugins (files) 19 ls plugins/
Number of plugins wired in nuxt.config.js 14 nuxt.config.js:179-225 (hotjar2 is commented out and excluded)

3.1 Largest files (top 5 of each)

Pages (find pages -name '*.vue' -exec wc -l {} \; | sort -rn | head -5):

Lines File
10,795 pages/userSetting/index.vue
9,781 pages/_accid/userSetting/index.vue
5,506 pages/_accid/my_library/index.vue
4,957 pages/_accid/contentplanner/index.vue
4,069 pages/contentplanner/index.vue

Components (find components -name '*.vue' -exec wc -l {} \; | sort -rn | head -5):

Lines File
3,678 components/editPostModal.vue
3,328 components/Cards/ContentCard.vue
2,512 components/Chatbot.vue
2,311 components/ImageManager.vue
2,200 components/createContentModal.vue

Finding [WC-ARCH-1] (Severity: High): Multiple files exceed 4,000 lines and one (pages/userSetting/index.vue) is 10,795 lines. Files of this size are well past any reasonable maintainability threshold; refactoring or extracting child components is a high-value Phase 0/1 effort. The total of files >2,000 lines is 9.

Finding [WC-ARCH-2] (Severity: High): pages/userSetting/index.vue (10,795 lines, legacy non-_accid route) and pages/_accid/userSetting/index.vue (9,781 lines, current account-scoped route) are near-duplicate files. The same pattern repeats for contentplanner, my_library, billing, topics, and Organisationprofile. This is a massive code-duplication finding: every user-facing change touches both copies. Estimated duplicated LOC: ~30,000+. Cleanup is a Phase 1 effort.

4. Code style and quality enforcement

Tool Wired? Source
Prettier Yes, via yarn format (manual) package.json:12
Prettier on save in editor Disabled by .vscode/settings.json .vscode/settings.json (sets formatOnSave: false)
ESLint Configured but not wired to a script package.json:128-141 (eslintConfig); no lint script
ESLint config severity Lowest extends: ["plugin:vue/essential", "eslint:recommended"], rules: {}
eslint-plugin-jsx-a11y Not installed Absent from package.json
TypeScript Not used No TS files, no tsconfig.json
.editorconfig Yes .editorconfig (2-space, LF, UTF-8)
.prettierrc Yes .prettierrc (single quotes, no semis, no trailing comma, 2-space)
Pre-commit hooks None functionally .git/hooks/pre-commit exists from yorkie but package.json has no pre-commit hook script, so it no-ops
CI lint gate None .github/workflows/dev_app.yml runs yarn build, no lint step
Type-check gate None (no TS)

Finding [WC-ARCH-3] (Severity: Medium): Quality enforcement is minimal. ESLint exists in config but is not run anywhere — no script, no pre-commit hook, no CI gate. Effective code-quality enforcement is manual peer review only. The CMMI rating for "Architecture & Modularity" pillar will reflect this.

5. Dead code and inconsistencies

Item Source
pages/posteditor/_id/index.vue, pages/cuseditor/_id/index.vue, pages/editor/_id/, pages/carouseleditor1/_id/, pages/carouseleditor/_id/, pages/carouselcpeditor/_id/ are legacy non-_accid routes; the live app uses _accid-prefixed equivalents. The appendUrl middleware silently rewrites unprefixed URLs to inject accountId. middleware/appendUrl.js:6-36; existing doc ../04-routing.md
api/index.js contains ~80 lines of commented-out Twitter/Passport scaffolding around 18 lines of live code api/index.js:1-105
plugins/fullstory.js contains a complete FullStory init script with hardcoded org ID o-1C5EVB-na1 but is not registered in nuxt.config.js → plugins plugins/fullstory.js; nuxt.config.js:179-225
plugins/hotjar.js, plugins/hotjar2.js exist but are not registered Same
plugins/sales_iq.js, plugins/snowfall.js exist; snowfall is registered, sales_iq is not Same
middleware/head.js contains substantial role-based access control logic but is not wired in nuxt.config.js or any per-page middleware Existing doc ../03-auth-and-sessions.md; verified via grep -rn "['\"]head['\"]" pages nuxt.config.js \| grep -v "<head>\|head:"
middleware/socialLogin.js is not referenced anywhere Same approach
Both yarn.lock (11,423 lines) and package-lock.json (22,271 lines) exist at the repo root — npm has been run alongside yarn at some point wc -l yarn.lock package-lock.json
node_modules.backup/ directories exist at root and inside polotno-editor/ ls -la \| grep node_modules
.env~ (vim swap-style backup) exists at the repo root and is not in .gitignore ls .env*; grep "\.env~" .gitignore (no match)
'admin' layout is referenced by one page but layouts/admin.vue does not exist Existing doc ../04-routing.md

Finding [WC-ARCH-4] (Severity: Medium): The repo carries substantial dead/unwired code — multiple unwired plugins, an unwired-but-implemented head middleware, ~80 lines of commented-out Express code in api/index.js, a near-complete legacy route tree under pages/<route>/_id/ that the rewriter middleware short-circuits, and dual lockfiles. Cleanup is a Phase 0 / Phase 1 hygiene task.

Finding [WC-ARCH-5] (Severity: Low/Medium): package-lock.json and yarn.lock coexist. This creates dependency drift if both are honored. Convention in this repo is yarn (per Jenkinsfile, 01-local-setup.md). Action: delete package-lock.json, add it to .gitignore. Confirm with team that no tool depends on it.

6. Build process

yarn build runs nuxt build, which produces:

.nuxt/      Nuxt build cache (62 MB)
dist/       Static-site output if `yarn generate` is run
            (currently 78 MB; contains a snapshot from `nuxt generate`)

The actual production runtime is yarn startnuxt start which serves the SPA from .nuxt/dist/. The dist/ directory is the artifact of a prior nuxt generate run; it is not what the production container serves.

The bundle is split across 254 JS chunks in dist/_nuxt/ totaling 21.8 MB raw. Top 5 chunks by size:

Raw bytes Gzipped File Likely contents
4,986,869 1,368,730 db8106d.js Polotno-related (konva, react-dom)
2,088,345 498,388 50ea2d1.js konva, moment
1,437,102 290,458 cc9063d.js filepond
923,358 210,595 4e81c68.js filepond, @fullcalendar/*
830,007 401,030 9a92ef4.js (unknown — investigate in performance.md)

See ./performance.md for full bundle analysis.

7. Embedded React app

The polotno-editor/ sub-project is an entirely separate React 18 application built with Parcel:

Property Value Source
Framework React 18 + MobX 6 + MobX-State-Tree 6 polotno-editor/package.json
Build tool Parcel 2 Same
Output ../polotno-bundle.js (216 KB / 221,172 bytes), ../polotno-bundle.css (~9.5 KB / 9,697 bytes) polotno-editor/package.json:6 ("main": "../polotno-bundle.js"); stat -c%s polotno-bundle.*
License key Hardcoded in polotno-editor/index.js:14 (createStore({ key: 'FXZvloSJvAe09-bdR9iC' })) polotno-editor/index.js:14
Persistence localStorage keyed by pathname + hash, debounced 2s polotno-editor/index.js:23-31
Dependencies 26 production, 2 dev jq '.dependencies \| length' polotno-editor/package.json

This is a second component for audit purposes but is treated here as a sub-component of the web client. Its security posture (large React bundle, AI provider keys baked at build time) is covered in ./security.md and ./performance.md.

8. Architectural concerns (summary)

The detailed maturity rating is in enterprise-readiness.md. Headlines:

  • Stack age. Vue 2 reached EOL on 2023-12-31 (per Vue.js core team announcement). Nuxt 2 reached EOL on 2024-06-30. Both are running unsupported in 2026. This is the single most consequential finding — it caps the upper bound on every other improvement and creates ongoing security exposure (see security.md).
  • No type safety. 159K lines of JS with no TypeScript and no runtime validation library (no Zod, Yup, etc., observed in deps). Refactor risk is high.
  • Massive single-file complexity. Five files >4K lines, two files >9K lines.
  • Zero test coverage. No project-owned test files (the 164 *.test.* matches are all inside node_modules/ of dependencies). No CI test gate. See ./testing.md.
  • Dual lockfiles. Drift risk; convention is yarn but npm has been run.
  • No type/lint CI gates. ESLint configured but never executed; no pre-commit hooks.

These are flagged as findings in enterprise-readiness.md and roadmapped per WEB_CLIENT_AUDIT_GUIDE.md §6.3.