Skip to content

03 — Someli-Designer architecture

A guided tour.


Entry point — nuxt.config.js

Already covered in 02-stack.md. Re-read it after you finish this doc; it's short and dense.


Request lifecycle

Browser
Nuxt router
middleware/axios.js  (the ONE global middleware)
  └─ adds base64(`Apptype`) header
Page (pages/<name>.vue)
Component lifecycle (mounted) → this.$axios.get('/...')
  │   (NO store/api cache — direct call to backend)
axios interceptor (above) → request fires
designer-api at process.env.baseURL

Compare to someli-platform: there is no /auth/ prefix check for token injection (designer-api has its own hand-rolled auth, the FE manages it differently), no router-level redirect middleware, no URL rewriting.


Pages — flat, with many close cousins

pages/ has 73 files, all at the top level (no subdirectories). Many pairs and triples differ by one character:

  • topics.vue / topicsNew.vue
  • content_library.vue / master_library.vue / master_libraryNew.vue
  • conditionedContent.vue / conditionedContentNew.vue
  • automationTemplate.vue / nonAutomationTemplate.vue / tempsets.vue / carousaltemplates.vue
  • templateEditor.vue / templateEditor1.vue / carousaltemplateEditor.vue
  • postEditor.vue / postcreator.vue / postdesigner.vue / mediaEditor.vue / MastermediaEditor.vue / PreproductionPostEditor.vue
  • Posts.vue / postsMismatching.vue / contentMismatching.vue
  • PostColorCorrection.vue / TemplateColorCorrection.vue
  • dynamicPost.vue / dynamicPost - Copy.vue (yes, with the space)
  • News.vue / LatestNews.vue
  • popularSubjects.vue / subjects.vue / subjectsDemands.vue / subjectsBasedJobs.vue / generateSubject.vue / generatedSubjectContent.vue

Junior gotcha: these are not always meaningful pairs. Some are A/B variants; some are legacy. Some are vestigial (Template.vue likely is). Don't assume that "new" / "1" / "Copy" suffixes are the canonical version — they sometimes are, sometimes aren't.

The pages mostly do the same thing: fetch data via $axios, render a table or card list, allow CRUD operations.

See the page list in 02-stack.md and consult the team if you're unsure which page is the canonical one for a feature.


Components — only four

File Purpose
components/Navbar.vue Top navigation; role_type-based nav gating
components/Notification.vue Notification toast container
components/skeletonCard.vue Loading skeleton for cards
components/ToasterProgress.vue Toast progress indicator

Vue components are auto-registered (components: true) — but with only 4 files in the folder, you'll mostly write inline templates in pages/*.vue rather than extracting reusable components. If you find yourself extracting a component, decide explicitly whether to create it in components/ or inline it. The repo's convention is "mostly inline".


Layouts

Layout Used for
layouts/default.vue Authenticated UI (Navbar + content + notifications)
layouts/blank.vue Login screen (bare, no Navbar)

A page picks a layout via the layout option:

<script>
export default { layout: 'blank' };  // login uses blank
</script>

State — single Vuex module

store/index.js is the only Vuex file. State, getters, mutations, actions all here.

Common patterns you'll find:

  • Auth/login state mirrored from @nuxtjs/auth cookies
  • A list of templates / topics / posts currently loaded for the active page
  • UI flags (isLoading, modalOpen)
  • No backend-response caching layer

Identity / auth

Concern Where
Strategy @nuxtjs/auth v4 local strategy
Login endpoint webauthenticate (on designer-api)
User-fetch endpoint me
Logout Disabled at strategy level; cleared client-side
Token storage Cookies (cookie-universal-nuxt)
Apptype header Added by middleware/axios.js

See ../../audit/Someli-Designer/authentication-client.md.


Polotno editor — the lean fork

polotno-editor/ is its own React 18 / MobX-State-Tree / Parcel subproject. ~50 KB of code (the customer-app fork is ~221 KB).

File Purpose
index.html / index.js / App.js React entry
alltemplatesPanel.js All templates browser
templatesPanel.js Per-category templates
carousaltemplatesPanel.js Carousel templates
brandkitPanel.js (capital P) Brand kit panel — the customer fork uses brandkitpanel.js (lowercase p)
customUploads.js, mediaGrid.js, Pexels.js, PexelVideos.js Asset panels
CustomPageControls.js, CustomWorkspace.js Editor chrome
QrSection.js, ModalPortal.js, icons.js, helper.js UI helpers

Diverged from someli-platform/polotno-editor/

  • File-name casing differs (brandkitPanel.js vs brandkitpanel.js)
  • The customer fork has additional panels (e.g., customTextSection/, common/, helper/ subfolders) that don't exist here
  • Same-named files have drifted

Edits do not auto-port. See ../../audit/CODE-OVERLAP-MATRIX.md § 6.


Build process

# In polotno-editor/ — for interactive dev
yarn dev                          # Parcel dev server on http://localhost:1234

# In polotno-editor/ — for the actual bundle
yarn build                        # writes polotno-bundle.js into the parent repo root

# At the repo root — Nuxt
yarn dev                          # Nuxt dev server on http://localhost:3000
yarn build && yarn start          # production build + start

External deps listed in polotno-editor/package.json are not bundled into polotno-bundle.js. They must also be installed in the parent Nuxt app's node_modules. The README explains.


Role-based UI gating

components/Navbar.vue reads role_type from auth state and conditionally renders nav items. The role IDs come from env vars (mirrored from admin_console_R/src/config/env.ts).

This is a known drift risk: if the backend changes a role number, the FE must be redeployed with the new env var value. There is no central registry.

Junior gotcha: if you add a nav item, decide which roles can see it and gate accordingly. The backend has matching access checks — failing to gate the FE just hides the button; the backend will still 403. Failing to gate the backend is the security issue.


Where to put a new file

Adding Put it in
A new page pages/<name>.vue (flat; no subdirectories)
A new component components/<Name>.vue — but think first: should it be inlined in the page?
A new helper helpers/<name>.js
A new plugin (singleton) plugins/<name>.js, register in nuxt.config.js
A new middleware middleware/<name>.js, register in nuxt.config.js → router.middleware (currently only axios lives there)
A new Polotno panel polotno-editor/<Panel>.js, register in polotno-editor/App.js, yarn build
A new global state field Extend store/index.js (no sub-modules)

Where to start when you have a feature to build

  1. Find or create the page in pages/.
  2. Identify the backend endpoint the page will call — look in ../../audit/designer-api/API-inventory.md.
  3. Wire this.$axios.get/post(...) in the page's mounted() or methods.
  4. Add any state to store/index.js.
  5. Consider role gating — does this page need a nav-link in Navbar.vue and a role_type guard?

Next

04-getting-started.md.