Skip to content

πŸ—οΈ Touli β€” Project Structure ​

Nx monorepo Β· Next.js web client Β· Express REST API Β· shared TypeScript libraries Β· AWS CDK infrastructure

NxNext.jsReactExpressPostgreSQLTypeScriptAWS CDK

There is a separate app, apps/mobile (Expo / React Native), documented on its own page β€” it shares libs/types with this side of the monorepo but has its own screen/routing/lib conventions.


Contents ​

  1. Overview
  2. Architecture flow
  3. Full folder tree
  4. Frontend β€” apps/client
  5. Backend β€” apps/server
  6. Shared libraries β€” libs/
  7. Infrastructure β€” libs/cdk
  8. Path aliases
  9. Tech stack

Overview ​

AreaPathWhat it is
🌐 Frontendapps/clientNext.js 16 App Router β€” SSR/SSG public site + admin dashboard
πŸ–₯️ Backendapps/serverExpress 5 REST API + PostgreSQL (Sequelize)
πŸ“± Mobileapps/mobileExpo / React Native app β€” see its own doc
πŸ“¦ libs/typessharedTypeScript interfaces, enums, DTOs, API path constants β€” imported by client, server, and mobile
🎨 libs/uiclient-onlyAnt Design–based component library (atoms β†’ molecules β†’ organisms)
πŸ—„οΈ libs/modelsserver-onlySequelize database models
πŸ” libs/seoclient-onlyStructured-data (JSON-LD) schema builders + metadata helpers
☁️ libs/cdkinfraAWS CDK stacks β€” VPC, ECS, RDS, ECR, pipelines, WAF, CloudWatch

Architecture flow ​

mermaid
flowchart LR
    U["πŸ§‘ Browser"] --> C["apps/client\nNext.js Β· SSR/SSG Β· Zustand"]
    C --> S["apps/server\nExpress Β· JWT Β· REST API"]
    S --> DB[("PostgreSQL\nvia libs/models")]
    S --> AWS["AWS S3 / SES"]
    M["πŸ“± apps/mobile\nExpo"] --> S

    style U fill:#fce7f3,stroke:#db2777
    style C fill:#eff6ff,stroke:#2563eb
    style S fill:#f0fdf4,stroke:#16a34a
    style DB fill:#fef3c7,stroke:#d97706
    style AWS fill:#fce7f3,stroke:#db2777
    style M fill:#eff6ff,stroke:#2563eb

libs/types is imported by both apps/client and apps/server (and apps/mobile) so request/response shapes can never drift between them. libs/cdk provisions the AWS infrastructure both apps deploy onto but is never imported by application code at runtime.


Full folder tree ​

text
touli/
β”œβ”€β”€ apps/
β”‚   β”œβ”€β”€ client/                # Next.js 16 web app
β”‚   β”œβ”€β”€ server/                # Express 5 REST API
β”‚   β”œβ”€β”€ mobile/                # Expo app β€” see docs/mobile/project-structure.md
β”‚   β”œβ”€β”€ client-e2e/            # Playwright E2E (client)
β”‚   └── server-e2e/            # Jest E2E (server API)
β”œβ”€β”€ libs/
β”‚   β”œβ”€β”€ types/                  # @workspace/types β€” shared interfaces, enums, DTOs, API constants
β”‚   β”œβ”€β”€ ui/                     # @workspace/ui β€” Ant Design component library (client-only)
β”‚   β”œβ”€β”€ models/                 # @workspace/models β€” Sequelize models (server-only)
β”‚   β”œβ”€β”€ seo/                    # @workspace/seo β€” JSON-LD schema + metadata helpers (client-only)
β”‚   └── cdk/                    # AWS CDK app β€” infrastructure as code (not an Nx-buildable lib)
β”œβ”€β”€ docs/                       # guides/, mobile/, architecture/
β”œβ”€β”€ tools/scripts/               # Repo automation (e.g. run-mobile-expo.mjs)
β”œβ”€β”€ nx.json Β· tsconfig.base.json # Nx + path-alias config
└── package.json                 # Workspace root β€” single yarn install for the whole repo

Frontend β€” apps/client ​

Next.js 16, App Router, Turbopack.

text
apps/client/src/
β”œβ”€β”€ app/                         # App Router β€” route groups, layouts, pages
β”‚   β”œβ”€β”€ layout.tsx                # Root layout β€” providers, fonts, i18n
β”‚   β”œβ”€β”€ (auth)/                   # Route group β€” no navbar/footer
β”‚   β”‚   β”œβ”€β”€ layout.tsx
β”‚   β”‚   └── login/page.tsx
β”‚   β”œβ”€β”€ (main)/                   # Route group β€” Navbar + Footer shell
β”‚   β”‚   └── page.tsx               # Home page
β”‚   └── admin/                     # Admin dashboard (currently a single placeholder route)
β”‚       └── page.tsx
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ layouts/                   # navbar.tsx, footer.tsx
β”‚   β”œβ”€β”€ modals/                    # modalWrapper.tsx (global portal), sampleModal.tsx, common/sortingModal.tsx
β”‚   β”œβ”€β”€ auth/                      # AuthHydration.tsx
β”‚   └── common/                    # Shared micro-components
β”œβ”€β”€ store/                         # Zustand β€” one *.store.ts per domain
β”‚   β”œβ”€β”€ auth/ Β· user/ Β· adminUsers/ Β· filter/ Β· common/
β”‚   └── app.store.ts
β”œβ”€β”€ services/                      # Axios-based API clients
β”‚   β”œβ”€β”€ httpClient.service.ts       # Browser-side axios instance
β”‚   β”œβ”€β”€ httpServer.service.ts       # Server-side axios instance (SSR/route handlers)
β”‚   β”œβ”€β”€ auth/                       # auth.client.service.ts Β· auth.proxy.service.ts Β· auth.service.ts Β· socialAuth.client.service.ts
β”‚   β”œβ”€β”€ user/                       # user.client.service.ts Β· user.server.service.ts
β”‚   └── common/                     # common.server.service.ts Β· utils.service.ts
β”œβ”€β”€ constants/                     # routes, navbar/footer menu IDs, cookie keys, locale, image paths, regex
β”œβ”€β”€ data/layouts/                   # NAVBAR_MENU_CONFIG, footer link/social configs (consume constants/)
β”œβ”€β”€ hooks/                          # useInfiniteScroll, useIsMobileDevice, useModalScrollLock, usePageFilters, useSectionData, useTableUrlState
β”œβ”€β”€ utils/
β”‚   β”œβ”€β”€ common/                     # account, date, file-extension, service-error helpers
β”‚   β”œβ”€β”€ cookies/                    # client + server cookie helpers
β”‚   └── crypto/                     # cookie encryption
β”œβ”€β”€ functions/                      # renderEmptyValue, toQueryString, getDashboardHref, handleDestination, persistClientAuthSession
β”œβ”€β”€ config/                         # axiosInstance.config.ts
β”œβ”€β”€ providers/                      # antdConfigProvider.tsx
β”œβ”€β”€ layouts/                        # authLayout.tsx
β”œβ”€β”€ i18n/                           # request.ts (next-intl)
β”œβ”€β”€ assets/                         # icon.ts, svgIcons.tsx
β”œβ”€β”€ proxy.ts / proxy.server.ts       # Next.js API-route proxying to apps/server
└── styles/globals.css

Backend β€” apps/server ​

Express 5, layered routes β†’ controllers β†’ services β†’ dao, PostgreSQL via libs/models (Sequelize).

text
apps/server/src/
β”œβ”€β”€ main.ts                       # Entry point
β”œβ”€β”€ servers/http.server.ts         # HTTP server bootstrap
β”œβ”€β”€ routes/                        # auth Β· users Β· profile Β· parentalConsent Β· challenge Β· points Β· utils Β· routes.ts (aggregator)
β”œβ”€β”€ controllers/                   # One per route file above
β”œβ”€β”€ services/                      # auth Β· users Β· profile Β· parentalConsent Β· challenge Β· points Β· email Β· utils
β”œβ”€β”€ dao/                           # auth Β· users Β· userRole Β· refreshToken Β· userConsent Β· challenge Β· challengeInterest Β·
β”‚                                    challengeSubmission Β· deedSubmission Β· giftInterest Β· pointsWallet Β· userChallenge Β· walletTransaction
β”œβ”€β”€ migrations/                    # Umzug migration scripts + migrator.ts CLI
β”‚   └── scripts/                    # e.g. initial-schema, seed-roles, challenges-schema, points-schema, ...
β”œβ”€β”€ templates/                     # Email templates (parental consent, consent response)
β”œβ”€β”€ common/
β”‚   β”œβ”€β”€ middleware/                  # auth Β· permission Β· validation Β· rateLimit
β”‚   β”œβ”€β”€ constants/                   # errors Β· status(HTTP) Β· environment Β· points
β”‚   β”œβ”€β”€ enums/                       # order Β· sequelizeErrors
β”‚   β”œβ”€β”€ interfaces/                  # authenticatedRequest/-User Β· error Β· status Β· email
β”‚   β”œβ”€β”€ responses/                   # success.response.ts
β”‚   β”œβ”€β”€ handler/                     # cb / cbError response envelope
β”‚   └── types/
β”œβ”€β”€ config/                        # app.config.ts, jwt.config.ts, sql.config.ts
β”œβ”€β”€ loaders/                        # express.loader.ts, sql.loader.ts (DB connection)
β”œβ”€β”€ utils/                         # aws.utils.ts (S3/SES), winston.utils.ts, error.utils.ts, http.utils.ts
└── certificates/                   # RDS TLS CA bundle

Shared libraries β€” libs/ ​

libs/types β€” @workspace/types/* ​

Imported by client, server, and mobile. Organized by kind, then by domain:

text
libs/types/src/
β”œβ”€β”€ interfaces/    auth Β· user Β· common Β· layouts Β· challenge Β· points
β”œβ”€β”€ dto/           auth Β· user Β· common Β· utils Β· onboarding Β· challenge Β· points
β”œβ”€β”€ enums/         auth Β· user Β· common Β· challenge Β· points
β”œβ”€β”€ constants/api/ common Β· utils Β· auth Β· users Β· challenge Β· points Β· api.constants.ts (base paths)
└── responses/     login Β· logout Β· register Β· emailVerification Β· userStats

libs/ui β€” @workspace/ui/* (client-only) ​

Ant Design–based component library, three atomic tiers, each theme-tokenized under components/tokens/antd/:

  • Atoms (26): Badge, Breadcrumb, Button, Cascader, Checkbox, Divider, Dropdown, FallbackImage, Icon, IconButton, Input, Message, PopConfirm, Progress, QRCode, Radio, Rate, Select, Skeleton, Spin, Tag, Text, TextArea, TimeStampPicker, Toggle, Tooltip
  • Molecules (18): Alert, Card, Carousel, Drawer, Empty, Flex, Grid, Menu, Modal, Notification, Pagination, Popover, Result, Segmented, Steps, Tab, Tour, Upload
  • Organisms (3): Form (+ FormItem, FormList), Sider, Table

Plus hooks/ (useWindowSize), icons/ (shared SVG logos), utils/.

libs/models β€” @workspace/models (server-only) ​

text
libs/models/src/
β”œβ”€β”€ user.model.ts Β· auth.model.ts Β· userRole.model.ts Β· refreshToken.model.ts Β· userConsent.model.ts
β”œβ”€β”€ challenge.model.ts Β· challengeCategory.model.ts Β· challengeTask.model.ts Β· challengeSubmission.model.ts
β”œβ”€β”€ userChallenge.model.ts Β· userTaskProgress.model.ts
β”œβ”€β”€ challengeInterest.model.ts Β· giftInterest.model.ts
β”œβ”€β”€ deedSubmission.model.ts Β· pointsWallet.model.ts Β· walletTransaction.model.ts
└── index.ts   # Barrel export

libs/seo β€” @workspace/seo (client-only) ​

JSON-LD structured-data schema builders (article, breadcrumb, faq, organization, website) + metadata generators, consumed by apps/client's page components for SEO.


Infrastructure β€” libs/cdk ​

A standalone AWS CDK app (not built through Nx's normal app/lib pipeline β€” it has its own package.json, cdk.json, tsconfig.json) that provisions the environment apps/server and apps/client deploy onto:

text
libs/cdk/
β”œβ”€β”€ bin/                # cdk.ts (app entry), pipeline.ts
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ stacks/           # client Β· server Β· server-pipeline Β· pipeline Β· network Β· security Β·
β”‚   β”‚                      storage Β· common-resources Β· observability Β· config
β”‚   └── factories/        # app-factory.ts β€” wires stacks together per environment
β”œβ”€β”€ resources/           # Reusable constructs: acm, cloudwatch, db (RDS), ec2, ecr, ecs,
β”‚                          iam, policies, s3, security-groups, ssm, vpc, waf
β”œβ”€β”€ config/              # demo / dev / staging / prod environment configs (JSON)
└── src/interfaces/       # repo, securityGroups, serverConfig, config interfaces

Deploys: VPC + security groups β†’ RDS (Postgres) β†’ ECR + ECS (server) β†’ ALB + WAF β†’ CloudWatch alarms, with separate CodePipeline stacks for client and server CI/CD.


Path aliases ​

Defined once in tsconfig.base.json, available to every app/lib in the workspace.

AliasResolves toUsed by
@client/*apps/client/src/*Client
@workspace/server/*apps/server/src/*Server
@workspace/models / @workspace/models/*libs/models/src/*Server
@workspace/types/constants/*libs/types/src/constants/*Client Β· Server Β· Mobile
@workspace/types/dto/*libs/types/src/dto/*Client Β· Server Β· Mobile
@workspace/types/enums/*libs/types/src/enums/*Client Β· Server Β· Mobile
@workspace/types/interfaces/*libs/types/src/interfaces/*Client Β· Server Β· Mobile
@workspace/types/responses (/*)libs/types/src/responses/*Client Β· Server
@workspace/ui/components/{atoms,molecules,organisms}/*libs/ui/src/components/ui-lib/antd/*Client
@workspace/ui/hooks/* Β· @workspace/ui/utils/*libs/ui/src/{hooks,utils}/*Client
@workspace/seo (/*)libs/seo/src/*Client

Mobile (apps/mobile) resolves @workspace/types/* the same way but uses its own @/lib/* / @/features/* aliases for app-local code β€” see mobile project structure.


Tech stack ​

LayerLibraryVersion
MonorepoNx20.7.1
LanguageTypeScript5.8.3 (client/server)
Frontend frameworkNext.js16.2.4 (Turbopack)
Frontend frameworkReact19.1.4
UI libraryAnt Design6.3.7
StylingTailwind CSS4.2.4
Client stateZustand5.0.3
i18nnext-intl4.11.0
HTTPaxios1.15.2
Backend frameworkExpress5.1.0
ORMSequelize / sequelize-typescript6.37.8 / 2.1.6
DatabasePostgreSQL (pg)8.13.1
AuthPassport.js + jsonwebtoken0.7.0 / 9.0.2
MigrationsUmzug3.8.3
LoggingWinston3.17.0
Cloud SDK@aws-sdk/client-s3, client-ses3.980.0
ValidationZod4.3.5
Rate limitingexpress-rate-limit8.5.2
InfraAWS CDKsee libs/cdk/package.json
TestingJest / Playwright / Testing Library29.7.0 / 1.36.0 / β€”
ToolingESLint + Prettier, Husky, Yarn 1.22.22β€”

Touli Β· keep this file (and docs/mobile/project-structure.md) in sync when app/lib structure changes