Files
nick-doc/07 - Development/Project Structure.md

209 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Project Structure
tags: [development]
---
# Project Structure
A bird's-eye view of both repos. For deep dives, follow the cross-links to [[Backend Architecture]] and [[Frontend Architecture]].
---
## Backend — `/Users/mojtabaheidari/code/backend`
A service-oriented Express 5 app. Each business domain owns a folder under `src/services/` containing its routes, controllers, services, and repositories. Cross-cutting concerns live in `src/shared/` and `src/infrastructure/`. PostgreSQL + Drizzle ORM is the sole database layer as of v2.9.12 (Mongoose fully removed).
```
backend/
├── src/
│ ├── app.ts # Express bootstrap: middleware, routes, Socket.IO, startup
│ ├── config/ # Sentry init (loaded before anything else)
│ ├── controllers/ # Thin HTTP controllers for orphan endpoints (disputes, points)
│ ├── routes/ # Router exports for orphan controllers above
│ ├── models/ # (removed — Mongoose models deleted; schemas now in src/db/schema/)
│ ├── db/ # PostgreSQL + Drizzle ORM — SOLE database layer (19 migrations, 32 tables)
│ │ ├── schema/ # Drizzle table definitions (single source of truth for data)
│ │ ├── migrations/ # SQL migration files (00000019)
│ │ └── repositories/ # Drizzle-backed repository implementations
│ ├── infrastructure/
│ │ ├── database/ # (removed — Mongoose connection code deleted)
│ │ └── socket/ # Socket.IO server adapter & emitter helpers
│ ├── services/ # Domain services — see breakdown below
│ ├── shared/
│ │ ├── config/ # Typed `config` object (env loader)
│ │ ├── middleware/ # auth, errorHandler, rate limit, request logger
│ │ ├── types/ # Cross-domain type aliases
│ │ └── utils/ # Helpers reused across services
│ ├── utils/ # logger, currencyUtils, videoHelpers
│ ├── seeds/ # Idempotent data seeders
│ └── scripts/ # One-off operational scripts (TS + sh)
├── __tests__/ # Jest suites (see Testing)
├── scripts/ # Shell scripts (build/push, version, ngrok, reset)
├── nginx/ # Nginx conf (production compose)
├── uploads/ # User uploads — mounted as volume
├── Dockerfile.dev # Hot-reload image (ts-node + nodemon)
├── Dockerfile.prod # Multi-stage build image (compiled JS, non-root user)
├── docker-compose.dev.yml # Local stack: backend + postgres + redis
├── docker-compose.production.yml # Prod stack: nginx + backend + frontend + postgres + redis
├── .gitea/workflows/ # Gitea Actions CI
├── healthcheck.js # Container HEALTHCHECK probe
├── eslint.config.js # Flat ESLint config (TS strict)
├── jest.config.js # ts-jest preset
└── package.json
```
### `src/services/` folders
Each service folder follows the same shape: `<service>Routes.ts`, `<service>Controller.ts`, `<service>Service.ts`, sometimes a `<service>Repository.ts` and an `index.ts` barrel.
| Folder | Purpose |
|--------|---------|
| `address/` | CRUD for buyer/seller addresses (max 3 per user) |
| `admin/` | Admin-only data-cleanup + diagnostic endpoints |
| `ai/` | OpenAI-backed assistants (offer suggestions, content moderation) |
| `auth/` | Login, signup, refresh, Google OAuth, passkey/WebAuthn, temp verification |
| `blockchain/` | Generic wallet/chain helpers shared by payment providers |
| `blog/` | Public blog posts, comments, video helpers |
| `chat/` | Realtime messaging between buyers & sellers |
| `delivery/` | Delivery tracking + shipping events |
| `dispute/` | Dispute opening, evidence upload, arbitration |
| `email/` | Nodemailer service + transactional templates |
| `file/` | Multer uploads + Sharp image processing |
| `marketplace/` | Purchase requests, seller offers, accept/reject, categories |
| `notification/` | In-app notifications + delivery (socket + email) |
| `payment/` | Payment orchestration; sub-folders `shkeeper/`, `depay/`, `web3/` |
| `points/` | Reputation points + level config |
| `redis/` | Redis client wrapper (caching, rate counters) |
| `user/` | Profile, settings, role management |
### `src/models/` (removed)
This directory no longer exists. All Mongoose models have been deleted. Data schemas are now defined as Drizzle table objects in `src/db/schema/`. See [[Data Models]] for the current PostgreSQL schema docs.
### `src/db/`
PostgreSQL + Drizzle ORM — the **sole** database layer (no Mongoose, no dual-write, no Mongo fallback). Highlights:
- `schema/` — Drizzle table definitions covering all 32 tables across 19 migrations (00000019)
- `migrations/` — SQL migration files applied via `drizzle-kit`
- `repositories/` — Drizzle-backed repository implementations returned exclusively by the repository factory
- All domain stores use `PG_URL` (required); `MONGO_URI` / `MONGODB_URI` / `MONGO_CONNECT_MODE` are obsolete
- IDs are PostgreSQL UUIDs (`.id` string field); `legacy_object_id` column preserves the original MongoDB ObjectId for `User` only
### `src/seeds/`
Idempotent, runnable via `npm run seed:*`. See [[Scripts#seed-scripts]].
---
## Frontend — `/Users/mojtabaheidari/code/frontend`
Next.js 16 App Router with the `src/` layout. The structure follows the Minimal v7 template: pages in `app/`, page-level UI in `sections/`, reusable atoms in `components/`, and a strong split between server data fetchers (`actions/`) and client UI.
```
frontend/
├── src/
│ ├── app/ # Next.js App Router — route groups: (auth) (dashboard) post shop
│ │ ├── layout.tsx # Root layout (providers, font, metadata)
│ │ ├── page.tsx # Landing page
│ │ ├── auth/ # /auth/* routes
│ │ ├── dashboard/ # /dashboard/* routes (authenticated)
│ │ ├── post/ # Public blog posts
│ │ ├── shop/ # Public shop pages
│ │ ├── error/ # Custom error route
│ │ ├── loading.tsx # Global loading skeleton
│ │ └── not-found.tsx # 404
│ ├── sections/ # Page-level UI grouped by domain
│ │ ├── account/ address/ blog/ chat/ dispute/ error/
│ │ ├── overview/ payment/ points/
│ │ ├── request/ request-template/ shop-settings/ user/
│ ├── components/ # Reusable UI atoms & molecules (MUI-based)
│ │ ├── hook-form/ # RHF-wrapped MUI inputs (RHFTextField, RHFSelect, …)
│ │ ├── iconify/ # The single icon component (use only this)
│ │ ├── animate/ carousel/ chart/ custom-* / nav-section/
│ │ ├── upload/ file/ image/ markdown/ editor/ map/ video-player/
│ │ └── … # see full list in the codebase
│ ├── contexts/ # Top-level React contexts (socket-context.tsx)
│ ├── hooks/ # Generic hooks: useBoolean, useSetState, useSnackbar, useSocket
│ ├── lib/ # axios.ts — singleton API client with interceptors
│ ├── locales/ # i18n: langs/, i18n-provider, server.ts, use-locales
│ ├── layouts/ # AppShell variants: auth-centered, auth-split, dashboard, main, simple
│ ├── theme/ # MUI theme (core + with-settings overrides)
│ ├── settings/ # Theme-switcher drawer + persisted user settings
│ ├── actions/ # Server-side / shared async API calls (axios)
│ ├── auth/ # JWT / OAuth / passkey context, guards, hooks, services
│ ├── socket/ # Socket.IO client, hooks, components, contexts
│ ├── web3/ # WalletConnect + Alchemy + Request Network checkout glue
│ ├── routes/ # Static path constants (paths object)
│ ├── utils/ # logger, format-number, format-time, localStorage, …
│ ├── types/ # Shared TS types (mirrors backend models where useful)
│ ├── assets/ # SVGs, illustrations
│ ├── _mock/ # Mock data for storybooks / tests
│ ├── global-config.ts # Read-only app config (name, version, paths)
│ └── global.css # Tailwind-less global styles
├── public/ # Static assets served at /
├── e2e/ # Playwright specs
├── __tests__/ # Jest + RTL specs (organised by domain)
├── scripts/ # Shell scripts (deploy, debug, version, console-log migration)
├── docs/ # In-repo design notes (not the Obsidian vault)
├── doc/ # Legacy docs folder
├── Dockerfile # Production multi-stage Next.js build
├── Dockerfile.dev # Dev image (yarn dev on port 3000)
├── next.config.ts # Standalone output, image domains, Sentry integration
├── playwright.config.ts # E2E test config
├── jest.config.js # Jest + jsdom + RTL
├── eslint.config.mjs # Flat ESLint with perfectionist sorting
├── prettier.config.mjs # Prettier config
├── .commitlintrc.json # Conventional commits enforcement
├── sentry.client.config.ts # Browser Sentry init
├── sentry.server.config.ts # Server runtime Sentry init
└── sentry.edge.config.ts # Edge runtime Sentry init
```
### `src/sections/` vs `src/components/`
A common confusion when first navigating the codebase:
- **components/** — generic, reused everywhere, no business logic. (e.g. `Iconify`, `RHFTextField`, `EmptyContent`.)
- **sections/** — page-level UI bound to a domain. (e.g. `sections/payment/CheckoutSummary.tsx`.) Sections may import from `components/` but not the other way around.
### `src/auth/` vs `src/socket/` vs `src/web3/`
These are feature-bundles that ship their own context, hooks, services, and components together. Treat each like an internal package — import only from its `index.ts` barrel.
### Routes & API
- `routes/paths.ts` — every URL the app navigates to, expressed as a typed object.
- `lib/axios.ts` — the single axios instance with auth interceptor and base URL from `NEXT_PUBLIC_API_URL`.
- `actions/*.ts` — async functions wrapping axios calls; consumed by both server components and client components.
---
## Repository layout (top-level)
```
~/code/
├── backend/ # this repo
├── frontend/ # this repo
└── docs/ # this Obsidian vault
```
The production `docker-compose.yml` lives in `backend/` but references `../frontend` for the frontend build context — keep both folders as siblings.
---
## Where to add new things
| You want to add… | Put it under… |
|---|---|
| A new public API route | `backend/src/services/<domain>/<domain>Routes.ts` (or a new domain folder) |
| A new database table | `backend/src/db/schema/<name>.ts` (Drizzle) + add a migration via `drizzle-kit generate` |
| A reusable UI component | `frontend/src/components/<kebab-name>/` with `index.ts` + `component.tsx` + `types.ts` |
| A page-specific block | `frontend/src/sections/<domain>/` |
| A new dashboard page | `frontend/src/app/dashboard/<route>/page.tsx` |
| A shared hook | `frontend/src/hooks/use-<name>.ts` |
| A one-shot ops script | `backend/scripts/<name>.sh` (operational) or `backend/src/scripts/<name>.ts` (touches DB) |
| A seed script | `backend/src/seeds/<name>.ts` and add an `npm run seed:<name>` entry |
For the architectural rationale behind these splits see [[Backend Architecture]] and [[Frontend Architecture]].