Skip to content

Architecture Overview

Tech stack

Concern Choice Version Cite
Framework React ^18.3.1 package.json
Language TypeScript ^5.5.3 package.json (devDep); tsconfig.json
Bundler Vite ^5.4.1 package.json; vite.config.ts
Build plugin @vitejs/plugin-react-swc ^3.5.0 vite.config.ts
Module system ESM ("type": "module") n/a package.json
Routing react-router-dom ^6.26.2 package.json; src/App.tsx
Server-state cache @tanstack/react-query ^5.56.2 package.json; src/App.tsx
Forms react-hook-form + @hookform/resolvers + zod latest package.json
CSS Tailwind 3 + tailwindcss-animate + class-variance-authority ^3.4.11 tailwind.config.ts
UI primitives shadcn/ui (Radix UI under the hood) varies src/components/ui/*.tsx; components.json
Icons lucide-react ^0.462.0 package.json
Toasts sonner + shadcn toast ^1.5.0 package.json
Charts recharts ^2.12.7 package.json
Date date-fns ^3.6.0 package.json
Linter ESLint 9 (flat config) + eslint-plugin-react-hooks + eslint-plugin-react-refresh + typescript-eslint latest eslint.config.js

There is no Prettier / pre-commit hook configured.

Source structure

admin_console_R/
├── index.html                       # Vite entry; loads /src/main.tsx; includes gpteng.co/gptengineer.js script (note in security.md)
├── vite.config.ts                   # dev server on :8080; allowedHosts includes admin.someli.ai; alias @ → src; HMR overlay disabled
├── eslint.config.js                 # ESLint 9 flat config
├── tailwind.config.ts               # darkMode 'class'; SF Pro Display font stack; design-token-driven HSL palette via CSS vars
├── tsconfig.json + tsconfig.app.json + tsconfig.node.json
├── components.json                  # shadcn CLI config (alias, css path)
├── postcss.config.js                # autoprefixer + tailwind
├── package.json
├── package-lock.json + yarn.lock + bun.lockb   # three lockfiles — see dependencies-inventory.md
├── public/                          # static assets (logo, dashboard.jpg)
└── src/
    ├── main.tsx                     # React 18 createRoot bootstrap
    ├── App.tsx                      # router + global providers (QueryClient, AuthProvider, TooltipProvider, Toasters)
    ├── index.css                    # global Tailwind + CSS variables
    ├── App.css                      # leftover, mostly empty
    ├── vite-env.d.ts                # vite type augmentation
    ├── components/
    │   ├── auth/
    │   │   ├── LoginForm.tsx
    │   │   └── ProtectedRoute.tsx
    │   ├── layout/
    │   │   ├── AppLayout.tsx        # sidebar + main content shell
    │   │   └── Sidebar.tsx          # nav items, logout, account switcher
    │   ├── shared/                  # small reusable bits
    │   └── ui/                      # 50 shadcn primitives (Radix wrappers)
    ├── config/
    │   └── env.ts                   # typed env var accessor
    ├── context/
    │   └── AuthContext.tsx          # user/token state, login/logout/checkAuth
    ├── hooks/
    │   ├── useAuth.tsx              # convenience wrapper around AuthContext
    │   ├── use-mobile.tsx
    │   └── use-toast.ts
    ├── lib/                         # cn() utility etc.
    ├── pages/
    │   ├── Accounts.tsx + Accounts.css
    │   ├── AffiliateMarketing.tsx
    │   ├── CustomerService.tsx
    │   ├── Index.tsx
    │   ├── Login.tsx
    │   ├── MyProfile.tsx
    │   ├── NotFound.tsx
    │   ├── Personnel.tsx
    │   └── Prompts.tsx
    └── services/
        └── api.ts                   # 184 lines — fetch wrapper + ~25 named API methods

Entry point — src/main.tsx / src/App.tsx

main.tsx does the React 18 createRoot(...).render(<App />). App.tsx composes the provider stack:

<QueryClientProvider>
  <TooltipProvider>
    <BrowserRouter>
      <AuthProvider>
        <Toaster />
        <Sonner />
        <Routes>
          <Route path="/" element={<Navigate to="/login" replace />} />
          <Route path="/login" element={<Login />} />
          <Route path="/accounts" element={<ProtectedRoute><AppLayout><Accounts /></AppLayout></ProtectedRoute>} />
          {/* ... */}
        </Routes>
      </AuthProvider>
    </BrowserRouter>
  </TooltipProvider>
</QueryClientProvider>

Every protected route is wrapped in ProtectedRoute → AppLayout → <Page />. The repetition is verbose but explicit. A refactor to a single <ProtectedRoutes> layout-route would tighten this without changing behaviour.

Build process

  • Dev: npm run devvitehttp://localhost:8080 (port set in vite.config.ts)
  • Production build: npm run buildvite builddist/
  • Dev-mode build (for staging?): npm run build:devvite build --mode development

There is no npm run start / npm run preview invoked anywhere; production hosting strategy is not documented in-repo (see build-and-deploy.md).

Largest files

(sample by inspection; full count would need find ... -exec wc -l)

  • src/services/api.ts — 184 lines
  • src/context/AuthContext.tsx — ~150 lines
  • src/pages/Accounts.tsx — verify; likely the largest page (table + filters + modals)
  • All src/components/ui/*.tsx — generated shadcn files, usually 40-200 lines each

No file is in the 1000+ LoC range typical of the backend repos. This is healthy.

Dead / commented code

  • src/components/layout/Sidebar.tsx has a commented-out Prompts nav item (despite the route being mounted). Either un-comment or delete.
  • index.html contains: <!-- IMPORTANT: DO NOT REMOVE THIS SCRIPT TAG OR THIS VERY COMMENT! --> followed by <script src="https://cdn.gpteng.co/gptengineer.js" type="module"></script>. This is the Lovable.dev runtime tag — see security.md.

Coding conventions

  • TypeScript with strict mode (verify in tsconfig.app.json — strict is default off in many starter templates; check)
  • React function components only
  • Naming: PascalCase for components, camelCase for utilities; file names match component names
  • Imports prefer the @/ alias over relative paths
  • cn() (from src/lib/utils.ts) for conditional class merging
  • Toasts via useToast() (src/hooks/use-toast.ts) which forwards to shadcn <Toaster>; Sonner is also mounted in App.tsx but the useToast route is the primary one used