Welcome to
Skip to main content
Home/Documentation/Architecture

Architecture

System Overview

Hub Digital follows a modern JAMstack-like architecture with server-side rendering, integrated with an AI-powered search and assistant layer orchestrated by Langflow:

System Overview

Key Architectural Decisions

  1. Server-Side Rendering (SSR) — Pages are rendered on the server for SEO and initial load performance
  2. API Proxy — All Directus API calls go through Nuxt's Nitro server (/api/proxy/) to handle auth and avoid CORS
  3. Domain-Driven Modules — Features are organized into self-contained modules
  4. Shared Packages — Common code (types, utils, validation, i18n) is extracted into workspace packages

Monorepo Structure

hub-digital-ui/
├── apps/web/            # Main Nuxt 3 application
├── packages/
│   ├── i18n/            # Translation files (pt.json, en.json)
│   ├── logs/            # Logging utilities
│   ├── types/           # Shared TypeScript type definitions
│   ├── utils/           # Shared utility functions
│   └── validation/      # Shared validation schemas (Zod)
├── tooling/
│   ├── eslint/          # ESLint config preset
│   ├── tailwind-config/ # Tailwind CSS base theme
│   └── typescript/      # Shared tsconfig base
├── config.ts            # Global app configuration
├── turbo.json           # Turborepo pipeline
└── pnpm-workspace.yaml  # Workspace packages

Package Dependencies

web
├── types          (shared TypeScript types)
├── utils          (utility functions)
├── validation     (Zod schemas)
├── tsconfig       (TypeScript base config)
└── tailwind-config (Tailwind base theme)
     └── i18n      (translation files loaded at runtime)

Module Architecture

The web app uses a domain-driven module architecture under apps/web/modules/. Each module is self-contained and typically includes:

modules/<feature>/
├── components/     # Vue SFC components
├── composables/    # Reactive composition functions
├── constants.ts    # Static configuration values
└── types.ts        # Module-specific TypeScript types

Module Registry

ModuleResponsibility
authLogin, signup, password reset UI components
accountProfile editing, security settings, invitations
analyticsAnalytics provider abstraction (Plausible, GA, etc.)
catalogCourse/resource/tool listing, search, filtering
dashboardUser dashboard, stats, achievements, leaderboard
directusCustom Nuxt module wrapping the Directus SDK
marketingLanding pages, blog, changelog, docs rendering
sharedCross-cutting components (search bar, icons, etc.)
suggest-resourceMulti-step resource submission wizard
suggest-toolMulti-step tool submission wizard
uishadcn-vue component library (buttons, forms, etc.)

Auto-Import Configuration

All module paths are registered in nuxt.config.ts under imports.dirs (composables) and components (Vue components). This means you never need to manually import components or composables — they're globally available.


Data Flow

Client → Server → Directus

Vue Component
  └─▶ Pinia Store (action)
       └─▶ $directus.request(...)
            └─▶ Directus SDK (fetch)
                 └─▶ /api/proxy/[...] (Nitro handler)
                      └─▶ Directus REST API
  1. Components dispatch actions on Pinia stores
  2. Stores use the Directus SDK via useNuxtApp().$directus
  3. The SDK is configured to route requests through /api/proxy/
  4. The proxy handler (server/api/proxy/[...].ts) forwards requests to the Directus backend, managing headers and cookies

Authentication Flow

Login Form → authStore.login() → Directus SDK login
  → Proxy → Directus /auth/login
  → Tokens stored in cookies
  → authStore.fetchUser() → /users/me with fields
  → User data stored in Pinia state

The Directus module provides:

  • useDirectusAuth() — Login, logout, token refresh
  • useDirectusUser() — Current user data
  • Auth middleware — Route protection for authenticated pages

AI & Assistant Integration

The AI chat assistant (Toti) is integrated as a core architectural feature, bridging the user interface, custom backend endpoints, and vector search capabilities:

AI Data Flow

Vue Component (Chat UI)
  └─▶ useChat Composable / chatStore
       └─▶ /api/proxy/ai-chat (Nitro proxy)
            └─▶ Directus Custom Endpoint (/ai-chat)
                 └─▶ Langflow Orchestrator
                      ├─▶ Intent Router (JSON output)
                      ├─▶ Qdrant Vector DB (retrieval with filters)
                      └─▶ LLM API (Azure OpenAI / Ollama generation)
  1. Directus /ai-chat Endpoint: A custom Node.js extension in hub-digital-admin that forwards incoming queries to the Langflow orchestration flow.
  2. Langflow Agent Orchestration: Langflow is used as the node-based visual orchestration framework to chain together intent classification, vector retrieval (Qdrant), web search APIs, and LLM prompting.
  3. Qdrant Vector Storage: Directus webhook operations (qdrant-upsert-operation, qdrant-delete-operation) synchronize catalog data (courses, resources, tools, best practices, case studies, pedagogical methods) into Qdrant. The Langflow pipeline queries Qdrant to retrieve relevant items based on semantic similarity.
  4. Intent Router: A fast LLM-based router configured within Langflow classifies the query into one of three execution paths:
    • Clarification: Prompts the user for details when the query is ambiguous.
    • Restricted: Internal Qdrant catalog lookup only (for courses and communities).
    • Hybrid: Internal catalog lookup with optional search-based enrichment (for tools, resources, best practices, etc.).
  5. Large Language Model (LLM): Integrates with Azure OpenAI (production) or Ollama (local development) through Langflow nodes, using system prompt guidelines that strictly prioritize internal catalog references.

UI Component Library

The project uses shadcn-vue for its component library, installed at modules/ui/components/. Currently available components include:

accordion, alert, alert-dialog, avatar, badge, breadcrumb, button, card, carousel, checkbox, collapsible, combobox, dialog, dropdown-menu, form, hover-card, input, label, pagination, popover, progress, range-calendar, scroll-area, select, separator, sheet, star-rating, table, tabs, tags-input, textarea, toast, tooltip

Additionally, a set of custom AI chat components are available under modules/ui/components/ai-elements/.


Layouts

LayoutFileUse Case
marketinglayouts/marketing.vuePublic pages: home, blog, docs, legal
authlayouts/auth.vueAuthentication pages
applayouts/app.vueAuthenticated app pages
cataloglayouts/catalog.vueCatalog browsing
defaultlayouts/default.vueFallback

Content System

Static content is managed via Nuxt Content v3 with the following collections defined in content.config.ts:

CollectionSourceSchema
legalcontent/legal/*.mdStandard SEO collection
coursescontent/catalog/courses/*.mdName, description, instructors, etc.
resourcescontent/catalog/resources/*.mdTitle, description, license, tags
toolscontent/catalog/tools/*.mdTitle, category, type, authors

Documentation pages (like this one) use a custom rendering system in modules/marketing/content/ that supports:

  • Multi-locale content (.md and .pt.md files)
  • Hierarchical navigation via meta.json files
  • Table of contents generation
  • Markdown rendering with syntax highlighting