tahamajs/IE / Projects /docs /AppStore.md
tahamajs's picture
|
download
raw
318 kB
# Research Platform – Complete Documentation
**Version 1.0.0** – A full‑featured, desktop‑style research collaboration environment with real‑time messaging, collaborative document editing, AI‑assisted research tools, and an extensible plugin/app store.
---
## 📋 Table of Contents
- [Overview](#overview)
- [Key Features](#key-features)
- [Architecture](#architecture)
- [Getting Started](#getting-started)
- [Project Structure](#project-structure)
- [Core Components](#core-components)
- [Feature Modules](#feature-modules)
- [App Store & Plugin System](#app-store--plugin-system)
- [API Integration](#api-integration)
- [Security & Permissions](#security--permissions)
- [Performance & Optimization](#performance--optimization)
- [Deployment](#deployment)
- [Contributing & Developer Guide](#contributing--developer-guide)
- [Troubleshooting](#troubleshooting)
- [Future Roadmap](#future-roadmap)
---
## Overview
The **Research Platform** is a full‑stack, desktop‑style web application designed for researchers to collaborate, publish, manage lab work, and extend functionality through custom plugins and apps. It combines real‑time messaging, collaborative editing (Yjs), a knowledge graph for research gaps, grant assistance, peer review, lab inventory, and an **App Store** where users can create and share lightweight HTML/JS/CSS tools.
The frontend is built with **React 19**, **TypeScript**, **Vite**, and **Tailwind CSS**, featuring a **window manager** (draggable, resizable windows with taskbar and start menu) that mimics a desktop operating system. The backend (Java Spring Boot) provides REST APIs and WebSocket for real‑time features.
---
## Key Features
| Category | Features |
|----------|----------|
| **Authentication & User Management** | Login, registration, 2FA (TOTP), password reset with security questions, profile editing, follow system |
| **Articles & Publications** | Create, edit, publish, search, like, comment, analytics (views/likes/comments), citation export (APA/MLA/BibTeX), graph‑based recommendations |
| **Messaging** | Private & group chats, threads, polls, voice messages, stickers, scheduled messages, global search, read receipts, typing indicators, secret chats (E2EE stubbed) |
| **Collaborative Editor** | Real‑time document editing with Yjs, LaTeX math, code blocks, tables, task lists, live preview, citation picker, export (PDF/DOCX/LaTeX/HTML) |
| **Paper Collections** | Organise articles into custom collections (public/private) |
| **Reference Manager** | Import references from DOI, BibTeX, Zotero, Mendeley; insert citations into editor |
| **Preprint Submission** | Upload manuscript, AI screening, DOI assignment |
| **Provenance / Trust** | Audit trail of actions, chain verification (integrity check) |
| **Unified Inbox** | Aggregated messages from all sources (private, groups, projects, AI, broadcasts) with filters |
| **Lab Inventory** | Manage chemicals, barcode scanning, low‑stock alerts, NFPA diamond, compatibility checker |
| **Peer Review** | Submit papers, claim reviews, anonymous review with scores, reviewer credentials |
| **Gap Analysis** | Knowledge graph (ForceGraph2D) of papers/concepts/gaps, AI‑powered gap detection |
| **Grant Assistant** | Deadlines, RFP analysis, draft generation (AI) |
| **Data Hub** | Research objects, lab protocols, preregistrations with DOI |
| **Projects & Tasks** | Kanban board, members, outputs |
| **Events & Networking** | Create events, RSVP, calendar export (iCal) |
| **Workspace (Desktop)** | Window manager with taskbar, start menu, resizable windows, desktop icons, keyboard shortcuts |
| **Voice Assistant** | Speech recognition, TTS, wake word (stub) |
| **Smart Notifications** | Real‑time bell, batching, quiet hours, deep work mode |
| **Admin Dashboard** | Manage users, articles, RAG documents, platform stats |
| **Offline Support** | IndexedDB persistence for collaborative editor, PWA (service worker) |
| **App Store / Plugin System** | Users can create, share, install HTML/CSS/JS apps that run in sandboxed iframes; visual no‑code builder (planned) |
---
## Architecture
The platform follows a **modular monolith** backend and a **feature‑based frontend** with a **desktop window manager**.
### High‑level Diagram
```
[Browser] ←→ [Frontend (React + Vite)] ←→ [Backend (Java Spring Boot)]
↕ ↕
[Window Manager] [PostgreSQL]
↕ ↕
[Sandboxed iframe] [WebSocket]
(plugins/apps)
```
### Frontend Technologies
| Area | Technologies |
|------|--------------|
| Core | React 19, TypeScript, Vite, React Router DOM |
| Styling | Tailwind CSS, CSS Modules, glass‑morphism |
| State | React Context (auth, theme), custom hooks, Zustand (optional) |
| Real‑time | WebSocket (native), Yjs, y‑websocket, y‑indexeddb |
| Editor | TipTap (ProseMirror), Yjs collaboration, LaTeX (KaTeX) |
| Window Manager | `react‑draggable`, `react‑resizable`, `framer‑motion` |
| Charts | Recharts, D3 |
| Graph | react‑force‑graph‑2d |
| Media | PDF.js, mammoth (DOCX), html2canvas, jspdf |
| Voice | Web Speech API, react‑speech‑recognition |
| PWA | `vite‑plugin‑pwa` |
### Backend (Conceptual – Java Spring Boot)
- REST APIs with JWT authentication
- WebSocket (`/ws`) for messaging, typing, notifications
- Yjs WebSocket server on port 9093 for collaboration
- PostgreSQL database with JDBC repositories
- File storage (AWS S3 or local) for uploads
- Email service (JavaMail)
- AI integration (OpenAI / local LLM via REST)
---
## Getting Started
### Prerequisites
- Node.js 20+ and npm/pnpm
- Java 17+ (for backend)
- PostgreSQL 14+ (or your preferred DB)
- Redis (optional, for caching/rate limiting)
### Installation (Frontend)
```bash
# Clone the repository
git clone https://github.com/your-org/research-platform.git
cd research-platform/front
# Install dependencies
npm install
# Copy environment variables
cp .env.example .env
# Edit .env with your backend URLs
# Start development server
npm run dev
```
### Environment Variables (`.env`)
```env
VITE_API_BASE_URL=http://localhost:8080/api
VITE_WS_URL=ws://localhost:8080/ws
VITE_COLLAB_WS_URL=ws://localhost:9093
```
### Backend Quick Start (see separate backend repo)
```bash
cd backend
./mvnw spring-boot:run
```
### Run with Docker Compose (both frontend + backend + DB)
```yaml
# docker-compose.yml (provided in backend repo)
```
---
## Project Structure
```
src/
├── api/ # API client modules (REST calls)
│ ├── client.ts # Axios instance with JWT refresh
│ ├── auth.ts
│ ├── articles.ts
│ ├── messages.ts
│ ├── users.ts
│ ├── collections.ts
│ ├── references.ts
│ ├── preprints.ts
│ ├── provenance.ts
│ ├── rag.ts
│ ├── admin.ts
│ ├── plugins.ts # App store API
│ └── index.ts
├── components/
│ ├── ui/ # Reusable UI primitives
│ │ ├── GlassCard.tsx
│ │ ├── Skeleton.tsx
│ │ ├── LoadingSkeleton.tsx
│ │ ├── AnimatedBackground.tsx
│ │ └── ParticleBackground.tsx
│ ├── desktop/ # Window manager
│ │ ├── WindowContainer.tsx
│ │ ├── DesktopWindow.tsx
│ │ ├── Taskbar.tsx
│ │ ├── StatusBar.tsx
│ │ └── index.ts
│ ├── workspace/
│ │ ├── SmartGlassWorkspace.tsx
│ │ └── PanelManager.tsx
│ ├── collaboration/
│ │ └── ScientificEditor.tsx
│ ├── messages/ # Chat components
│ ├── collections/ # Paper collections UI
│ ├── references/ # Reference manager UI
│ ├── preprint/ # Preprint submission UI
│ ├── provenance/ # Provenance timeline
│ ├── unified-chat/ # Inbox filter bar
│ ├── admin/ # Admin tables
│ ├── dashboard/ # Dashboard widgets
│ ├── article/ # Article card, markdown renderer
│ ├── voice/ # Voice assistant widget
│ ├── notifications/ # Notification center
│ ├── app-store/ # App store & plugin components
│ │ ├── AppCard.tsx
│ │ ├── AppEditor.tsx
│ │ ├── AppRunner.tsx
│ │ └── PluginStorePage.tsx
│ └── ...
├── pages/ # Route pages (25+)
├── hooks/ # Custom hooks (50+)
├── lib/ # Core libraries (auth, api, websocket, secret chat)
├── services/ # Business logic services
├── security/ # JWT, CSRF, sanitize, rate limiting
├── audit/ # Audit logger
├── utils/ # File, date, string, error helpers
├── config/ # Constants, env helpers
├── seo/ # Site metadata
├── workers/ # Web workers (RAG)
├── styles/ # Global CSS (glass, animations)
├── types/ # TypeScript re‑exports
├── App.tsx
├── main.tsx
├── vite-env.d.ts
└── index.css
```
---
## Core Components
### Desktop Window Manager
- **`WindowContainer`**: Global state (open/close/minimize/maximize/z‑index). Exposes `useWindowManager` hook.
- **`DesktopWindow`**: Draggable, resizable window with title bar, icon, and control buttons.
- **`Taskbar`**: Start menu, open window icons, system tray (clock).
- **`StatusBar`**: Top bar with Wi‑Fi, battery, volume (mock).
**Usage**:
```tsx
const { openWindow } = useWindowManager();
openWindow('My App', <MyComponent />, { width: 800, height: 600 });
```
### Collaborative Editor (`ScientificEditor`)
- Built on TipTap + Yjs.
- Real‑time collaboration with peers (cursors, presence).
- LaTeX math (KaTeX), code highlighting, tables, task lists.
- Live preview (HTML with rendered math).
- Export to PDF, DOCX, LaTeX, HTML.
- Citation picker (integrates with Reference Manager).
- Offline support via IndexedDB.
### Messaging (`ChatArea`, `MessageBubble`)
- Private & group chats.
- Attachments (images, videos, files).
- Reactions (emojis).
- Reply to messages, threads.
- Edit/delete/forward (single or multi‑select).
- Voice messages, stickers, polls.
- Scheduled messages.
- Global search (`Ctrl+K`).
### Window Manager Events
- `openWindow` (custom event) – launch any app from anywhere.
- `closeWindow` – close current window.
- Desktop icons for installed apps.
---
## Feature Modules
### Paper Collections
- **Pages**: `CollectionsPage`, `CollectionDetailPage`
- **Modals**: `CreateCollectionModal`, `AddToCollectionModal`
- **Hook**: `usePaperCollections`
- **Backend**: `/api/collections/*`
### Reference Manager
- **Pages**: `ReferenceManagerPage`
- **Modals**: `ReferenceImportModal` (DOI, BibTeX, Zotero, Mendeley)
- **Picker**: `ReferencePicker` (inserts `\cite{key}` into editor)
- **Hook**: `useReferenceManager`
### Preprint Submission
- **Page**: `PreprintSubmissionPage`
- **Component**: `ScreeningResultCard`
- **Hook**: `usePreprintSubmission`
- **Backend**: `/api/preprints/screen`, `/api/preprints/submit`
### Provenance (Trust)
- **Components**: `ProvenanceTimeline`, `VerifyChainButton`
- **Hook**: `useProvenance`
- **Integration**: Button in `ArticleDetailPage` opens modal.
### Unified Inbox
- **Page**: `UnifiedInboxPage`
- **Filter bar**: `InboxFilterBar` (tabs: all, unread, critical, direct, groups, projects, papers, AI, broadcasts)
- **Hook**: `useUnifiedInbox`
- **Backend**: `/api/unified-inbox`
### Scheduled Messages
- **Modal**: `ScheduleModal` (datetime picker)
- **Panel**: `ScheduledMessagesPanel` (list, cancel)
- **Integration**: Calendar button in `ChatArea`, clock icon in `MessagesPage`.
### Global Search Modal
- **Component**: `GlobalSearchModal`
- **Keyboard shortcut**: `Ctrl+K`
- **Backend**: `/api/conversations/search`, `/api/groups/{id}/search`
- **Integration**: Button in `MessagesPage`.
### Admin Dashboard
- **Page**: `AdminPage`
- **Tables**: `UserTable`, `ArticleTable`, `RagDocTable`
- **Hooks**: `useAdminStats`
- **Backend**: `/api/admin/*`
### Offline Support
- **Collaborative editor**: `IndexeddbPersistence` from `y‑indexeddb`
- **PWA**: `vite-plugin-pwa`, service worker registration.
- **Status**: `OfflineSyncStatus` component.
---
## App Store & Plugin System
Users can build, share, and install HTML/CSS/JS applications that run inside the desktop environment.
### How It Works
1. **Developer** writes a self‑contained HTML file (HTML, CSS, JS).
2. **Uploads** to the platform via the **App Editor** (simple textarea or file upload).
3. **Admin approves** (or auto‑approve for trusted users).
4. **Other users** browse the **App Store**, click “Install”.
5. Installed apps appear as **desktop icons**.
6. **Launch** opens a new window with a sandboxed `iframe` that runs the HTML code.
### Security
- Each app runs in an `<iframe>` with `sandbox="allow-same-origin allow-scripts allow-popups allow-forms"`.
- No access to parent page DOM, cookies, or localStorage.
- API calls must go through `postMessage` (optional – can be extended).
### Creating an App
**Minimal example**:
```html
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>My Tool</title></head>
<body>
<h1>Hello Research!</h1>
<button onclick="fetch('/api/articles/trending').then(r=>r.json()).then(console.log)">Fetch</button>
</body>
</html>
```
**Upload via App Editor**:
- Name, description, icon (optional), HTML code.
### Visual No‑Code Builder (Planned)
- Drag‑and‑drop UI builder.
- Property panels for each component.
- Visual workflow editor (node‑graph) for logic.
- Generates JSON blueprint → backend → code → deployment.
---
## API Integration
All frontend API calls are organized in `src/api/`. Example:
```ts
import { articleApi } from '@/api/articles';
const articles = await articleApi.getAll({ page: 1, limit: 20 });
```
### WebSocket Events
| Event Type | Description |
|------------|-------------|
| `new_message` | New private message |
| `new_group_message` | New group message |
| `typing` | User is typing |
| `message_status` | Delivered/seen status |
| `reaction` | Emoji reaction added/removed |
| `message_edited` | Message content edited |
| `message_deleted` | Message soft‑deleted |
| `message_pinned` | Pin/unpin group message |
| `new_notification` | Real‑time bell notification |
| `presence` | Online/offline status |
---
## Security & Permissions
| Layer | Measures |
|-------|----------|
| **Authentication** | JWT (access + refresh tokens), httpOnly cookie for refresh |
| **2FA** | TOTP (Google Authenticator), backup codes |
| **CSRF** | Token in meta tag, verified on state‑changing requests |
| **Rate Limiting** | Token bucket (client‑side stub) – backend recommended |
| **Sanitization** | DOMPurify for user‑generated HTML |
| **Sandbox** | iframe sandbox for third‑party apps |
| **Audit Log** | All critical actions logged (auditLogger.ts) |
---
## Performance & Optimization
- **Lazy loading**: All pages and heavy components are lazy‑loaded (`React.lazy`).
- **Memoization**: `useMemo`, `useCallback`, `React.memo` for expensive renderers.
- **Virtualization**: Planned for long lists (messages, articles) – `react‑virtuoso`.
- **Asset caching**: Service worker caches static assets (PWA).
- **Code splitting**: Vite automatically splits chunks.
- **Image lazy loading**: `loading="lazy"` on images.
---
## Deployment
### Build for Production
```bash
npm run build
# Output: dist/ folder
```
### Serve with Nginx (example)
```nginx
server {
listen 80;
server_name research.yourdomain.com;
root /var/www/research-platform/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://localhost:8080;
}
location /ws {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```
### Dockerfile
```dockerfile
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
```
### Environment Variables for Production
- `VITE_API_BASE_URL=https://api.research.yourdomain.com`
- `VITE_WS_URL=wss://api.research.yourdomain.com/ws`
- `VITE_COLLAB_WS_URL=wss://collab.research.yourdomain.com`
---
## Contributing & Developer Guide
### Adding a New Feature
1. Create feature branch from `main`.
2. Implement using the existing patterns:
- API calls in `src/api/`
- Hook in `src/hooks/`
- Components in `src/components/features/`
- Page in `src/pages/`
- Add route in `App.tsx`
3. Write tests (Jest + React Testing Library).
4. Submit pull request.
### Code Style
- ESLint (React Hooks, TypeScript)
- Prettier
- Tailwind CSS for styling
### Building a New Desktop App
- Add entry to `DESKTOP_APPS` in `SmartGlassWorkspace.tsx`.
- Provide component (or page).
- If the app needs to be installed, use the App Store mechanism.
---
## Troubleshooting
### Common Issues
| Issue | Likely Cause | Solution |
|-------|--------------|----------|
| WebSocket not connecting | Wrong `VITE_WS_URL` | Check .env, ensure backend WebSocket is running |
| Collaborative editor not syncing | Yjs WebSocket port 9093 not running | Start `y-websocket` server |
| PWA not installing | Missing icons or wrong manifest | Add `icon-192.png`, `icon-512.png` to `public/` |
| iframe sandbox blocks scripts | Missing `allow-scripts` | Add `allow-scripts` to sandbox attribute |
| Messages not loading | AbortController race condition | Fetch aborts properly; ensure `loadMessagesForSelected` is memoized |
### Debugging
- **React DevTools**: Inspect component tree, state, props.
- **Network tab**: Check API calls, WebSocket frames.
- **Console**: Look for errors in plugin code (if any).
- **LocalStorage**: View persisted token, app data.
---
## Future Roadmap
| Milestone | Description |
|-----------|-------------|
| **v1.1** | Complete offline queue for messages; extend PWA caching. |
| **v1.2** | Visual no‑code app builder (drag‑drop UI, workflow editor). |
| **v1.3** | AI agents (autonomous research tasks). |
| **v1.4** | Multi‑language support (i18n). |
| **v1.5** | Mobile‑optimized view (responsive desktop windows). |
| **v2.0** | Full secret chat with Signal protocol (Double Ratchet). |
---
## License
MIT © IE Research Team
---
## Acknowledgments
- [Yjs](https://yjs.dev/) – CRDTs for collaboration
- [TipTap](https://tiptap.dev/) – Headless editor framework
- [react‑force‑graph‑2d](https://github.com/vasturiano/react-force-graph) – Knowledge graph visualisation
- [Tailwind CSS](https://tailwindcss.com/)
- [Lucide Icons](https://lucide.dev/)
- [Framer Motion](https://www.framer.com/motion/)
---
*This documentation is a living document. For the most up‑to‑date information, refer to the source code and the project’s GitHub wiki.*
---
## 📁 1. Project Structure (Complete Deep Dive)
The `src/` directory is organised into logical layers, ensuring separation of concerns, reusability, and scalability.
### 1.1 `api/` – REST Communication Layer
This folder contains modules that encapsulate all backend API calls. Each module corresponds to a backend controller.
| File | Purpose | Key Functions |
|------|---------|----------------|
| `client.ts` | Axios instance with JWT refresh logic, error handling, CSRF token injection. | Interceptors for adding `Authorization` header, refreshing token on 401. |
| `auth.ts` | Authentication endpoints | `login`, `logout`, `register`, `refreshToken`, `getMe`, `changePassword`, `forgotPassword`, `resetPassword`, `enable2FA`, `verify2FA`, etc. |
| `articles.ts` | Article CRUD + search + analytics + recommendations | `getAll`, `getById`, `create`, `update`, `delete`, `like`, `comment`, `search`, `getAnalytics`. |
| `messages.ts` | Private & group messaging | `getConversations`, `getMessages`, `sendMessage`, `editMessage`, `deleteMessage`, `addReaction`, `sendTyping`, `markAsRead`, `archive`, `scheduleMessage`, `getScheduledMessages`, group‑specific endpoints. |
| `users.ts` | User profiles, follow, contacts | `getProfile`, `follow`, `unfollow`, `getFollowers`, `getFollowing`, `getContacts`, `uploadAvatar`. |
| `collections.ts` | Paper collections | `getAll`, `create`, `delete`, `addPaper`, `removePaper`. |
| `references.ts` | Reference manager | `getForDocument`, `add`, `update`, `delete`, `importFromDOI`, `importBibTeX`, `connectZotero`, `connectMendeley`. |
| `preprints.ts` | Preprint submission | `screen`, `submit`. |
| `provenance.ts` | Provenance / trust | `get`, `verify`. |
| `rag.ts` | RAG assistant | `chat`, `indexDocument`, `getDocuments`, `deleteDocument`, `getConversation`, `clearConversation`. |
| `admin.ts` | Admin endpoints | `getStats`, `getUsers`, `deleteUser`, `updateUserRole`, `getArticles`, `deleteArticle`, `getRagDocuments`, `deleteRagDocument`. |
| `plugins.ts` | App store / plugins | `getAll`, `getById`, `submit`, `install`, `getInstalled`. |
| `index.ts` | Barrel export – re‑exports all modules for convenient imports. |
**Why this structure?**
- Each module is small and focused – easy to test and maintain.
- Changes to one endpoint family don't affect others.
- The barrel file (`index.ts`) allows importing like `import { articleApi } from '@/api'`.
---
### 1.2 `components/` – Reusable UI Building Blocks
The `components/` directory is split by domain/feature, plus a `ui/` folder for truly generic components.
| Subdirectory | Purpose | Key Files |
|--------------|---------|------------|
| `ui/` | Highly reusable, style‑only or behaviour‑only components | `GlassCard.tsx` (frosted glass card with hover animation), `Skeleton.tsx` (shimmer placeholder), `LoadingSkeleton.tsx` (multiple variants), `AnimatedBackground.tsx` (canvas particles), `ParticleBackground.tsx` (alternative). |
| `desktop/` | **Window manager** (explained in detail below) | `WindowContainer.tsx`, `DesktopWindow.tsx`, `Taskbar.tsx`, `StatusBar.tsx`, `index.ts`. |
| `workspace/` | Desktop environment integration | `SmartGlassWorkspace.tsx` (main desktop), `PanelManager.tsx` (renders panel content inside windows). |
| `collaboration/` | Real‑time editor | `ScientificEditor.tsx`. |
| `messages/` | Chat UI | `ChatSidebar.tsx`, `ChatArea.tsx`, `MessageBubble.tsx`, `ScheduleModal.tsx`, `ScheduledMessagesPanel.tsx`, `GlobalSearchModal.tsx`, `VoiceMessageRecorder.tsx`, etc. |
| `collections/` | Paper collections UI | `CollectionCard.tsx`, `CreateCollectionModal.tsx`, `AddToCollectionModal.tsx`. |
| `references/` | Reference manager UI | `ReferenceImportModal.tsx`, `ReferencePicker.tsx`. |
| `preprint/` | Preprint submission UI | `ScreeningResultCard.tsx`. |
| `provenance/` | Trust UI | `ProvenanceTimeline.tsx`, `VerifyChainButton.tsx`. |
| `unified-chat/` | Inbox filters | `InboxFilterBar.tsx`, `InboxMessageCard.tsx`. |
| `admin/` | Admin panel tables | `UserTable.tsx`, `ArticleTable.tsx`, `RagDocTable.tsx`. |
| `dashboard/` | Dashboard widgets | `widgets/StatCard.tsx`, `ViewsChart.tsx`, `RecentArticlesList.tsx`. |
| `article/` | Article display components | `ArticleCard.tsx`, `MarkdownRenderer.tsx`. |
| `voice/` | Voice assistant UI | `VoiceAssistantWidget.tsx`, `VoiceSettingsModal.tsx`, `VoiceMessageRecorder.tsx`. |
| `notifications/` | Notification centre | `SmartNotificationCenter.tsx`, `NotificationItem.tsx`. |
| `app-store/` | Plugin/app store | `AppCard.tsx`, `AppEditor.tsx`, `AppRunner.tsx`, `PluginStorePage.tsx`. |
**Why this structure?**
- Feature folders keep related components close together.
- Shared UI primitives are in `ui/`, reducing duplication.
- Desktop‑specific code is isolated in `desktop/` and `workspace/`.
---
### 1.3 `pages/` – Route Pages
Each file corresponds to a route (lazy‑loaded). Examples:
| File | Route | Description |
|------|-------|-------------|
| `HomePage.tsx` | `/` | Landing page with animated background, call to action. |
| `LoginPage.tsx` | `/login` | Glass‑form login with 2FA support. |
| `RegisterPage.tsx` | `/register` | Registration with password strength meter. |
| `DashboardPage.tsx` | `/dashboard` | Stats cards, charts, recent articles. |
| `ArticlesPage.tsx` | `/articles` | Article list with search/filter, infinite scroll. |
| `ArticleDetailPage.tsx` | `/articles/:id` | Full article view, comments, likes, provenance button. |
| `MessagesPage.tsx` | `/messages` | Unified messaging (both private and groups). |
| `UnifiedInboxPage.tsx` | `/inbox` | Aggregated inbox with filter bar. |
| `CollectionsPage.tsx` | `/collections` | List of paper collections. |
| `CollectionDetailPage.tsx` | `/collections/:id` | Single collection with papers. |
| `ReferenceManagerPage.tsx` | `/references/:docId` | Manage references for a document. |
| `PreprintSubmissionPage.tsx` | `/submit-preprint` | Submit preprint with AI screening. |
| `LikedArticlesPage.tsx` | `/liked-articles` | Articles liked by the user. |
| `AdminPage.tsx` | `/admin` | Admin dashboard with user/article/RAG tables. |
| `SettingsPage.tsx` | `/settings` | User settings (profile, security, notifications, appearance). |
| `ProfilePage.tsx` | `/profile` | View own profile. |
| `GroupsPage.tsx` | `/groups` | List of research groups. |
| `NotFound.tsx` | `*` | 404 page. |
**Why lazy loading?**
- Reduces initial bundle size.
- Pages are loaded only when the user navigates to them.
---
### 1.4 `hooks/` – Custom Hooks
Over 50 custom hooks encapsulating business logic, data fetching, and state management. Examples:
| Hook | Purpose |
|------|---------|
| `useAuth` | Authentication state, login, logout, token refresh. |
| `useArticles` | Fetch articles with pagination, search, filter. |
| `useMessaging` | Chat state, send messages, reactions, threads, scheduling, archive. |
| `usePaperCollections` | Manage user collections. |
| `useReferenceManager` | Import, delete, insert citations. |
| `usePreprintSubmission` | Screen and submit preprints. |
| `useProvenance` | Fetch events and verify integrity. |
| `useUnifiedInbox` | Aggregated messages from all sources. |
| `useCollaborativeEditor` | Yjs document, WebSocket, offline persistence, export. |
| `useSecuritySettings` | 2FA, password change, security question. |
| `useRegister` | Registration form with password strength. |
| `usePasswordReset` | Security question based password reset. |
| `useProfile` | Fetch and update user profile. |
| `useSearch` | Search articles with URL parameters. |
| `useWebSocket` | WebSocket connection management. |
| `useVoiceAssistant` | Speech recognition, TTS, wake word. |
| `useRagSystem` | Document indexing, AI chat, source citations. |
| `useNotifications` | Fetch, mark read, delete notifications. |
| `useSmartNotifications` | Batching, quiet hours, deep work mode. |
| `useDragDropOverlay` | Detect file drag over window. |
| `useLocalNotificationClassifier` | AI priority prediction (stub). |
| `useNetworkQuality` | Detect effective network type (4G, 3G, etc.). |
| `useProjectSpace` | Project details, members, outputs. |
| `useProjectTaskManager` | Kanban board tasks. |
| `useLabInventory` | Chemicals, alerts, barcode scanning. |
| `usePeerReview` | Submissions, reviews, credentials. |
| `useGapAnalysis` | Knowledge graph nodes/edges, AI gap detection. |
| `useGrantAssistant` | Grant deadlines, RFP analysis. |
| `useEventHosting` | Events, RSVPs, reminders. |
| `useWorkspace` / `useSmartGlassWorkspace` | Workspace panels, presets. |
| `useDataHub` | Research objects, protocols, preregistrations. |
**Why custom hooks?**
- Business logic is separated from UI components → easier testing.
- Logic can be reused across multiple components.
- Hooks can be composed to build complex features.
---
### 1.5 `lib/` – Core Libraries
Low‑level utilities that are used throughout the app.
| File | Purpose |
|------|---------|
| `api.ts` | Re‑export of `api/client` (backward compatibility). |
| `auth.tsx` | React context for authentication (`AuthProvider`, `useAuth`). |
| `useWebSocket.ts` | Custom hook for WebSocket management (reconnection, message handler). |
| `useSecretChat.ts` | E2EE stub (Signal protocol placeholder). |
| `types/` | All TypeScript interfaces and types (mirrors backend DTOs). |
---
### 1.6 `services/`, `security/`, `audit/`, `utils/`, `config/`, `seo/`, `workers/`, `styles/`, `types/`
These directories provide cross‑cutting concerns:
| Directory | Purpose | Example Files |
|-----------|---------|----------------|
| `services/` | Complex business logic (export, notifications, search, RAG) | `exportService.ts`, `notificationService.ts`, `ragService.ts`, `searchService.ts`. |
| `security/` | Client‑side security helpers | `jwt.ts` (decode/verify), `csrf.ts` (get token), `rateLimit.ts` (client‑side limiter), `sanitize.ts` (DOMPurify wrapper). |
| `audit/` | Audit logging (sends events to backend) | `auditLogger.ts`. |
| `utils/` | Pure helper functions | `fileUtils.ts` (file size, type, dataURL), `dateUtils.ts` (relative time, formatting), `stringUtils.ts` (truncate, slugify), `errorHandler.ts`, `localStorage.ts` (typed wrapper). |
| `config/` | Environment‑aware constants | `constants.ts` (API base, WS URL, pagination size), `env.ts` (`isDev`, `isProd`). |
| `seo/` | SEO metadata | `metadata.ts` (site title, description, social tags). |
| `workers/` | Web Workers for heavy tasks | `rag-worker.ts` (PDF/DOCX parsing, embedding generation). |
| `styles/` | Global CSS | `globals.css` (glassmorphism, keyframes, scrollbar, dark mode). |
| `types/` | TypeScript type re‑exports | `index.ts` (re‑exports all types from `lib/types/`). |
---
## 🖥️ 2. Core Components – Desktop Window Manager
The **window manager** is the heart of the desktop environment. It allows users to open multiple applications (panels) as independent windows that can be moved, resized, minimised, maximised, and closed – similar to Windows or macOS.
### 2.1 `WindowContainer.tsx` – Global State Provider
This component provides the global state and actions for all windows using React Context.
**State** (managed with `useState`):
- `windows: DesktopWindow[]` – array of all open windows.
- `activeWindowId: string | null` – the window that currently has focus (highest z‑index).
- `nextZIndex: number` – increments every time a window is brought to front, ensuring proper stacking order.
**Actions (exposed via `useWindowManager` hook)**:
- `openWindow(title, content, options)`: creates a new window with a unique ID, default position (staggered), default size (800×600), and appends to the list.
- `closeWindow(id)`: removes window from state.
- `minimizeWindow(id)`: sets `isMinimized: true` – window disappears from screen but remains in taskbar.
- `maximizeWindow(id)`: sets `isMaximized: true` – window expands to full screen (with backdrop overlay).
- `restoreWindow(id)`: returns from minimized or maximized state.
- `bringToFront(id)`: updates z‑index of the window to the highest value (`nextZIndex++`).
- `updateWindow(id, updates)`: partial update (position, size, etc.).
**How it works**:
- The provider wraps the entire workspace content.
- Any component inside can call `useWindowManager()` to get state and actions.
- Window positions are stored in the state and can be persisted to `localStorage` (via `persist` middleware – optional).
**Example usage**:
```tsx
const { openWindow } = useWindowManager();
openWindow('My App', <MyComponent />, { width: 600, height: 400 });
```
---
### 2.2 `DesktopWindow.tsx` – Individual Draggable/Resizable Window
This component renders a single window. It uses `react‑draggable` and `react‑resizable` to provide dragging and resizing.
**Props**:
- `windowId: string` – the ID of the window (used to retrieve the window object from context).
**Internal state**:
- `position` (x, y) – local copy, updated while dragging, then persisted to global state on stop.
- `size` (width, height) – local copy, updated while resizing, then persisted on stop.
**Rendering logic**:
- If `window.isMinimized` → return `null` (window hidden).
- If `window.isMaximized`:
- Render a full‑screen overlay with a backdrop blur.
- Inside, a full‑size `GlassCard` with the window content.
- Clicking the backdrop restores the window.
- Else (normal state):
- Wrap the window in a `Draggable` component (drag handle = `.window-drag-handle`).
- Inside, a `Resizable` component (handles on edges).
- The window has a header (`.window-drag-handle`) with title, icon, and control buttons (minimize, maximize, close).
- Clicking the header (or anywhere) calls `bringToFront`.
**Drag and resize details**:
- `react‑draggable` uses the node reference to track mouse movement.
- `onStop` callback updates the global position.
- `react‑resizable` provides handles at edges and corners.
- `onResize` updates local size; `onResizeStop` updates global size.
**Styling**:
- The window uses the `glass-card` class (backdrop blur, border, shadow).
- Z‑index is set directly from the global state (`style={{ zIndex: window.zIndex }}`).
---
### 2.3 `Taskbar.tsx` – Bottom Bar with Start Menu and Open Windows
The taskbar provides:
- **Start button** (Home icon) – opens a menu listing all available desktop apps.
- **Open window buttons** – each open (non‑minimized) window has a button in the taskbar. Clicking it brings that window to front (or restores if minimized).
- **System tray** – clock (updates every second) and mock icons for Wi‑Fi, battery, volume.
**State**:
- `showStartMenu` (boolean) – controls visibility of the start menu modal.
- `currentTime` (Date) – updated every second with `setInterval`.
**Start menu**:
- Fetches the list of apps from the parent (`apps` prop).
- Each app button triggers the provided `action()` (which calls `openWindow`).
- Modal animates with `framer‑motion`.
**Open window buttons**:
- Derived from the `windows` array (from `useWindowManager`).
- Only non‑minimized windows are shown (though minimized can be shown with a special icon – could be added).
- Active window (the one with highest z‑index) is highlighted with `bg-primary/20`.
**Clock**:
- Uses `toLocaleTimeString` to format time.
- Updates every second via `setInterval` (cleaned up on unmount).
---
### 2.4 `StatusBar.tsx` – Optional Top Bar
A simple top bar showing:
- App name / version (left).
- Mock system icons (Wi‑Fi, volume, shield, battery).
- No functional logic – just visual polish.
---
### 2.5 `index.ts` – Barrel Export
Exports all desktop components and hooks for convenient imports:
```ts
export * from './WindowContainer';
export * from './DesktopWindow';
export * from './Taskbar';
export * from './StatusBar';
```
---
## 🔄 3. How the Window Manager Works Together
**Integration in `SmartGlassWorkspace.tsx`**:
1. The `WindowContainer` provider wraps the entire content.
2. `DESKTOP_APPS` defines all available applications (static).
3. `WorkspaceContent` component:
- Uses `useWindowManager` to access `openWindow`, `windows`, etc.
- Renders desktop icons (from `DESKTOP_APPS` and installed apps from `useAppStore`).
- Renders all windows (mapping `windows` to `<DesktopWindow key={id} windowId={id} />`).
- Renders `<Taskbar />` with the list of apps.
4. When a user clicks an icon:
- `launchApp` checks if the window already exists (by title). If yes, brings it to front; otherwise calls `openWindow`.
5. Windows are draggable, resizable, minimizable, etc. All state is kept in `WindowContainer`.
**Keyboard shortcuts** (can be added via `useEffect` listening to `keydown` events):
- `Ctrl+W` – close active window.
- `Ctrl+M` – minimize active window.
- `Ctrl+Shift+M` – maximize/restore active window.
- `Ctrl+K` – open global search modal (already implemented in `MessagesPage`).
---
## 🧩 4. Example Flow: Opening a New App
1. User clicks on "Messages" desktop icon.
2. `DESKTOP_APPS` entry for `messages` provides component `<MessagesPage />`.
3. `launchApp('Messages', ...)` calls `openWindow('Messages', <MessagesPage />, { icon: <MessageSquare />, size: { width: 900, height: 650 } })`.
4. `openWindow` creates a new window object, adds to `windows` array, sets `activeWindowId` to this new window, and increments `nextZIndex`.
5. The window is rendered by `<DesktopWindow windowId={newId} />`.
6. The window appears on screen at the calculated position (staggered). User can drag, resize, etc.
7. The taskbar shows a new button for "Messages".
8. Clicking the taskbar button brings the window to front (if it was behind) or restores it if minimised.
---
## 📦 5. Adding a New Desktop App
To add a new app, simply:
1. Create a component (or page) that will be the window content.
2. Add an entry to `DESKTOP_APPS` in `SmartGlassWorkspace.tsx`:
```ts
{ id: 'my-app', name: 'My App', icon: <MyIcon />, component: <MyComponent />, defaultSize: { width: 800, height: 600 } }
```
3. Optionally, add an icon to the desktop by including it in the `Desktop Icons` section.
4. The app will automatically appear in the Start Menu (from `Taskbar`).
5. Users can open it, and it will behave like any other window.
For **installable apps** (via App Store), the process is similar but the app definition comes from the backend, and the icon is dynamically added to the desktop after installation.
---
## 🎯 6. Why This Window Manager is Powerful
- **Truly desktop‑like**: Users can arrange their workspace exactly as they like.
- **Multi‑tasking**: Open many windows simultaneously, switch via taskbar.
- **Extensible**: Adding new apps requires only a few lines of code.
- **Persistent layout** (optional): You can save window positions/sizes to `localStorage` and restore on reload.
- **Accessible**: Keyboard shortcuts can be added easily.
- **Responsive**: Windows are constrained to the viewport (bounds set in `Draggable`).
- **Performance**: Windows are only rendered when open; closed windows are removed from DOM.
---
## ✅ Conclusion
The **Project Structure** is modular, feature‑based, and follows best practices for a large React application. The **Desktop Window Manager** provides a full desktop experience with draggable/resizable windows, a taskbar, start menu, and status bar, all styled with glassmorphism and integrated with the rest of the platform.
This architecture allows you to add new research tools, plugins, and even user‑submitted apps with ease, while maintaining a consistent and beautiful UI. 🚀
# Feature Modules – Complete Detailed Explanation
Below is an exhaustive, code‑free explanation of every major feature module in the Research Platform. For each module, you will learn: its purpose, the user journey, the components involved, how data flows between frontend and backend, key integration points, and important design decisions.
---
## 1. Paper Collections
**Purpose**: Allow researchers to organise articles into custom collections (e.g., “Deep Learning Papers”, “Grant References”). Collections can be private or public.
### User Journey
1. The user navigates to the **Collections Page** (`/collections`).
2. They see a grid of existing collections (if any) and a “+ New Collection” button.
3. Clicking “+ New Collection” opens a modal (`CreateCollectionModal`) where they enter a title, optional description, and toggle public/private.
4. After creation, the collection appears in the grid.
5. Clicking a collection card opens the **Collection Detail Page** (`/collections/:id`).
6. On the detail page, they see a list of papers already in the collection (with links to the articles) and a “Remove” button next to each paper.
7. To add a paper, the user goes to an article page (or article card) and clicks “Save to collection”. This opens `AddToCollectionModal` where they select an existing collection or create a new one on the fly.
8. The paper is added, and the collection’s paper count increments.
### Components
- **`CollectionsPage`**: Main grid view. Uses `usePaperCollections` hook to fetch collections. Renders `CollectionCard` for each.
- **`CollectionDetailPage`**: Shows papers inside a collection. Calls `removePaperFromCollection` when user clicks remove.
- **`CollectionCard`**: Displays collection title, description, paper count, and privacy icon. Click navigates to detail page. Delete button calls `deleteCollection`.
- **`CreateCollectionModal`**: Form modal that calls `createCollection` from the hook.
- **`AddToCollectionModal`**: Appears on article pages. Lists user’s collections; allows adding or creating a new collection.
### Hook: `usePaperCollections`
- Fetches collections from `/api/collections`.
- Provides `createCollection`, `deleteCollection`, `addPaperToCollection`, `removePaperFromCollection`.
- Optimistically updates local state before backend confirmation, rolls back on error.
### Backend Endpoints (conceptual)
- `GET /api/collections` – returns all collections for the authenticated user.
- `POST /api/collections` – creates a new collection (body: `{ title, description, isPublic }`).
- `DELETE /api/collections/{id}` – deletes a collection.
- `POST /api/collections/{id}/papers` – adds a paper (body: `{ articleId, title, authors, addedAt }`).
- `DELETE /api/collections/{id}/papers/{paperId}` – removes a paper.
### Integration Points
- Article detail and article card components include a “Save to collection” button that triggers `AddToCollectionModal`.
- The modal uses the same `usePaperCollections` hook, ensuring consistency.
---
## 2. Reference Manager
**Purpose**: Manage bibliographic references for a collaborative document. Users can import references from DOI, BibTeX, Zotero, or Mendeley, and insert citations (`\cite{key}`) into the TipTap editor.
### User Journey
1. The user opens the **Reference Manager Page** (`/references/:docId`) while working on a document (e.g., in the Scientific Editor).
2. They see a list of references already added to that document, each with title, authors, year, journal, and DOI.
3. They can click “Add Reference” to open `ReferenceImportModal`.
4. In the modal, they choose a source:
- **DOI**: paste a DOI (e.g., `10.1038/s41586-020-2649-2`). The backend fetches citation data and adds it.
- **BibTeX**: paste a BibTeX entry (plain text). The backend parses it.
- **Zotero**: provide API key and user ID; the backend imports all references from Zotero.
- **Mendeley**: provide an access token.
5. After import, the reference appears in the list.
6. While editing the document, the user clicks the “Insert citation” button in the editor toolbar. This opens `ReferencePicker`.
7. In the picker, they search/filter existing references, click one, and the editor inserts `\cite{key}` at the cursor.
8. The user can delete a reference using the delete button (confirmation dialog).
### Components
- **`ReferenceManagerPage`**: Main page listing references. Uses `useReferenceManager`. Renders each reference with title, authors, etc. Buttons for import and citation picker.
- **`ReferenceImportModal`**: Tabbed modal for different import sources. Manages its own input fields and calls the appropriate import function from the hook.
- **`ReferencePicker`**: Modal with search input. Fetches references (already loaded). On selection, dispatches a custom `insertCitation` event that the editor listens to.
### Hook: `useReferenceManager`
- Takes `docId` as argument.
- Fetches references for that document via `GET /documents/{docId}/references`.
- Provides `importFromDOI`, `importBibTeX`, `connectZotero`, `connectMendeley`, `removeReference`, and `refetch`.
- After import, automatically updates the list.
### Editor Integration
- The `ScientificEditor` component listens for `insertCitation` custom event.
- When received, it calls `editor.chain().focus().insertContent(text).run()`.
- The `ReferencePicker` dispatches this event with `text = \cite{${ref.key}}`.
### Backend Endpoints
- `GET /documents/{docId}/references`
- `POST /documents/{docId}/references` (for DOI/BibTeX direct)
- `DELETE /documents/{docId}/references/{refId}`
- `POST /references/connect-zotero`
- `POST /references/connect-mendeley`
---
## 3. Preprint Submission
**Purpose**: Allow researchers to submit preprints (manuscripts) to the platform. The backend provides AI‑based screening (format, plagiarism, completeness) and assigns a DOI upon successful submission.
### User Journey
1. User navigates to **Preprint Submission Page** (`/submit-preprint`).
2. They fill in a form:
- Title (required)
- Abstract (minimum 100 characters)
- Keywords (optional, can be added via input + “Add” button)
- Manuscript file (PDF, DOC, DOCX; max 50 MB)
- Authors (list of names, emails, optional ORCID). Can add multiple.
- Cover letter (optional)
3. They click “Screen Submission”. The frontend calls `screenSubmission` with the form data (excluding the file? Actually, screening may need only metadata; file can be optional for screening, but typical implementation sends metadata only). The backend returns a screening result object: `{ passed, issues, suggestions, score }`.
4. The `ScreeningResultCard` displays the result – issues to fix, suggestions, and a pass/fail score.
5. If screening passes (or if the user decides to proceed regardless), they click “Submit Preprint”. The frontend sends a multipart form with all data + manuscript file. The backend assigns a DOI, stores the preprint, and returns success.
6. After submission, the form resets, and the user sees a success message.
### Components
- **`PreprintSubmissionPage`**: Container for the entire form. Manages local state, validation, and calls the hook.
- **`ScreeningResultCard`**: Pure presentation component that displays screening feedback. Shows score as percentage, lists issues and suggestions, and uses color coding (red/yellow/green) for severity.
### Hook: `usePreprintSubmission`
- `screenSubmission(data: any)`: POST to `/api/preprints/screen` (only metadata). Sets `screeningResult` and `screening` loading state.
- `submitPreprint(formData: FormData)`: POST to `/api/preprints/submit` (multipart). Handles upload progress via `onUploadProgress` (optional).
- Returns `screeningResult`, `submitting`, `screening`, `uploadProgress`, `submittedDoi`.
### Backend Endpoints
- `POST /api/preprints/screen` – expects JSON: `{ title, abstract, keywords, field }`. Returns screening results.
- `POST /api/preprints/submit` – expects `multipart/form-data` with fields: `title`, `abstract`, `keywords`, `field`, `authors` (JSON string), `coverLetter`, `manuscript` (file). Returns `{ doi, status }`.
---
## 4. Provenance (Trust)
**Purpose**: Provide an auditable trail of actions on an entity (article, user, chemical, project). Users can see who created, edited, viewed, downloaded, or shared the entity, and can verify the integrity of the chain (e.g., cryptographic hash verification).
### User Journey
1. While viewing an article, the user clicks a “Provenance” button in the action bar.
2. A modal opens, containing two parts:
- **ProvenanceTimeline**: chronological list of events (each with action, user, timestamp, optional details). Events are fetched from `/api/provenance/article/{articleId}`.
- **Verify Chain Button**: user clicks it, the frontend calls `/api/provenance/article/{articleId}/verify`. The backend checks the integrity (e.g., hash chain) and returns `{ valid: true/false }`. A toast notifies the user.
3. The user can close the modal.
### Components
- **`ProvenanceTimeline`**: Takes `entityId` and `entityType`. Fetches events using `useProvenance`. Renders a timeline with icons, action names, users, and timestamps.
- **`VerifyChainButton`**: Uses `useProvenance` to call `verifyChain()`. Shows loading state, then a toast with result. Also updates a local `checked` state to display “Valid”/“Invalid” on the button.
### Hook: `useProvenance`
- `fetchProvenance`: GET `/api/provenance/{entityType}/{entityId}`.
- `verifyChain`: POST `/api/provenance/{entityType}/{entityId}/verify`.
- Returns `events`, `loading`, `verifying`, `chainValid`.
### Integration
- Added to `ArticleDetailPage` as a button that opens a modal (or collapsible panel). The modal imports `ProvenanceTimeline` and `VerifyChainButton`.
### Backend Endpoints
- `GET /api/provenance/{entityType}/{entityId}` – returns list of events (action, user, timestamp, metadata).
- `POST /api/provenance/{entityType}/{entityId}/verify` – returns `{ valid: boolean }`.
---
## 5. Unified Inbox
**Purpose**: Aggregate messages from all sources – private chats, group chats, project discussions, paper Q&A, AI assistant conversations, and broadcast channels – into a single inbox. Users can filter by type, priority, date, and search.
### User Journey
1. User navigates to **Unified Inbox** (`/inbox`).
2. At the top, a tab bar (`InboxFilterBar`) shows counts for each message origin (All, Unread, Critical, Direct, Groups, Projects, Papers, AI, Broadcasts).
3. Below the tabs, a search bar filters messages by content, sender, or origin name.
4. Next to the search bar, a “Filter” button opens a panel for priority (critical/high/medium/low) and date range.
5. Messages are displayed as cards (`InboxMessageCard`), each showing origin icon, origin name, sender, message preview, timestamp, and a “read” indicator.
6. Clicking a message navigates to the original conversation (opens the relevant chat window or page) and marks it as read.
7. Each card has a “Forward” button (optional) to forward the message to another chat.
8. At the top of the page, a “Mark All Read” button and a “Refresh” button are available.
### Components
- **`UnifiedInboxPage`**: Main container. Uses `useUnifiedInbox` for state.
- **`InboxFilterBar`**: Renders tabs, counts, priority filter, date range. Communicates via callbacks.
- **`InboxMessageCard`**: Displays one message. Contains logic for marking as read on click, and forwarding.
### Hook: `useUnifiedInbox`
- Fetches aggregated messages from `/api/unified-inbox`.
- Manages filter state (tab, search, priority, date range).
- Provides `markAsRead`, `markAllRead`, `forwardMessage`, `navigateToOrigin`, and refetch.
- The backend is responsible for combining messages from different sources (private, groups, projects, etc.) into a unified format.
### Backend Endpoint
- `GET /api/unified-inbox` – returns an array of messages with fields: `id`, `origin`, `originName`, `from`, `body`, `sentAt`, `priority`, `isRead`, `link`.
### Integration Notes
- The inbox does not replace existing dedicated chat pages; it is an additional view.
- Clicking a message navigates to the appropriate chat (using `navigateToOrigin`), which uses the `link` field from the message.
---
## 6. Scheduled Messages
**Purpose**: Allow users to write a message now but schedule it to be sent automatically at a future date/time. Users can also view and cancel scheduled messages.
### User Journey (Scheduling)
1. In any chat (private or group), the user types a message.
2. Instead of pressing “Send”, they click a **calendar icon** in the input toolbar.
3. A `ScheduleModal` opens, showing a datetime picker (HTML `datetime-local`). Only future dates/times are allowed.
4. The user selects a date/time and clicks “Schedule”.
5. The frontend calls the appropriate backend endpoint (`/api/conversations/{username}/schedule` or `/api/groups/{groupId}/schedule`).
6. A toast confirms the scheduling, and the input field is cleared.
### User Journey (Viewing/Cancelling)
1. In the main `MessagesPage`, there is a **clock icon** in the header.
2. Clicking it opens `ScheduledMessagesPanel`.
3. The panel fetches all scheduled messages for the user (`GET /api/messages/scheduled`).
4. Each scheduled message shows: chat name, message preview, scheduled date/time, and a cancel button.
5. Clicking cancel sends `DELETE /api/messages/scheduled/{id}` and removes the message from the list.
### Components
- **`ScheduleModal`**: Simple modal with a datetime picker. Takes `onSchedule` callback.
- **`ScheduledMessagesPanel`**: Modal that lists scheduled messages. Uses `api.get` and `api.delete`. Optionally accepts `onCancel` and `onRefresh` props for custom handling.
### Integration in `ChatArea`
- The calendar button is added next to the send button.
- When clicked, `setScheduleModalOpen(true)`.
- `onSchedule` callback constructs the appropriate API call based on `selectedChat.type`.
- After scheduling, the input is cleared, and the modal closes.
### Integration in `MessagesPage`
- The clock button is added in the top bar (near the search button).
- It opens `ScheduledMessagesPanel`. The panel uses the same API endpoints directly, no extra props needed.
### Backend Endpoints
- `POST /api/conversations/{username}/schedule` – body: `{ body, scheduledAt }`.
- `POST /api/groups/{groupId}/schedule` – body: `{ body, scheduledAt }`.
- `GET /api/messages/scheduled` – returns array of scheduled messages for the current user.
- `DELETE /api/messages/scheduled/{id}` – cancels a scheduled message.
---
## 7. Global Search Modal
**Purpose**: Search across all private and group messages (full‑text) and jump directly to the relevant conversation, optionally scrolling to the specific message.
### User Journey
1. User presses `Ctrl+K` (or `Cmd+K` on Mac) anywhere in the app, or clicks a search button in the `MessagesPage`.
2. A modal (`GlobalSearchModal`) opens with a search input field.
3. As the user types (debounced 400ms), the frontend calls:
- `/api/conversations/search?q={query}` for private messages.
- For groups, it calls `/api/groups/{id}/search?q={query}` for each group the user is a member of (limited to first 10 groups for performance). Alternatively, a unified group search endpoint can be used.
4. Results are grouped by chat (private conversations and groups).
5. Each result shows the message preview, sender, and timestamp.
6. User clicks a result. The modal closes, and the main chat page opens with that chat selected. If a `messageId` was provided, the page scrolls to that specific message (using `document.getElementById` and `scrollIntoView`).
### Components
- **`GlobalSearchModal`**: Handles input, debouncing, calling search endpoints, and rendering grouped results. Uses a local state for results and loading.
### Integration in `MessagesPage`
- A search button (magnifying glass) is added in the header.
- On click, `setShowSearch(true)`.
- The `GlobalSearchModal` receives `groups` (list of user’s groups) and `onSelectChat` callback.
- `onSelectChat` finds the chat object in `messaging.chats`, calls `setSelectedChat`, and optionally scrolls to the message.
### Backend Endpoints
- `GET /api/conversations/search?q={query}` – returns array of `{ with: string, messages: [...] }`.
- `GET /api/groups/{groupId}/search?q={query}` – returns array of messages (each with `id`, `body`, `sentAt`, `from`).
- **Optional**: `GET /api/groups/search?q={query}` – unified group search (recommended for scalability).
### Keyboard Shortcut
- An effect in `MessagesPage` listens for `keydown` events with `ctrlKey`/`metaKey` and key `'k'`. Prevents default and sets `showSearch` to true.
---
## 8. Admin Dashboard
**Purpose**: Provide platform administrators with statistics and management interfaces for users, articles, and RAG‑indexed documents.
### User Journey
1. Admin logs in and navigates to `/admin`.
2. They see a dashboard with:
- Statistics cards (total users, articles, views, etc.) fetched from `/api/admin/stats`.
- A recent activity feed (if implemented).
- Tabs below the stats: **Users**, **Articles**, **RAG Documents**.
3. **Users tab**:
- Table listing users (ID, username, email, role, join date).
- Actions: delete user, promote/demote admin role.
- Search input to filter users by username/email.
- Pagination.
4. **Articles tab**:
- Table listing articles (ID, title, author, status, views, creation date).
- Actions: delete article, view article (opens in new tab).
- Filter by status (published/draft/all).
- Search by title or author.
5. **RAG Documents tab**:
- Table listing RAG‑indexed documents (title, file type, source, added date).
- Action: delete document (removes from RAG index).
- Search by title.
### Components
- **`AdminPage`**: Main container, fetches stats, and handles tab switching.
- **`UserTable`**: Fetches users from `/api/admin/users` (with pagination and search). Uses delete and role update endpoints.
- **`ArticleTable`**: Similar, with article management endpoints.
- **`RagDocTable`**: Fetches from `/api/admin/rag/documents` and calls `/documents/{docId}/rag-delete` for deletion.
### Hooks
- `useAdminStats` – fetches global stats.
- Individual tables use direct `api` calls or separate hooks.
### Backend Endpoints
- `GET /api/admin/stats`
- `GET /api/admin/users` (with pagination, search, role filters)
- `DELETE /api/admin/users/{id}`
- `PUT /api/admin/users/{id}/role`
- `GET /api/admin/articles` (with pagination, status filter, search)
- `DELETE /api/admin/articles/{id}`
- `GET /api/admin/rag/documents`
- `DELETE /documents/{docId}/rag-delete`
### Security
- Only users with `role = "admin"` can access the admin page. The frontend checks `user?.role` and redirects non‑admins to home.
---
## 9. Offline Support
**Purpose**: Allow the collaborative editor to work offline (no internet connection). Changes are saved locally (IndexedDB) and automatically synced when the connection is restored. The application can also be installed as a PWA, caching static assets for offline use.
### How It Works (Collaborative Editor)
1. When the user opens a document, the Yjs document (`ydoc`) is initialised.
2. Two providers are attached:
- `WebsocketProvider` – synchronises changes with the server when online.
- `IndexeddbPersistence` – persists the document to the browser’s IndexedDB.
3. When offline, the `WebsocketProvider` disconnects, but the user can still edit. Changes are stored in IndexedDB.
4. When the connection is restored, the `WebsocketProvider` reconnects and automatically syncs all local changes with the server (and other peers). Yjs handles the merging.
5. An `OfflineSyncStatus` component shows a small indicator (green “Online” or red “Offline” with a “Syncing…” spinner) in the header.
### PWA (Service Worker)
- The `vite-plugin-pwa` plugin generates a service worker.
- It caches static assets (HTML, CSS, JS, images) using a cache‑first strategy.
- When offline, the app can still load and show a cached version of the UI (though dynamic data will be stale).
- The service worker is registered in `main.tsx` with `registerSW({ immediate: true })`.
### Components
- **`OfflineSyncStatus`**: Uses `navigator.onLine` and browser events to show online/offline status.
- The collaborative editor hook (`useCollaborativeEditor`) already includes `IndexeddbPersistence` and exposes `isOfflineSyncing`.
### Integration Points
- `useCollaborativeEditor` is modified to instantiate `IndexeddbPersistence` and to set `isOfflineSyncing` state.
- The `OfflineSyncStatus` component is placed in `MainLayout.tsx` (header).
- The PWA manifest and icons are added to `public/`.
### Backend / Infrastructure
- The collaboration WebSocket server (y‑websocket) must be running.
- The service worker caches static files; dynamic API calls are not cached (except maybe responses if needed).
---
## 10. App Store & Plugin System
**Purpose**: Allow researchers to build, share, and install lightweight HTML/CSS/JS applications that run inside the desktop environment. This turns the platform into an extensible ecosystem.
### User Journey for Developers
1. Developer opens the **App Store** window from the desktop.
2. They click the “+” button to open `AppEditor`.
3. They fill in:
- App name
- Description
- Icon (optional, base64 image)
- HTML code (full page) – can be typed or uploaded from a `.html` file.
4. Click “Submit App”. The frontend sends a `FormData` containing the metadata and the code to `POST /api/plugins`.
5. The backend stores the plugin in the database with `approved = false` (requires manual approval, or can be auto‑approved for trusted users).
6. An admin approves the plugin (via admin panel or direct DB edit).
7. Once approved, the plugin appears in the App Store for all users.
### User Journey for End Users
1. Other users open the App Store.
2. They browse available plugins (grid of `AppCard` components).
3. Each card shows name, description, author, install count, and an “Install” button.
4. Click “Install” sends `POST /api/plugins/user/install/{pluginId}`. The backend records the installation.
5. Installed plugins appear as **desktop icons** dynamically (fetched via `GET /api/user/installed` and added to the desktop area in `SmartGlassWorkspace`).
6. Clicking the desktop icon launches the app in a new window. The window content is an `AppRunner` component that renders a sandboxed iframe with the plugin’s HTML code.
7. The app runs inside the iframe, isolated from the main platform.
### Components
- **`AppStorePage`**: Main store UI. Uses `useAppStore` to fetch available and installed plugins. Shows `AppCard`s.
- **`AppCard`**: Displays a single plugin. Has install/uninstall buttons. Shows install count.
- **`AppEditor`**: Form for submitting a new plugin. Has fields for name, description, icon (file input), and code (textarea with optional file upload). Submits `FormData` to `pluginsApi.submit`.
- **`AppRunner`**: Takes `appId` and `code` as props. Creates an iframe, sets `sandbox` attributes, and writes the HTML code into it. Also sets up a `postMessage` listener for secure API calls (optional).
- **`PluginStorePage`**: In the current implementation, the app store is integrated as a desktop app; it can be a separate page or a window.
### Hook: `useAppStore`
- Fetches available and installed plugins.
- Provides `installPlugin`, `uninstallPlugin`, `submitPlugin`.
- Refreshes lists after mutations.
### Security
- The iframe sandbox is crucial: `sandbox="allow-same-origin allow-scripts allow-popups allow-forms"`.
- **Never** add `allow-top-navigation` or `allow-modals` unless absolutely necessary.
- API calls from the plugin to the main platform must go through `postMessage` (the plugin sends a message, the parent window makes the actual fetch, then replies). This keeps API tokens secure.
### Backend Endpoints
- `GET /api/plugins` – list of approved plugins.
- `GET /api/plugins/{id}` – get plugin details (including code).
- `POST /api/plugins` – submit a new plugin (multipart).
- `POST /api/plugins/user/install/{pluginId}` – record installation.
- `GET /api/plugins/user/installed` – list installed plugins for the current user.
- Optional: `DELETE /api/plugins/user/uninstall/{pluginId}` (not yet implemented).
### Desktop Integration
- In `SmartGlassWorkspace.tsx`, an additional desktop icon for “App Store” is added.
- After fetching installed plugins (using `useAppStore`), the desktop area also renders an icon for each installed plugin. When clicked, it calls `openWindow` with `AppRunner` as the content (the code is fetched from the plugin’s `code` field, which is stored in the plugin object).
- The same `AppRunner` component is used for all plugins.
### Visual No‑Code Builder (Planned Future)
- This will be a separate module that generates the plugin HTML via drag‑and‑drop.
- It would output a JSON blueprint, which is then converted to HTML/CSS/JS by a backend code generator.
- The generated plugin can then be submitted to the App Store.
- This is not yet implemented, but the architecture is designed to accommodate it later.
---
## Summary
Each feature module follows a consistent pattern:
1. **Page component** (if standalone) or **modal/panel** for auxiliary interactions.
2. **Custom hook** that encapsulates data fetching, state management, and business logic.
3. **API module** with typed functions for backend communication.
4. **Integration with other modules** (e.g., ReferencePicker integrates with ScientificEditor, Provenance button integrates with ArticleDetailPage).
5. **Backend endpoints** that follow REST conventions.
The desktop environment (window manager) ties everything together, allowing users to open any feature as a window, rearrange their workspace, and install custom apps.
This architecture ensures the platform is **extensible**, **maintainable**, and **user‑friendly** for researchers.
This detailed technical overview explains the key client‑server communication methods and the frameworks that power your research platform.
---
## 🧱 1. High-Level Architecture
Your platform is a **full‑stack web application** with a clear separation of concerns:
* **Frontend (Client)** – A React‑based Single Page Application (SPA) that also acts as a **desktop environment** with its own window manager, taskbar, and start menu. All user interactions happen here.
* **Backend (Server)** – A Java Spring Boot application that provides REST APIs, WebSocket endpoints, database access, and business logic.
* **Collaboration Server** – A separate WebSocket server (Yjs) dedicated to real‑time document editing.
The frontend communicates with the backend through two primary channels: **REST over HTTP** for standard CRUD operations and a **WebSocket** for real‑time events (new messages, typing indicators, notifications).
---
## 📡 2. Client-Server Communication Methods
### 🔁 2.1 REST APIs (HTTP)
**Purpose**: All data persistence, user management, articles, messaging, collections, etc.
**Frontend Implementation**: The entire API layer is centralized in the `src/api/` folder. Each module exports typed functions that use an Axios instance (`client.ts`) with built‑in JWT authentication and automatic token refresh.
```typescript
// src/api/client.ts – simplified
import axios from 'axios';
const api = axios.create({ baseURL: '/api' });
api.interceptors.request.use(config => {
config.headers.Authorization = `Bearer ${localStorage.getItem('accessToken')}`;
return config;
});
api.interceptors.response.use(
res => res,
async err => {
if (err.response?.status === 401) {
// Refresh token and retry
}
return Promise.reject(err);
}
);
```
**Backend Implementation**: Spring Boot controllers map HTTP requests to Java methods. Example for article CRUD:
```java
@RestController
@RequestMapping("/api/articles")
public class ArticleController {
@GetMapping
public List<Article> getArticles() { ... }
@PostMapping
public Article createArticle(@RequestBody ArticleDto dto) { ... }
@GetMapping("/{id}")
public Article getArticle(@PathVariable Long id) { ... }
}
```
**Why Axios + Spring Boot**:
* Axios provides a consistent, promise‑based API, interceptors for authentication/refresh, and automatic JSON transformation.
* Spring Boot offers a mature, annotation‑driven REST framework with built‑in security (Spring Security), data (Spring Data JPA), and dependency injection.
### 🔌 2.2 WebSocket for Real‑Time Features
**Purpose**: Live updates for messaging (new messages, typing, read receipts, reactions) and notifications.
**Frontend Implementation**: A custom `useWebSocket` hook manages the connection lifecycle.
```typescript
// Simplified from src/hooks/useWebSocket.ts
export function useWebSocket(onMessage: (data: any) => void) {
const wsRef = useRef<WebSocket | null>(null);
useEffect(() => {
const ws = new WebSocket(import.meta.env.VITE_WS_URL);
ws.onmessage = (event) => onMessage(JSON.parse(event.data));
wsRef.current = ws;
return () => ws.close();
}, []);
return wsRef;
}
```
**Backend Implementation**: Spring Boot’s WebSocket support with STOMP as the sub‑protocol.
```java
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic", "/queue");
config.setApplicationDestinationPrefixes("/app");
}
}
```
Messages are sent to specific destinations (e.g., `/app/chat.sendMessage`) and broadcast to all connected clients subscribed to a topic (e.g., `/topic/messages/{roomId}`).
### ✍️ 2.3 Yjs WebSocket for Collaborative Editing
**Purpose**: Real‑time, peer‑to‑peer document editing (used in `ScientificEditor`).
**How it works**:
* Yjs is a **CRDT** (Conflict‑free Replicated Data Type) library. It allows multiple users to edit a shared document simultaneously without locking, merging changes automatically.
* The frontend creates a Yjs document (`ydoc`), attaches a `WebsocketProvider` to sync changes via a separate WebSocket server (port `9093`), and connects a `IndexeddbPersistence` provider for offline storage.
* The TipTap editor is extended with the `Collaboration` and `CollaborationCursor` extensions, which use the Yjs document as the source of truth.
**Backend / Infrastructure**: A standalone `y-websocket` server (Node.js) or a Java implementation that relays updates between clients.
**Advantages**:
* **No central locking** – edits from different users are merged transparently.
* **Offline‑first** – thanks to the IndexedDB provider, changes made offline are synced automatically when the connection returns.
* **Cursor awareness** – users see each other’s cursors and selections in real time.
---
## 🎨 3. Frontend Frameworks & Key Libraries
### ⚛️ 3.1 React 19 & TypeScript
**React 19** is the core UI library. The app is structured as a **Single Page Application (SPA)** with React Router for client‑side routing.
**TypeScript** provides static typing across the entire codebase, from API responses (`src/api/*.ts`) to component props (`src/components/**/*.tsx`). This drastically reduces runtime errors and improves developer experience.
### 🧩 3.2 UI Components & Styling
* **Tailwind CSS** – a utility‑first CSS framework. All components use Tailwind classes (e.g., `flex`, `p-4`, `rounded-xl`). The custom “glassmorphism” effects (`glass-card`, `glass`) are defined in `src/index.css`.
* **Lucide React** – a consistent, beautifully designed icon set. Used everywhere (e.g., `MessageSquare`, `FileText`, `Plus`).
* **Framer Motion** – powers all animations: window opening/closing (scale + fade), taskbar start menu, message pop‑ins, and smooth transitions between routes.
### 🖥️ 3.3 Desktop Environment (Window Manager)
The desktop experience is implemented with a **custom window manager** composed of four main components:
* `WindowContainer` (Context Provider) – holds the global state of all open windows (positions, sizes, z‑index, minimized/maximized).
* `DesktopWindow` – uses `react-draggable` for dragging and `react-resizable` for resizing. It wraps any content.
* `Taskbar` – shows start menu, open window buttons, and the system clock (updated every second).
* `StatusBar` – an optional top bar with mock system icons.
**Why not a library like `react‑grid‑layout`?**
Because the requirement was to allow **free‑form, overlapping windows** (like a real desktop), not a rigid grid.
### 💬 3.4 Messaging & Real‑Time
* **`useWebSocket` hook** – manages a single WebSocket connection for all real‑time features (chat, typing, notifications).
* **MessageBubble** – each message is rendered with reaction buttons, reply preview, edit/delete menu, and status icons. Uses `framer-motion` for hover animations.
* **GlobalSearchModal** – debounced search across private and group messages, with results grouped by chat.
### 📝 3.5 Collaborative Editor Stack
* **TipTap** – a headless editor framework built on ProseMirror. It provides ready‑made extensions (bold, italic, lists, tables, code blocks, math) and a plugin system.
* **Yjs** – the CRDT that powers real‑time collaboration.
* **y-websocket** – the provider that syncs Yjs documents over WebSocket.
* **y-indexeddb** – the provider that persists the document locally for offline editing.
* **KaTeX** – renders LaTeX math inside the editor and in the live preview.
* **Lowlight** – provides syntax highlighting for code blocks.
* **Citation Picker** – a custom modal (`ReferencePicker`) that inserts `\cite{key}` into the editor via a custom event (`insertCitation`).
### 📊 3.6 Data Visualization & Graphs
* **Recharts** – used for the `ViewsChart` component (line charts of article views over time).
* **react‑force‑graph‑2d** – powers the knowledge graph in `GapAnalysisDashboard`. It renders an interactive force‑directed graph of nodes (papers, concepts, gaps) and edges.
### 🗄️ 3.7 State Management
Most state is local to components or lifted to custom hooks. The only global state is authentication (`AuthProvider`), theme (`ThemeProvider`), and the window manager (`WindowContainer`). This avoids the complexity of Redux while keeping the app predictable.
### 🧩 3.8 PWA & Offline Support
* **vite‑plugin‑pwa** – generates the service worker and manifest. The service worker caches static assets (HTML, JS, CSS, images) using a cache‑first strategy.
* **IndexedDB** – used by `y-indexeddb` to store collaborative documents offline.
* **OfflineSyncStatus** – a small component that displays a green/red indicator in the header based on `navigator.onLine`.
### 🧪 3.9 API Communication & Data Fetching
While the app uses direct `axios` calls inside custom hooks, a future improvement would be to introduce **React Query** (`@tanstack/react-query`) to automatically handle caching, background refetching, and request deduplication.
---
## ☕ 4. Backend Frameworks (Conceptual)
Although the backend code is not provided in the frontend repository, the architecture is based on industry standards:
* **Spring Boot** – the core framework for REST APIs, dependency injection, and security.
* **Spring Data JPA** – for database access (PostgreSQL).
* **Spring Security** – for JWT authentication, CSRF protection, and role‑based authorisation.
* **Spring WebSocket** – for real‑time messaging and notifications.
* **HikariCP** – the connection pool (default in Spring Boot).
* **Flyway** – for database migrations (optional but recommended).
---
## 🔗 5. How Data Flows – Concrete Example
Let’s trace the flow of a new message:
1. **User types and sends** a message in `ChatArea`.
2. `ChatArea` calls `onSendMessage` (which comes from `useMessaging.sendMessage`).
3. `sendMessage` optimistically adds the message to the local `messages` state and shows a “sending” status.
4. It then makes a `POST` request to `/api/conversations/{username}/messages` using the API client.
5. The backend Spring Boot controller receives the request, validates the user, persists the message to the database, and returns the saved entity.
6. **At the same time**, the backend publishes a WebSocket message to `/topic/messages/{roomId}`.
7. The frontend WebSocket handler receives the message and calls `onMessage`.
8. `onMessage` updates the local state (replacing the optimistic message with the real one) and triggers a re‑render.
9. The `MessageBubble` component shows the delivered/seen status, reactions, etc.
---
## 🧠 6. Why This Stack?
| Requirement | Solution | Reason |
|-------------|----------|--------|
| **Type safety** | TypeScript + Spring Boot (Java) | Catches errors early, improves maintainability. |
| **Real‑time updates** | WebSocket (STOMP) + Yjs | Efficient, low‑latency, supports offline editing. |
| **Desktop‑style UI** | React + custom window manager + react‑draggable / react‑resizable | Gives users a familiar workspace without rebuilding an entire OS. |
| **Rich text editing** | TipTap + Yjs | Ready‑made collaboration extensions, great Markdown/LaTeX support. |
| **Graph visualisation** | react‑force‑graph‑2d | Interactive, scalable, and well‑documented. |
| **Animations** | Framer Motion | Declarative API, spring physics, easy exit animations. |
| **Styling** | Tailwind CSS | Rapid development, consistent design, small bundle size (via PurgeCSS). |
| **Offline capability** | IndexedDB + service worker (PWA) | Essential for researchers working in the field. |
---
## ✅ 7. Summary
The Research Platform is a **modern, full‑stack web application** that seamlessly blends a **desktop‑style React frontend** with a **Java Spring Boot backend**. Communication happens through:
* **REST APIs** for all persistent data (Axios ↔ Spring MVC).
* **WebSockets** for real‑time messaging and notifications.
* **A separate Yjs WebSocket server** for collaborative document editing.
The frontend is built with **React 19**, **TypeScript**, **Vite**, and **Tailwind CSS**, while the backend relies on **Spring Boot**, **Spring Data JPA**, and **Spring WebSocket**. The combination of these technologies provides a **secure, extensible, and highly interactive** environment for researchers, with a unique desktop‑style user experience and offline capabilities. 🚀
# How AI Agents Can Revolutionise the Development & Operation of Your Research Platform
AI agents – autonomous or semi‑autonomous programs powered by large language models (LLMs), decision‑making algorithms, and tool‑use capabilities – can dramatically accelerate the implementation of your research platform, both during development and at runtime. They can write code, generate documentation, debug issues, optimise performance, and even act as user‑friendly “co‑pilot” tools that run inside the platform itself, helping researchers analyse data, draft papers, or manage projects.
Below is a complete explanation of how agents can be integrated into **every stage** of the platform lifecycle, and how they can execute either on the server (centralised, heavy compute) or on the client’s own machine (privacy‑sensitive, offline‑friendly).
---
## 1. What Are AI Agents in This Context?
An AI agent is a software entity that:
- **Perceives** its environment (via APIs, user input, file system, or sensor data).
- **Reasons** about a goal (e.g., “write a React component for a new dashboard widget”).
- **Acts** by generating code, making API calls, editing files, or sending responses.
- **Learns** from feedback (via reinforcement learning or in‑context examples).
In your platform, agents can be **LLM‑based** (e.g., GPT‑4, Code Llama, or local models like Ollama) and can be given access to:
- The codebase (source code, documentation, issue tracker).
- The running application (UI state, backend logs, database).
- External tools (terminal, compiler, linter, test runner).
---
## 2. Agents in the Development Phase (Writing Code)
### 2.1 Automated Code Generation for New Features
Instead of manually writing every React component, API endpoint, or database migration, a developer can **describe the feature** in natural language, and an agent generates the code.
**Example**: “Create a new desktop app called ‘Literature Review Mapper’. It should have a draggable canvas where users can add paper nodes and connect them with citation edges. Store the graph in IndexedDB for offline use.”
The agent would:
1. Analyse your existing code patterns (component structure, state management, use of `GlassCard`, window manager integration).
2. Generate the new component (`LiteratureReviewMapper.tsx`) with the necessary imports, state hooks, canvas logic, and IndexedDB integration.
3. Add the app to `DESKTOP_APPS` in `SmartGlassWorkspace.tsx`.
4. Optionally create an API endpoint if cloud sync is required.
5. Run the linter and TypeScript compiler, automatically fix simple errors.
**How it works**: The agent is given access to your project’s source tree, a terminal to execute commands, and a browser to preview the result. It iteratively edits files, runs tests, and corrects mistakes.
### 2.2 Automatic Refactoring & Code Quality
Agents can identify outdated patterns, duplicate code, or performance bottlenecks and propose (or automatically apply) refactors.
- **Example**: Detect that many components manually call `useEffect` for data fetching and suggest replacing them with React Query.
- **Example**: Find repetitive Tailwind class combinations and create a reusable `GlassCard` component (already done).
- **Example**: Uncover missing error boundaries or incorrect key props in lists.
### 2.3 Bug Detection & Fixing
When a bug is reported (e.g., “the unified inbox filter does not update counts after marking a message as read”), an agent can:
1. Replicate the bug by inspecting the frontend state.
2. Trace the code path using static analysis or by simulating user actions.
3. Propose a fix – often by editing a few lines in `useUnifiedInbox.ts` or `InboxMessageCard.tsx`.
4. Run the test suite to verify the fix.
### 2.4 Documentation & Onboarding
Agents can generate comprehensive documentation from the existing codebase:
- Write JSDoc comments for every hook, component, and API function.
- Create a searchable `README.md` that explains the structure of the `api/`, `components/`, and `hooks/` folders.
- Produce a visual “dependency graph” of modules.
For new developers, an agent can act as an interactive guide: answer questions (“how does the window manager store window state?”), provide code examples, and even set up their local development environment.
---
## 3. Agents Inside the Running Platform (User‑Facing)
Once the platform is deployed, AI agents can be embedded as **services** that researchers can invoke through the desktop environment – for example, as a dedicated “AI Assistant” window or as a plugin.
### 3.1 Agents Running on the Server (Centralised)
**Advantages**:
- Can use large, powerful models (GPT‑4, Claude, etc.).
- Central logging, easier to update, shared across all users.
- Can access the full backend database (with proper authorisation).
**Use Cases**:
- **Research Gap Analyzer**: An agent analyses the user’s knowledge graph (from `GapAnalysisDashboard`), identifies under‑explored connections, and suggests novel hypotheses. It can then automatically create new `hypothesis` nodes in the graph.
- **Grant Proposal Writer**: Given an RFP text, the agent drafts a full proposal structure, pulls relevant citations from the reference manager, and writes a first draft in the collaborative editor.
- **Peer Review Assistant**: After a user submits a review, the agent checks for bias, missing criteria, or contradictory statements, and suggests improvements before final submission.
- **Automated Literature Summariser**: For a list of paper DOIs or a search query, the agent fetches abstracts, reads the full texts (if accessible), and produces a structured summary with key findings and limitations.
- **Smart Notification Classifier**: The agent examines incoming notifications and decides whether to show them immediately, batch them, or delay them based on the user’s current deep‑work mode.
**Integration**: These agents run as separate microservices (or as background jobs) that expose REST APIs. The frontend communicates with them via the existing `api/` layer. Results appear as messages in the unified inbox, or as new content in the collaborative editor.
### 3.2 Agents Running on the Client PC (Local)
**Advantages**:
- **Privacy**: Sensitive research data never leaves the user’s machine.
- **Offline capability**: Work without an internet connection.
- **Lower latency**: No network round‑trip.
- **Reduced server load**: Heavy compute is offloaded to the user’s hardware.
**Constraints**: Models must be smaller (e.g., Llama 3‑8B, Phi‑3, Mistral) and may require WebAssembly or local inference engines (Ollama, llama.cpp, or Transformers.js).
**Use Cases**:
- **Local Code Interpreter**: A researcher can open an “AI Sandbox” window, write Python or R code, and execute it inside a WebAssembly sandbox (e.g., Pyodide). The agent helps debug the code, suggests libraries, and visualises results – all without sending any data to the server.
- **On‑Device Text Summarisation**: The user pastes a long PDF excerpt; a small LLM running in the browser summarises it instantly.
- **Offline Graph Generator**: Using a local model to generate citation graph embeddings for the knowledge graph (gap analysis) – valuable when traveling without internet.
- **Personal AI Assistant**: The agent has access to the user’s local drafts, notes, and collections. It helps organise notes, tag research objects, and set reminders – all stored only on the user’s machine.
**Technical Implementation**:
- Use **Transformers.js** (Hugging Face) to run models directly in the browser via WebAssembly or WebGPU.
- Use **Ollama** (or llama.cpp) as a local server; the frontend sends prompts via fetch to `http://localhost:11434`.
- For heavy computations, use **Web Workers** to keep the UI responsive.
**Security**: The local agent runs in a sandboxed iframe or a Web Worker with limited file system access (via the File System Access API, with user permission). It cannot access other browser tabs or the main platform’s DOM.
---
## 4. How Agents Can Write Code in Any Language
Modern LLMs can generate code in **virtually any programming language** (C++, Rust, Go, Python, Ruby, Java, etc.). In the context of your platform, this capability can be used for:
### 4.1 Generating Backend Microservices in Java/Spring
A developer describes: “We need a new microservice that monitors the RAG vector database and re‑indexes documents every night.” The agent creates a complete Spring Boot application with:
- `@Scheduled` cron job.
- Connection to the existing PostgreSQL and vector DB.
- Logging and metrics endpoints.
- Dockerfile and Kubernetes deployment YAML.
### 4.2 Writing Data Science Scripts (Python/R)
Researchers can ask an agent: “Write a Python script using pandas and matplotlib to analyse my lab inventory dataset and predict which chemicals will expire next month.” The agent generates the code, installs dependencies (in a virtual environment), and even runs it on the user’s local machine (with permission).
### 4.3 Translating Between Languages
If the platform originally had a frontend helper script written in JavaScript, but a user prefers to process data in Python, the agent can **transpile** the logic while preserving the original semantics.
### 4.4 Generating SQL Queries
Instead of manually writing complex joins for the analytics dashboard, a researcher describes: “Show me the monthly trend of articles published in the ‘machine learning’ category.” The agent produces the correct PostgreSQL query, optimises indexes, and adds caching hints.
---
## 5. A Concrete Example: Agent‑Powered New Feature Development
**Goal**: Add a “Literature Review” desktop app that allows users to import a set of papers (by DOI) and automatically generate a summarised table (title, authors, abstract, keywords) using an LLM.
**Agent‑Assisted Steps**:
1. The developer opens a “Chat with AI Agent” panel inside the IDE (or a dedicated window).
2. They type: “I want to add a new desktop app called `LiteratureReviewTable` under the research tools category. It should have a text area to paste DOIs (one per line), a ‘Fetch’ button, and a table that displays title, authors, abstract, and a ‘Summarise’ button per row. When clicked, that row’s abstract is sent to an LLM (via our existing `/ai/rag-chat` endpoint) and the summary appears inline. Use the existing `GlassCard` and `AppRunner` pattern. Also add an entry to the desktop icons.”
3. The agent analyses the existing codebase (`AppRunner.tsx`, `GlassCard.tsx`, `DESKTOP_APPS` structure, `useAppStore` hook). It generates:
- `src/components/app-store/LiteratureReviewTable.tsx` (the component).
- Updates `DESKTOP_APPS` in `SmartGlassWorkspace.tsx`.
- Adds an import for the new component.
- Generates a mock API call (later replaced by backend implementation).
4. The agent runs `npm run lint` and fixes any formatting issues.
5. The developer reviews the generated code, manually adjusts the styling, and merges.
6. The agent then writes the backend Spring Boot controller and service that fetches paper metadata from CrossRef or Semantic Scholar, caches it, and integrates with the existing RAG chat endpoint.
7. Finally, the agent produces a unit test for the frontend component (using React Testing Library) and an integration test for the backend endpoint.
**Time saved**: From ~6‑8 hours to ~30 minutes of review.
---
## 6. Operational & Governance Considerations
| Aspect | Recommendation |
|--------|----------------|
| **Security** | Agents should run with **least privilege**. For code generation, they must not have direct access to production credentials. For user‑facing agents, implement strict content filtering and rate limiting. |
| **Cost** | Server‑side agents (using GPT‑4) incur API costs. Local agents (using open‑source models) are free but slower and require more client resources. |
| **Quality** | Always require **human review** of generated code before merging. Use automated tests to verify that agent‑generated code does not break existing functionality. |
| **Versioning** | Store agent‑generated code in version control (Git) with attribution (e.g., “Co‑authored by AI agent”). |
| **User Privacy** | For client‑side agents, clearly indicate that data never leaves the user’s machine. For server‑side agents, enforce data anonymisation and secure data retention policies. |
---
## 7. Implementation Roadmap
1. **Phase 1 – Developer‑facing agents**:
- Integrate a “code assistant” panel into your IDE (e.g., using VS Code extension or a custom web view).
- Grant the agent read‑only access to the repository.
- Allow it to suggest code via pull requests.
2. **Phase 2 – Integrated AI Assistant Window**:
- Create a new desktop app (`AIWindow`) that embeds a chat interface.
- Connect it to a local LLM (Ollama or Transformers.js) with tool‑use capabilities (edit files, run commands).
- Restrict the tool‑use to a sandboxed development environment.
3. **Phase 3 – User‑invocable agents (server side)**:
- Expose a new API endpoint `/api/agent/:task` that accepts a natural language description and returns the result (or an asynchronous job ID).
- Build specialised agents (gap analysis, grant writer) that call external APIs and internal services.
4. **Phase 4 – Offline, client‑side agents**:
- Implement WebAssembly‑based execution of small models (e.g., `transformers.js`) inside `AppRunner`.
- Provide a local “agent store” where users can download pre‑trained, small agents for common research tasks.
---
## 8. Conclusion
AI agents are not a distant future – they can be integrated **today** into your research platform, both to **accelerate development** (writing clean, maintainable code in any language) and to **empower end users** (automating research tasks, generating reports, summarising papers). Because agents can run on the server (centralised, powerful) or on the client (private, offline), you can tailor the solution to each use case.
By embedding agent capabilities, your platform becomes more than a tool – it becomes an **intelligent partner** that researchers can **talk to** and delegate tedious or complex work, all while respecting their privacy and offline needs. 🚀
## Backend Architecture of the Research Platform: A Detailed Explanation
The backend of this research platform is built as a **modular monolith** but is architected with clear **service boundaries** and **asynchronous communication patterns**. This design offers a balance: it avoids the initial complexity of a full microservices architecture while keeping a path open for future scaling. The core of the backend is built on **Spring Boot**, a mature and widely adopted framework that provides essential building blocks for everything from REST APIs to real-time messaging and data persistence.
---
### 1. The Foundation: From Client Request to Server Response
At its core, every action on the platform begins with a request from the frontend. The backend's primary function is to receive these requests, process them, and return a response. This is facilitated by **RESTful APIs** for all data-creating, reading, updating, and deleting (CRUD) operations.
**REST APIs (HTTP/HTTPS):** For standard, non-real-time operations, the frontend uses REST APIs built with **Spring MVC**. Each HTTP method (GET, POST, PUT, DELETE) maps to a specific backend controller method via annotations like `@GetMapping`, `@PostMapping`, etc. For example, when a user creates a new article, the frontend sends a `POST` request to `/api/articles` with the article data in JSON format. The backend’s `ArticleController` receives this, validates the input, saves it to the database, and returns the newly created article object as a JSON response.
**Authentication & Authorization:** Security is managed by **Spring Security**, which uses **JWT (JSON Web Tokens)** for stateless authentication. Upon successful login, the server issues a short-lived `access_token` and a longer-lived `refresh_token`. The frontend stores these and sends the access token in the `Authorization` header of every subsequent request. The backend verifies the token’s signature and extracts the user’s identity and roles. If the token has expired, the frontend can use the refresh token to obtain a new access token without requiring the user to log in again, a feature often implemented with Redis to invalidate tokens on logout.
---
### 2. Real-Time Communication: WebSockets and Beyond
For features requiring instantaneous updates, such as new messages in a chat or real-time collaboration in the document editor, the platform uses **WebSockets**, a persistent, full-duplex communication protocol. This is a stark contrast to REST, where the client must repeatedly poll the server for new data.
#### The WebSocket Stack
The platform uses a layered approach to WebSockets:
* **WebSocket Protocol:** This provides the underlying persistent connection between the client and server.
* **STOMP (Simple Text Oriented Messaging Protocol):** Layered on top of WebSockets, STOMP provides a flexible, message-oriented framing protocol. Instead of raw WebSocket messages, the client and server exchange STOMP frames, which define concepts like `destination`, `content-type`, and `body`.
**How It Works:**
When a user sends a message in a chat, the process is:
1. **Frontend Sends a Message:** The frontend establishes a WebSocket connection to the backend endpoint (e.g., `/ws`). Using the STOMP protocol, it sends a message to a specific destination, e.g., `/app/chat.sendMessage`, containing the message data.
2. **Backend Receives and Publishes:** The backend has a controller with a method annotated with `@MessageMapping("/chat.sendMessage")`. This method is invoked, processes the message (e.g., saves it to the database), and then uses a `SimpMessagingTemplate` to publish the message to a **topic** that all clients in that chat room are subscribed to, such as `/topic/public/${roomId}`.
3. **Other Clients Receive:** All frontend clients connected to the same chat room are subscribed to the `/topic/public/...` destination. The server broadcasts the message to them, and their WebSocket handler processes the incoming message and updates the UI instantly.
This architecture can be scaled horizontally by using an external message broker (like **RabbitMQ** or **Apache Kafka**) as a "broker relay". In that configuration, multiple instances of your backend application can all connect to the same broker, allowing them to publish and subscribe to topics and messages across instances, which is essential for clustering.
---
### 3. The Collaborative Editor: A Specialized Real-Time Engine
The collaborative document editor (`ScientificEditor`) is powered by **Yjs**, a high-performance **CRDT (Conflict-free Replicated Data Type)** library. Yjs is not a typical WebSocket application. It handles the complex logic of merging concurrent edits from multiple users automatically, guaranteeing that everyone ends up with the same final document without any central lock. The platform's architecture for this is unique:
* **Yjs Client on Frontend:** Each user's editor integrates a Yjs client. When a user types, the change is immediately applied to their local Yjs document.
* **Yjs WebSocket Provider:** The frontend uses a `WebsocketProvider` to connect to a **dedicated Yjs WebSocket server** (e.g., running on port 9093). This server is responsible for **relaying** updates between clients.
* **Offline-First Collaboration:** Changes are also persisted to the browser's `IndexedDB` using `y-indexeddb`. If a user goes offline, all their edits are saved locally. When they reconnect, the Yjs protocol automatically syncs their local changes with the server and other peers, ensuring no data is lost. This is a powerful **offline-first** capability built into the architecture.
---
### 4. Beyond Synchronous Calls: Building for Long-Term Scale
As the platform grows, a purely synchronous request/response architecture becomes a bottleneck. To prepare for the future, the platform's design incorporates patterns for asynchronous processing and eventual scalability.
#### Asynchronous and Event-Driven Patterns
For long-running or non-critical tasks (like sending emails or generating PDF exports), the platform can offload work to a background processor using a message queue. The frontend's request is acknowledged immediately, and the actual work happens asynchronously. This is the foundation of an **event-driven architecture (EDA)**, where services communicate primarily through events.
* **Event Sourcing and CQRS:** For critical features with complex history, like the provenance trail, the platform could adopt **Event Sourcing**, where every state change is stored as an immutable event. Combined with **CQRS (Command Query Responsibility Segregation)**, which separates write and read operations, this pattern ensures a complete audit log and can improve scalability.
#### From Monolith to Microservices
To gracefully handle growth, the modular monolith is designed to be split into independent **microservices**. The current `service` layer (e.g., `UserService`, `ArticleService`) defines clear boundaries that could become their own applications. For such an architecture, a set of supporting technologies would be essential:
* **API Gateway:** A central entry point like **Spring Cloud Gateway** would route requests to the correct microservice, handle cross-cutting concerns like **rate limiting**, and manage authentication for the entire system.
* **Service Discovery:** With multiple independent services, they need to find each other. A service registry like **Netflix Eureka** allows services to register themselves and discover others dynamically, avoiding hardcoded IP addresses.
* **Orchestration:** Managing data across services is complex. Patterns like **Sagas**, which use a sequence of local transactions with compensating actions, are used to maintain data consistency.
---
### 5. AI Agents: The Backend’s Cognitive Layer
The platform can embed **AI agents** as specialized microservices. These agents, built with emerging Java frameworks like **Spring AI**, **Koog**, or **Embabel**, can be exposed as standard web endpoints.
* **How the Backend Handles an Agent Request:**
1. A user requests an AI task (e.g., "summarize this paper").
2. The frontend sends a `POST` request to an endpoint like `/api/agent/summarize`.
3. The backend, through a service like `AgentOrchestratorService`, routes the request.
4. The appropriate agent is invoked, possibly calling external LLM APIs or running a local model.
5. The agent returns the result (e.g., the summary).
6. The result can be saved to the database and returned to the frontend.
This architecture keeps your main application layer decoupled from the complexity of AI logic. As frameworks like **Spring AI** mature, they will offer even deeper integration, enabling autonomous, stateful agent workflows.
---
### 6. Summary: A Backend Built for the Future
The following table summarizes how the backend handles different types of workloads:
| **Workload Type** | **Primary Backend Technology** | **Key Characteristic** | **Future Scalability Path** |
| :--- | :--- | :--- | :--- |
| **Synchronous CRUD** | Spring MVC REST APIs | Stateless, request/response | Scale horizontally with more instances |
| **Real-Time Messaging** | WebSockets with STOMP | Stateful, persistent connection | Use external message broker (e.g., Redis, RabbitMQ) |
| **Collaborative Editing** | Yjs WebSocket Provider | CRDT-based, offline-first | Horizontal scaling of Yjs relay servers |
| **Long-Running Tasks** | Message Queues (e.g., RabbitMQ, Kafka) | Asynchronous, event-driven | Scale consumer services independently |
| **Complex Data & Audit** | Event Sourcing + CQRS | Immutable event log, separate read/write models | Decouples reads and writes for independent scaling |
| **AI Features** | Dedicated Agent Microservices | Specialized, potentially stateful | Scale agent services based on demand |
In essence, the backend is not a single monolithic application but a **platform of capabilities**. It handles immediate requests efficiently while providing a robust foundation for asynchronous work, event-driven communication, and future expansion into a full microservices architecture. This layered, forward-thinking design ensures the platform can support researchers for years to come.
# Complete Backend Architecture & Frameworks for the Research Platform
This document provides an exhaustive, in‑depth explanation of the backend technologies, frameworks, design patterns, and operational practices used to build the research platform. It covers everything from the core stack to advanced features like real‑time collaboration, AI agents, and scalable deployment.
---
## 1. High-Level Backend Philosophy
The backend is designed as a **modular monolith** – a single deployable application with clear domain boundaries (services, repositories, controllers). This avoids the complexity of microservices early on while keeping the option to split into distributed services later. The guiding principles are:
- **Statelessness**: Each server instance can handle any request; state is externalized (e.g., to Redis or the database).
- **Event‑driven communication** for asynchronous, decoupled tasks.
- **Security by design** – authentication, authorization, CSRF, rate limiting, and data validation at every layer.
- **Observability** – logs, metrics, and traces are first‑class citizens.
- **Resilience** – timeouts, retries, circuit breakers, and graceful degradation.
---
## 2. Core Frameworks & Libraries (Spring Boot Ecosystem)
The backbone of the backend is **Spring Boot 3.x** (using Java 17/21). Spring Boot provides a convention‑over‑configuration approach and an extensive ecosystem.
| Framework / Library | Purpose | How It Is Used |
|---------------------|---------|----------------|
| **Spring Framework** | Core IoC (Inversion of Control), DI, AOP | All services, repositories, and controllers are Spring beans. Dependency injection decouples layers. |
| **Spring MVC** | REST API layer | Controllers map HTTP endpoints (e.g., `@RestController`, `@GetMapping`). Request validation with `@Valid`. |
| **Spring Data JPA** | Database access (ORM) | Repositories extend `JpaRepository`. Entities mapped with `@Entity`. Hibernate as the JPA provider. |
| **HikariCP** | Connection pooling | Default in Spring Boot 2+; highly performant, zero‑overhead configuration. |
| **Spring Security** | Authentication & authorization | JWT‑based stateless authentication. Method security with `@PreAuthorize`. CORS configuration. |
| **Spring WebSocket** | Real‑time messaging | WebSocket endpoint (`/ws`) with STOMP protocol. Handles chat, typing indicators, notifications. |
| **Spring Scheduling** | Background jobs | `@Scheduled` for daily digest emails, cleanup tasks, index rebuilding. |
| **Spring Cache** | Caching abstraction | `@Cacheable`, `@CacheEvict` with Redis or Caffeine as backing cache. |
| **Spring Actuator** | Monitoring & management | Exposes `/health`, `/metrics`, `/info`, `/prometheus` endpoints. |
### 2.1 Why Spring Boot?
- **Production‑ready features** (Actuator, metrics, health checks) out of the box.
- **Huge community** and compatibility with almost any Java library.
- **GraalVM native image** support for lower memory footprint and faster startup (if needed).
- **Long‑term support** from VMware.
---
## 3. Database & Data Persistence
### 3.1 Relational Database: PostgreSQL
- **Why PostgreSQL**: ACID compliant, supports JSONB (useful for dynamic metadata), full‑text search, and excellent performance under analytical workloads.
- **Connection Pool**: HikariCP – default with Spring Boot, minimal configuration.
- **Migration Tool**: **Flyway** (or Liquibase). SQL migrations in `db/migration` run automatically on startup.
### 3.2 JPA & Hibernate
- Entities use `@Entity`, relationships (`@OneToMany`, `@ManyToOne`), and lazy loading.
- **Custom repositories** with `@Query` for complex queries.
- **Auditing**: `@CreatedDate`, `@LastModifiedDate` via Spring Data Auditing.
### 3.3 Caching with Redis
- **Purpose**: Reduce database load, speed up repeated reads (user profiles, session data, rate‑limit counters).
- **Spring Cache** with Redis as the provider.
- **Use cases**:
- User session storage (when horizontally scaling).
- Rate limiting counters (bucket4j with Redis backend).
- Query cache for expensive joins (e.g., article recommendations).
### 3.4 Full‑Text Search (Optional but Recommended)
- **Elasticsearch** or **OpenSearch** can be integrated for advanced search over articles, messages, and users.
- Synchronization can be done via **change data capture** (Debezium) or by emitting events after entity changes.
---
## 4. Real‑Time Communication & Messaging
### 4.1 WebSocket + STOMP (for Chat & Notifications)
- **Endpoint**: `/ws` (configurable).
- **STOMP** provides a message‑oriented protocol over WebSockets.
- **Flow**:
1. Client subscribes to a topic (e.g., `/topic/messages/room-123`).
2. Client sends a message to a destination like `/app/chat.sendMessage`.
3. Controller (`@MessageMapping`) processes the message, persists it, then uses `SimpMessagingTemplate` to broadcast to all subscribers.
- **Scaling**: Use an external broker (RabbitMQ or Kafka) as a “broker relay” to share messages across multiple backend instances.
### 4.2 Collaborative Editing with Yjs
- **Separate WebSocket server** (e.g., `y-websocket`) running on a different port (9093).
- **Why not use the main WebSocket?** The Yjs protocol is very chatty and benefits from a dedicated, lightweight relay.
- **Client**: Frontend uses `y-websocket` provider to sync changes.
- **Persistence**: Yjs documents can be persisted to the main database (PostgreSQL) for long‑term storage, but the primary real‑time relay is stateless.
### 4.3 Asynchronous Messaging (RabbitMQ / Kafka)
- **Purpose**: Handle long‑running or background tasks.
- **Examples**:
- Sending emails after user registration.
- Generating PDF exports of documents.
- Indexing new articles in Elasticsearch.
- Training recommendation models.
- **Implementation**: Spring AMQP for RabbitMQ, or Spring Kafka. Producers send messages to queues; consumers (asynchronous) process them and update the database or call external services.
---
## 5. Security Architecture
### 5.1 Authentication: JWT (Stateless)
- **Login endpoint**: `/api/login` returns `access_token` (short expiry, e.g., 15 min) and `refresh_token` (httpOnly cookie or stored in database).
- **Access token** is sent in `Authorization: Bearer` header.
- **Refresh token** endpoint `/api/token/refresh` returns new access token.
- **Spring Security** with custom `JwtAuthenticationFilter` that validates the token and sets `SecurityContext`.
### 5.2 Two‑Factor Authentication (TOTP)
- **Library**: Google Authenticator (`com.warrenstrange:googleauth`).
- **Flow**: User enables 2FA → server generates secret + QR code → user scans and verifies first code → backup codes generated.
- **Backup codes** stored encrypted in database.
### 5.3 Authorization: Role‑Based (RBAC)
- **Roles**: `USER`, `ADMIN`, `MODERATOR` (extensible).
- `@PreAuthorize("hasRole('ADMIN')")` on admin endpoints.
### 5.4 CSRF Protection
- Enabled by default in Spring Security for state‑changing endpoints (POST, PUT, DELETE).
- Since the API is stateless and uses JWT, CSRF tokens can be disabled or handled via a custom filter.
### 5.5 Rate Limiting
- **Library**: Bucket4j (token bucket algorithm).
- Backed by Redis for distributed counters.
- Applied via a custom Spring interceptor or Spring Cloud Gateway.
- Limits per endpoint, per user, or per IP.
### 5.6 Data Sanitization & Validation
- **Input validation**: `@NotNull`, `@Size`, `@Pattern` on DTOs.
- **XSS prevention**: Escape user‑generated HTML before storing; use `HtmlUtils.htmlEscape` or OWASP Encoder.
### 5.7 Secrets Management
- **Environment variables** for database password, JWT secret, API keys.
- For production: **HashiCorp Vault** or **AWS Secrets Manager**.
---
## 6. AI Agents & LLM Integration
### 6.1 How the Backend Handles AI Agents
AI agents are implemented as **specialised microservices** or **Spring components** that integrate with Large Language Models (LLMs). The backend exposes endpoints that invoke these agents.
**Frameworks**:
- **Spring AI** (emerging) – provides abstractions for chat completions, embeddings, and function calling.
- **LangChain4j** – Java port of LangChain; supports many LLM providers and vector stores.
- **Custom HTTP clients** to OpenAI, Anthropic, Cohere, or local models (Ollama, llama.cpp).
**Typical Agent Workflow**:
1. Frontend sends a request to `/api/agent/summarize` with paper content.
2. Backend (Agent Orchestrator) selects the appropriate agent.
3. Agent formats a prompt (with role, context, and instructions).
4. Agent calls the LLM (OpenAI API or local) and receives the response.
5. Backend may post‑process the response (extract JSON, validate).
6. Result is saved to the database (e.g., as a `PaperSummary` entity) and returned to the frontend.
### 6.2 Running Agents on the Server vs. Client
| Aspect | Server‑side Agent | Client‑side (Local) Agent |
|--------|-------------------|----------------------------|
| **Models** | Large (GPT‑4, Claude), proprietary or hosted open‑source | Small models (Phi‑3, Llama 3‑8B) via Transformers.js or Ollama |
| **Privacy** | Data leaves user’s machine | Data stays on user’s machine |
| **Latency** | Depends on network and API | Very low after initial model load |
| **Resource Usage** | Central server resources (GPU optional) | User’s RAM/GPU (high for large models) |
| **Offline** | Requires internet | Works offline |
| **Implementation** | Spring AI client, async tasks | WebAssembly + local server (Ollama) or pure browser inference |
The backend can support **both** – offer server agents for heavy tasks (e.g., training a custom model) and provide APIs for client agents to call when they need fallback or centralised data.
### 6.3 Example: Research Agent for Gap Analysis
- **Agent type**: Server‑side, using GPT‑4 via Spring AI.
- **Input**: Research question (e.g., “What are the open problems in few‑shot learning?”)
- **Process**:
1. Agent queries the knowledge graph database for existing nodes.
2. Fetches recent papers from Semantic Scholar.
3. Combines with LLM to propose three new research hypotheses.
4. Stores hypotheses as new nodes in the gap‑analysis graph.
- **User sees**: New `hypothesis` nodes appear in the knowledge graph, ready to be explored.
---
## 7. Asynchronous & Scheduled Tasks
### 7.1 `@Async` (Spring) for Simple Background Tasks
- Enables with `@EnableAsync`.
- Use a custom `ThreadPoolTaskExecutor` (e.g., core=4, max=10).
- Return `CompletableFuture` for non‑blocking calls.
### 7.2 Message Queues for Durable, Scalable Processing
- **RabbitMQ** (simpler) or **Kafka** (high‑throughput, retention).
- Example: When a new article is published, an event is sent to a `article.published` exchange. Multiple consumers (email service, search indexer, recommendation engine) process it independently.
- This decouples the main request lifecycle from the background work.
### 7.3 Scheduled Jobs (`@Scheduled`)
- **Cron expressions** for daily digests, database cleanups, certificate renewal.
- To prevent duplicate execution in a cluster, use **ShedLock** with a shared database table or Redis.
---
## 8. Resilience & Fault Tolerance
| Pattern | Implementation | When to Use |
|---------|----------------|--------------|
| **Retries** | Spring Retry (`@Retryable`) | Transient failures (network timeouts, database deadlocks). |
| **Circuit Breaker** | Resilience4j | External service (LLM API, recommendation model) starts failing; avoid cascading failures. |
| **Bulkhead** | Resilience4j (thread pool or semaphore isolation) | Limit concurrent access to a critical resource (e.g., database connection pool). |
| **Timeout** | `@Transactional(timeout = ...)` or Resilience4j | Prevent long‑running requests from exhausting threads. |
| **Rate Limiter** | Bucket4j | Protect against API abuse, both per user and per endpoint. |
---
## 9. Observability (Logging, Metrics, Tracing)
### 9.1 Logging
- **SLF4J + Logback** (Spring Boot default).
- **Structured logging** (JSON) to integrate with ELK or Loki.
- **Log levels**: DEBUG for development, INFO for production, WARN/ERROR for issues.
- **MDC** (Mapped Diagnostic Context) to inject trace ID, user ID, request ID.
### 9.2 Metrics (Micrometer + Prometheus)
- Micrometer collects: request count, response time histogram, error count, JVM memory, thread pools, database connection pool.
- Prometheus scrapes metrics from `/actuator/prometheus`.
- **Grafana** dashboards visualise the data.
### 9.3 Distributed Tracing (OpenTelemetry)
- **OpenTelemetry** Java agent auto‑instruments Spring Boot, HTTP clients, JDBC, etc.
- Export traces to **Jaeger** or **Tempo**.
### 9.4 Health Checks
- Spring Actuator provides `/health` (liveness) and `/health/readiness` (readiness).
- Used by Kubernetes for probes.
---
## 10. Testing Strategy
| Test Type | Tools | Coverage |
|-----------|-------|----------|
| **Unit** | JUnit 5, Mockito | Services, utilities, mappers. |
| **Integration** | `@SpringBootTest`, Testcontainers | Controllers, repository operations, WebSocket communication. |
| **Contract** | Spring Cloud Contract or Pact | API contract between frontend and backend. |
| **End‑to‑End** | Playwright (frontend) + Testcontainers (backend) | Critical user flows (login → create article → send message). |
| **Load** | JMeter, Gatling, k6 | Simulate high concurrency. |
**Testcontainers** is especially useful: it spins up real PostgreSQL, Redis, RabbitMQ containers for integration tests.
---
## 11. Deployment & CI/CD
### 11.1 Containerisation (Docker)
- **Dockerfile** using `eclipse-temurin:17-jre` as base.
- Layered builds to cache dependencies.
- Use of **Jib** (Google) for optimized, secure images without Docker daemon.
### 11.2 Orchestration (Kubernetes)
- **Deployment** with multiple replicas for high availability.
- **ConfigMaps** for environment variables.
- **Secrets** for sensitive data (database passwords, JWT secret).
- **Horizontal Pod Autoscaler** based on CPU/memory or custom metrics (e.g., queue length).
- **Ingress** with TLS termination (Let’s Encrypt).
### 11.3 CI/CD Pipeline (GitHub Actions)
- Stages: `checkout → setup JDK → cache dependencies → unit tests → integration tests → build image → push to registry → deploy to staging → (manual approval) → deploy to production`.
- **Security scanning**: Snyk or Trivy for vulnerabilities in dependencies and Docker image.
- **Rollback**: Revert deployment to previous revision.
### 11.4 Blue‑Green / Canary Deployments
- **Argo Rollouts** or **Flagger** for progressive delivery.
- Blue‑green: two identical environments; switch traffic instantly.
- Canary: route a small percentage of users to the new version, monitor error rate, then increase gradually.
---
## 12. Scalability Techniques
| Technique | How It Helps |
|-----------|---------------|
| **Stateless services** | Any instance can handle any request → easy horizontal scaling. |
| **Read replicas** | Scale read queries (e.g., article listings) to replica databases; writes go to the primary. |
| **Caching (Redis)** | Reduce database load; store user sessions, rate‑limit counters, frequently accessed data. |
| **Asynchronous processing** | Offload long tasks to background workers; keep web threads free. |
| **Database partitioning** | Split large tables (e.g., `messages`) by date or user ID. |
| **Indexing** | Proper database indexes; Elasticsearch for search. |
---
## 13. Example Technology Stack Summary
| Layer | Technology / Library |
|-------|----------------------|
| **Language** | Java 17 (LTS) |
| **Framework** | Spring Boot 3.2.x |
| **Security** | Spring Security, JJWT (for JWT), Google Auth (2FA) |
| **Database** | PostgreSQL 15+ with Hibernate (Spring Data JPA) |
| **Migration** | Flyway |
| **Caching** | Redis (via Spring Cache) |
| **Messaging / Queue** | RabbitMQ (AMQP) or Kafka |
| **WebSocket** | Spring WebSocket + STOMP, optional RabbitMQ broker relay |
| **Collaborative editor** | Yjs + y-websocket server (Node.js or Java) |
| **Search** | Elasticsearch (optional) |
| **Monitoring** | Micrometer + Prometheus + Grafana |
| **Logging** | Logback (JSON), Loki |
| **Tracing** | OpenTelemetry + Jaeger |
| **Rate Limiting** | Bucket4j + Redis |
| **Resilience** | Resilience4j, Spring Retry |
| **Testing** | JUnit 5, Mockito, Testcontainers, RestAssured |
| **Container** | Docker + Jib |
| **Orchestration** | Kubernetes (EKS / GKE / AKS) |
| **CI/CD** | GitHub Actions |
| **AI Integration** | Spring AI / LangChain4j, OpenAI API, Ollama (local) |
---
## 14. Conclusion
The backend of your research platform is built on a robust, production‑proven stack that emphasizes **reliability**, **security**, and **extensibility**. By leveraging Spring Boot’s ecosystem, you get:
- Clean separation of concerns (controllers, services, repositories).
- Powerful real‑time communication via WebSockets + STOMP.
- Scalable event‑driven architecture using message queues.
- AI agent integration that can run both on the server (heavy models) and on the client (private, offline).
- Comprehensive observability, testing, and deployment pipelines.
This architecture not only serves the current feature set but also provides clear paths to split into microservices, adopt new AI capabilities, and handle thousands of concurrent researchers. 🚀
# Complete Backend Component Connections & Data Flow
This document explains, in exhaustive detail, how every backend component connects to every other component, and how the frontend communicates with them. The goal is to provide a complete picture of the system’s internal communication patterns, protocols, and data flows.
---
## 1. Overview of Components and Their Roles
| Component | Role | Technology / Protocol |
|-----------|------|------------------------|
| **Frontend (React)** | User interface, window manager, desktop environment | HTTP/HTTPS, WebSocket, Yjs WebSocket |
| **Backend (Spring Boot)** | REST APIs, WebSocket (STOMP), business logic, database access, background tasks | HTTP/HTTPS, WebSocket (STOMP), AMQP (RabbitMQ) / Kafka |
| **PostgreSQL** | Primary database | JDBC (via Hibernate) |
| **Redis** | Caching, session storage, rate limiting counters, distributed locks | TCP (Redis protocol) |
| **RabbitMQ / Kafka** | Message broker for async tasks | AMQP 0-9-1 (RabbitMQ) or TCP (Kafka) |
| **Yjs WebSocket Server** | Real‑time document collaboration (CRDT) | WebSocket (raw) |
| **Elasticsearch (optional)** | Full‑text search | HTTP REST |
| **LLM Provider (OpenAI / local)** | AI agent capabilities | HTTPS / HTTP |
| **Object Storage (S3 / MinIO)** | File storage for manuscripts, avatars, research objects | HTTP REST (S3 API) |
| **SMTP Server** | Email sending | SMTP |
---
## 2. Communication Protocols and Ports
| Protocol | Used For | Typical Port |
|----------|----------|--------------|
| **HTTP/HTTPS** | REST API calls between frontend and backend | 8080 (backend), 443 (frontend reverse proxy) |
| **WebSocket (STOMP)** | Real‑time chat, typing, notifications | 8080 (upgraded HTTP) |
| **WebSocket (raw Yjs)** | Collaborative editing updates | 9093 |
| **TCP (PostgreSQL)** | Database connection | 5432 |
| **TCP (Redis)** | Cache / session store | 6379 |
| **AMQP (RabbitMQ)** | Asynchronous messaging | 5672, 15672 (management) |
| **TCP (Kafka)** | Event streaming | 9092 |
| **HTTP (Elasticsearch)** | Search queries | 9200 |
| **HTTPS (LLM API)** | AI agent inference | 443 |
| **HTTPS (S3 API)** | File upload/download | 443 (or 9000 for MinIO) |
| **SMTP** | Email sending | 25, 465, 587 |
---
## 3. Detailed Component Connections
### 3.1 Frontend ↔ Backend (REST API)
- **Direction**: Bidirectional (request/response).
- **Protocol**: HTTP/HTTPS.
- **Authentication**: JWT in `Authorization` header.
- **Example flow**:
1. Frontend sends `POST /api/articles` with JSON body.
2. Backend controller (`ArticleController`) receives, validates, calls `ArticleService`, saves via `ArticleRepository`.
3. Backend returns HTTP 201 with the created article JSON.
- **Load balancing**: Nginx or Kubernetes Ingress distributes requests across multiple backend pods.
### 3.2 Frontend ↔ Backend (WebSocket – STOMP)
- **Endpoint**: `ws://backend/ws` (or `/ws` with upgrade).
- **Connection initiation**:
1. Frontend creates a WebSocket connection.
2. STOMP client handshake (CONNECT frame with authentication token).
3. Backend authenticates using the token (e.g., via `ChannelInterceptor`).
- **Subscription**:
- Client sends `SUBSCRIBE` frame to a destination, e.g., `/topic/messages/room-123`.
- Backend remembers the session.
- **Publishing**:
- Client sends `SEND` frame to `/app/chat.sendMessage`.
- Backend `@MessageMapping` method processes the message.
- Backend uses `SimpMessagingTemplate.convertAndSend(destination, payload)` to broadcast to all subscribers.
- **Broker Relay** (for scaling):
- Spring’s `@EnableWebSocketMessageBroker` can be configured with `setRelayHost` to forward messages to an external RabbitMQ broker.
- Then multiple backend instances share the same broker; each instance subscribes to the broker, and the broker distributes messages to all instances (which in turn push to their local client connections).
### 3.3 Frontend ↔ Yjs WebSocket Server
- **Endpoint**: `ws://yjs-server:9093` (separate from main backend).
- **Why separate**: Yjs WebSocket protocol is different from STOMP; mixing them would add complexity.
- **Connection flow**:
1. Frontend creates a Yjs document (`new Y.Doc()`).
2. Initializes `WebsocketProvider` with the server URL, room name (docId), and the Ydoc.
3. The WebSocket provider connects and sends a “sync” message.
4. Yjs server maintains a list of connections per room.
5. When any client makes a local change, the Yjs provider sends an update message; the server relays it to all other clients in the same room.
6. The Yjs server does not persist data; it’s stateless. Persistence (offline) is done by the frontend via `y-indexeddb`. Long‑term storage can be added by having the server also write to PostgreSQL (optional).
- **Authentication**: The Yjs server can be configured to check a token (e.g., by providing a custom authentication callback). The frontend includes the JWT in the connection URL as a query parameter: `ws://yjs-server:9093?token=...`. The server validates the token and maps it to a user ID.
### 3.4 Backend ↔ PostgreSQL
- **Connection**: Hibernate / Spring Data JPA uses a HikariCP connection pool.
- **Configuration**: `spring.datasource.url`, username, password.
- **Transactions**: `@Transactional` declarative boundaries.
- **Read replicas**: Spring can be configured with `RoutingDataSource` to route read queries (`@Transactional(readOnly=true)`) to a replica.
### 3.5 Backend ↔ Redis
- **Use cases**:
- **Caching** (`@Cacheable`): e.g., user profiles, article trending lists.
- **Rate limiting counters** (Bucket4j Redis backend).
- **Distributed locks** (e.g., ShedLock for scheduled jobs).
- **Session storage** (when clustering, store `SecurityContext` in Redis).
- **Client**: Lettuce (default in Spring Boot) or Jedis.
- **Serialization**: JSON (Jackson) or Protobuf for performance.
### 3.6 Backend ↔ RabbitMQ / Kafka
- **Purpose**: Decouple time‑consuming or non‑critical tasks from the request/response cycle.
- **Producer side** (e.g., after article publication):
```java
@Service
public class ArticleService {
@Autowired
private RabbitTemplate rabbitTemplate;
public Article publish(Article article) {
// save article to DB
rabbitTemplate.convertAndSend("exchange", "routingKey", new ArticlePublishedEvent(article));
return article;
}
}
```
- **Consumer side** (e.g., email service, search indexer):
```java
@RabbitListener(queues = "article.published.queue")
public void handle(ArticlePublishedEvent event) { ... }
```
- **Kafka** uses `@KafkaListener` instead.
- **Integration**: Spring AMQP / Spring Kafka provide auto‑configuration.
### 3.7 Backend ↔ Elasticsearch
- **Why**: Fast full‑text search across articles, messages, users.
- **Sync strategy**:
- After an article is created/updated, the service sends a message via RabbitMQ.
- A separate consumer (can be the same backend instance or a dedicated search service) listens to the queue and updates the Elasticsearch index.
- Alternatively, use Change Data Capture (Debezium) to stream DB changes directly to Elasticsearch.
- **Query**: Frontend calls a search endpoint (`/api/articles/search`), the backend translates the request to an Elasticsearch query and returns the results.
### 3.8 Backend ↔ LLM Provider (AI Agent)
- **Provider options**:
- **OpenAI / Anthropic / Cohere**: HTTPS calls to their APIs.
- **Local model (Ollama)**: HTTP to `http://localhost:11434` (if running on same host) or to a dedicated inference service.
- **Spring AI** provides a consistent `ChatClient` interface:
```java
String summary = chatClient.call("Summarize this paper: " + paperText);
```
- **Agent orchestration**:
- Backend endpoint `/api/agent/analyze` receives request.
- `AgentOrchestratorService` selects the appropriate agent (e.g., `GapAnalysisAgent`).
- Agent builds a prompt, calls LLM, parses response, and may call other internal APIs (e.g., the knowledge graph service).
- The result is stored (e.g., as a new `Hypothesis` entity) and returned to frontend.
### 3.9 Backend ↔ Object Storage (S3 / MinIO)
- **Use cases**: Store uploaded files – avatars, manuscript PDFs, research objects, exported documents.
- **Flow**:
1. Frontend sends file to backend (multipart form data) or directly uses presigned URL.
2. Backend (if using presigned URL): calls `GeneratePresignedUrlRequest` on S3 client, returns URL to frontend; frontend uploads directly to S3.
3. Backend stores the file URL in the database.
- **Client**: AWS SDK for Java (S3).
### 3.10 Backend ↔ SMTP Server
- **Use**: Sending emails – password reset, email verification, daily digest, notifications.
- **Integration**: `JavaMailSender` (Spring Boot starter).
- **Configuration**: `spring.mail.host`, port, username, password.
- **Templates**: Thymeleaf or FreeMarker for HTML emails.
---
## 4. Data Flow for a Critical User Action: Sending a Group Message
This concrete example ties all components together.
1. **User types message in ChatArea** and clicks “Send”.
2. **Frontend**:
- Optimistically adds message to local state (temp ID, “sending” status).
- Sends via WebSocket STOMP: `stompClient.send("/app/group.sendMessage", {}, JSON.stringify({ groupId, body, replyToId }))`.
3. **Backend WebSocket (@MessageMapping)**:
- Method `handleGroupMessage` in `GroupChatController` receives the message.
- Validates user membership in group.
- Calls `GroupMessageService.saveMessage(...)` which persists to PostgreSQL (via `GroupMessageRepository`).
- After successful save, uses `SimpMessagingTemplate.convertAndSend("/topic/group/" + groupId, messageDTO)` to broadcast.
- Also sends a message to a RabbitMQ queue `group.message.sent` for analytics / notification processing.
4. **Broadcast**:
- All other clients subscribed to `/topic/group/groupId` receive the message.
- Their frontend WebSocket handler updates the message list.
5. **Asynchronous processing**:
- A `@RabbitListener` on `group.message.sent` queue fetches the message.
- It updates the `lastMessage` and `unreadCount` for each group member (batch update).
- Also triggers a push notification (via WebSocket or Firebase) if the user is offline.
6. **Read receipt**:
- When a user views the group, the frontend sends a STOMP message to `/app/group.markRead`.
- Backend marks the user’s last read timestamp and sends a “read receipt” event to the group topic.
---
## 5. Inter‑Service Communication (within the Backend)
Even though the backend is a monolith, its internal services communicate through:
- **Direct method calls**: `ArticleService` calls `UserService` to get author profile.
- **Application events** (Spring `ApplicationEventPublisher`): Decouples modules. For example, `ArticleService` publishes `ArticlePublishedEvent`; `AnalyticsService` listens and updates statistics.
- **Message queue** (RabbitMQ/Kafka) for cross‑module communication that should be asynchronous and durable. This also paves the way for future microservice extraction.
---
## 6. Scaling and High Availability
| Component | How to Scale |
|-----------|--------------|
| **Backend (Spring Boot)** | Horizontal scaling – multiple pods behind a load balancer. **Stateless** design required. |
| **WebSocket connections** | Sticky sessions (session affinity) or using a shared broker (RabbitMQ) to distribute messages across instances. |
| **Yjs WebSocket Server** | Also stateless; multiple instances can be deployed; clients connect to one instance. Since Yjs updates are based on room (docId), the server can use a consistent hashing strategy or simply rely on the frontend to reconnect if one instance goes down. However, Yjs does **not** share state across servers; if you need that, you would need a shared backend store (e.g., Redis or CRDTs across servers). For most use cases, a single Yjs server with a backup is enough. |
| **PostgreSQL** | Read replicas, connection pooling, vertical scaling, or partitioning. |
| **Redis** | Redis Cluster or Redis Sentinel. |
| **RabbitMQ** | Cluster mode. |
| **Kafka** | Partition replication. |
---
## 7. Security Between Components
| Connection | Security Measure |
|------------|------------------|
| Frontend ↔ Backend (REST) | JWT over HTTPS; rate limiting; input validation. |
| Frontend ↔ Backend (WebSocket) | JWT passed in connection (e.g., as `Authorization` header during STOMP handshake). |
| Frontend ↔ Yjs Server | JWT as query parameter; Yjs server validates token. |
| Backend ↔ PostgreSQL | TLS (sslmode=require) and database user/password. |
| Backend ↔ Redis | Password authentication; optional TLS. |
| Backend ↔ RabbitMQ | Username/password; TLS; separate vhosts. |
| Backend ↔ Elasticsearch | TLS and API key. |
| Backend ↔ LLM API | API key in HTTPS header. |
| Backend ↔ S3 | IAM roles (on cloud) or access/secret keys with TLS. |
---
## 8. Deployment Topology (Example)
```
[Internet]
↓
[Cloud Load Balancer (e.g., AWS ALB)] (443/80)
↓
[Reverse Proxy / Ingress (nginx)] (forward to backend on 8080)
↓
[Backend Pods (Spring Boot)] – multiple replicas
├─→ PostgreSQL (primary + read replica)
├─→ Redis (cluster)
├─→ RabbitMQ (cluster)
├─→ Yjs Server (one or more pods)
├─→ Elasticsearch (cluster)
└─→ S3 / MinIO
```
- **WebSocket connections** (chat) go through the same load balancer; they require **sticky sessions** (session affinity) or a shared broker. Using an external RabbitMQ as the broker relay removes the need for sticky sessions for STOMP messages.
- **Yjs WebSocket connections** often go to a separate endpoint (e.g., `ws://yjs.yourdomain.com`). This can be a different load balancer or a subdomain.
---
## 9. Summary Table: Component Connections
| From | To | Protocol | Port (typical) | Purpose |
|------|----|----------|----------------|---------|
| Frontend | Backend (REST) | HTTP | 443/8080 | All CRUD operations |
| Frontend | Backend (STOMP) | WebSocket | 443/8080 | Real‑time chat, notifications |
| Frontend | Yjs Server | WebSocket | 9093 | Collaborative editing |
| Backend | PostgreSQL | JDBC (TCP) | 5432 | Data persistence |
| Backend | Redis | TCP | 6379 | Caching, rate limiting |
| Backend | RabbitMQ | AMQP | 5672 | Async tasks, event distribution |
| Backend | Elasticsearch | HTTP | 9200 | Full‑text search |
| Backend | LLM API | HTTPS | 443 | AI agent inference |
| Backend | S3 / MinIO | HTTPS | 443/9000 | File storage |
| Backend | SMTP | TCP | 587 | Email sending |
| Backend (or external) | Yjs Server | WebSocket | 9093 | (Only if backend needs to act as a Yjs client) |
---
## 10. Conclusion
All components are interconnected through well‑defined protocols and standards: HTTP, WebSocket, JDBC, Redis protocol, AMQP, and more. The design uses **loose coupling** where possible (e.g., event‑driven communication via RabbitMQ) to allow independent scaling and evolution. The frontend communicates with three distinct endpoints:
- REST for normal operations.
- STOMP WebSocket for real‑time chat.
- Yjs WebSocket for collaborative editing.
The backend acts as the orchestrator, integrating the database, cache, message broker, search engine, AI services, and object storage into a cohesive platform. This architecture ensures high performance, reliability, and extensibility for a research environment. 🚀
# Complete Backend Source Code Structure (Java Spring Boot)
This document provides a **complete, ready-to-implement folder and file tree** for the backend of the research platform. All files are named according to standard Spring Boot conventions and grouped by feature. You can use this as a blueprint to create the exact directory structure and file names for your project.
The backend is built with **Java 17**, **Spring Boot 3.x**, **Maven** (or Gradle), **PostgreSQL**, **Redis**, **RabbitMQ**, and optional **Elasticsearch**. The structure is modular, with clear separation of concerns: controllers, services, repositories, DTOs, entities, configuration, security, and integration components.
---
## 1. Overview of the Backend Directory Tree
```
src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── ie/
│ │ └── researchplatform/
│ │ ├── ResearchPlatformApplication.java
│ │ ├── config/
│ │ ├── controller/
│ │ ├── service/
│ │ ├── repository/
│ │ ├── model/
│ │ ├── dto/
│ │ ├── security/
│ │ ├── event/
│ │ ├── listener/
│ │ ├── messaging/
│ │ ├── collaboration/
│ │ ├── ai/
│ │ ├── util/
│ │ ├── exception/
│ │ └── integration/
│ └── resources/
│ ├── application.yml
│ ├── application-dev.yml
│ ├── application-prod.yml
│ ├── db/migration/
│ ├── templates/ (email templates)
│ └── static/
├── test/
│ └── java/
│ └── com/ie/researchplatform/ (tests mirroring main)
└── pom.xml (or build.gradle)
```
---
## 2. Detailed File Tree with Explanations
### 2.1 Main Application Entry Point
```
com/ie/researchplatform/
└── ResearchPlatformApplication.java
```
- `@SpringBootApplication` annotation.
- Contains `main` method.
### 2.2 Configuration Classes (`config/`)
| File | Purpose |
|------|---------|
| `AppConfig.java` | General beans (e.g., `RestTemplate`, `ObjectMapper`). |
| `DatabaseConfig.java` | Data source settings, Hibernate properties, connection pool tuning. |
| `RedisConfig.java` | Redis connection factory, cache manager, serialization. |
| `RabbitMQConfig.java` | Exchanges, queues, bindings for async processing. |
| `WebSocketConfig.java` | STOMP endpoint configuration, broker relay. |
| `SecurityConfig.java` | Spring Security filters, JWT authentication, CORS, CSRF. |
| `AsyncConfig.java` | `@EnableAsync`, thread pool executors. |
| `SchedulingConfig.java` | `@EnableScheduling`, custom scheduler. |
| `SwaggerConfig.java` | OpenAPI (SpringDoc) configuration. |
| `ElasticsearchConfig.java` | RestHighLevelClient (if used). |
| `AwsS3Config.java` | S3 client configuration (if using object storage). |
| `MailConfig.java` | JavaMailSender configuration. |
### 2.3 Controllers (`controller/`)
Each controller maps to a domain. All endpoints are prefixed with `/api`.
| File | Endpoint Base | Description |
|------|---------------|-------------|
| `AuthController.java` | `/api/auth` | Login, logout, refresh token, 2FA verification. |
| `UserController.java` | `/api/users` | Profile, follow, contacts, avatar upload. |
| `ArticleController.java` | `/api/articles` | CRUD, search, like, comment, analytics, publish. |
| `MessageController.java` | `/api/messages` | Private message history, forward, reactions. |
| `ConversationController.java` | `/api/conversations` | List conversations, delete, archive, typing, read status. |
| `GroupController.java` | `/api/groups` | Group CRUD, members, admins, messages, pins, mute. |
| `GroupMessageController.java` | `/api/groups/{id}/messages` | Group message operations. |
| `PollController.java` | `/api/polls` | Poll creation, voting, results. |
| `NotificationController.java` | `/api/notifications` | Fetch notifications, mark read, delete. |
| `RecommendationController.java` | `/api/recommendations` | Feed, trending, similar articles. |
| `CollectionController.java` | `/api/collections` | Paper collections CRUD. |
| `ReferenceController.java` | `/api/references` | Reference import (DOI, BibTeX, Zotero, Mendeley). |
| `DocumentController.java` | `/api/documents` | Collaborative document references, export. |
| `PreprintController.java` | `/api/preprints` | Screening and submission. |
| `ProvenanceController.java` | `/api/provenance` | Fetch events, verify chain. |
| `UnifiedInboxController.java` | `/api/unified-inbox` | Aggregated inbox. |
| `RagController.java` | `/api/ai/rag` | RAG chat, indexing, conversation. |
| `GapAnalysisController.java` | `/api/gap-analysis` | Nodes, edges, AI analysis, hypothesis generation. |
| `GrantController.java` | `/api/grants` | Grant deadlines, RFP analysis, generation. |
| `LabInventoryController.java` | `/api/inventory` | Chemicals, alerts, scan, compatibility, stats. |
| `PeerReviewController.java` | `/api/peer-review` | Submissions, claims, reviews, credentials. |
| `ProjectController.java` | `/api/projects` | Projects, members, tasks, outputs. |
| `EventController.java` | `/api/events` | Event CRUD, RSVP, reminders, calendar export. |
| `WorkspaceController.java` | `/api/workspace` | Panels, presets, sharing. |
| `VoiceSettingsController.java` | `/api/voice` | TTS voices, user settings, wake words. |
| `AdminController.java` | `/api/admin` | Stats, user/article/RAG management. |
| `PluginController.java` | `/api/plugins` | App store – list, install, submit. |
| `HealthController.java` | `/health` | Liveness/readiness probes. |
### 2.4 Services (`service/`)
Each service contains business logic, orchestration, and transaction boundaries.
| File | Description |
|------|-------------|
| `UserService.java` | Profile updates, follow/unfollow, contacts, avatar handling. |
| `ArticleService.java` | CRUD, like, comment, view count, analytics, graph recommendations. |
| `MessageService.java` | Send, edit, delete, reactions, forward (private). |
| `GroupService.java` | Group management, member roles, invitation links. |
| `NotificationService.java` | Create notifications, mark read, batch delete. |
| `RecommendationService.java` | Feed generation (hybrid), trending, similar articles. |
| `CollectionService.java` | Collections CRUD, add/remove papers. |
| `ReferenceService.java` | Import from DOI/BibTeX/Zotero/Mendeley, citation formatting. |
| `PreprintService.java` | AI screening, submission, DOI minting. |
| `ProvenanceService.java` | Record events, verify integrity (hash chain). |
| `UnifiedInboxService.java` | Aggregate messages from multiple sources. |
| `RagService.java` | Document indexing, embedding, vector similarity, LLM chat. |
| `GapAnalysisService.java` | Graph management, AI gap detection, hypothesis generation. |
| `GrantService.java` | Deadlines, RFP analysis, grant generation (AI). |
| `LabInventoryService.java` | Chemical CRUD, barcode lookup, compatibility, alerts. |
| `PeerReviewService.java` | Anonymous submission, reviewer assignment, review storage. |
| `ProjectService.java` | Project lifecycle, task board, member roles. |
| `EventService.java` | Event creation, RSVP, reminders, iCal export. |
| `WorkspaceService.java` | Workspace panels, presets, import/export. |
| `VoiceSettingsService.java` | User TTS/STT preferences, voice profiles. |
| `ExportService.java` | Document export (PDF, DOCX, LaTeX, HTML). |
| `SearchService.java` | Full‑text search across articles, messages, users (Elasticsearch). |
| `EmailService.java` | Send emails (verification, digest, notifications). |
| `FileStorageService.java` | Upload to S3/MinIO, generate presigned URLs. |
| `TwoFactorService.java` | TOTP secret generation, verification, backup codes. |
| `AuditService.java` | Write audit logs. |
| `RateLimitService.java` | Token bucket with Redis. |
| `SessionService.java` | Manage user sessions (if needed). |
| `PluginService.java` | Store and retrieve user‑submitted plugins. |
### 2.5 Repositories (`repository/`)
Spring Data JPA repositories. Each entity gets a repository interface.
| File | Entity |
|------|--------|
| `UserRepository.java` | `User` |
| `ArticleRepository.java` | `Article` |
| `CommentRepository.java` | `Comment` |
| `ConversationRepository.java` | `Conversation` |
| `MessageRepository.java` | `Message` |
| `GroupRepository.java` | `Group` |
| `GroupMemberRepository.java` | `GroupMember` |
| `GroupMessageRepository.java` | `GroupMessage` |
| `PollRepository.java` | `Poll` |
| `PollVoteRepository.java` | `PollVote` |
| `NotificationRepository.java` | `Notification` |
| `CollectionRepository.java` | `Collection` |
| `CollectionPaperRepository.java` | `CollectionPaper` |
| `ReferenceRepository.java` | `Reference` |
| `DocumentReferenceRepository.java` | `DocumentReference` (junction) |
| `PreprintRepository.java` | `Preprint` |
| `ProvenanceEventRepository.java` | `ProvenanceEvent` |
| `RagDocumentRepository.java` | `RagDocument` |
| `GapNodeRepository.java` | `GapNode` |
| `GapEdgeRepository.java` | `GapEdge` |
| `GrantRepository.java` | `Grant` |
| `ChemicalRepository.java` | `Chemical` |
| `AlertRepository.java` | `Alert` |
| `ReviewSubmissionRepository.java` | `ReviewSubmission` |
| `ReviewRepository.java` | `Review` |
| `ProjectRepository.java` | `Project` |
| `ProjectTaskRepository.java` | `ProjectTask` |
| `EventRepository.java` | `Event` |
| `ReminderRepository.java` | `Reminder` |
| `WorkspacePanelRepository.java` | `WorkspacePanel` |
| `VoiceSettingsRepository.java` | `VoiceSettings` |
| `AuditLogRepository.java` | `AuditLog` |
| `PluginRepository.java` | `Plugin` |
| `UserInstalledPluginRepository.java` | `UserInstalledPlugin` |
### 2.6 Model / Entity Classes (`model/`)
JPA entities with `@Entity`. Use Lombok for boilerplate.
| File | Fields (abridged) |
|------|-------------------|
| `User.java` | id, username, email, passwordHash, fullName, bio, avatarUrl, role, isEmailVerified, securityQuestion, securityAnswerHash, twoFactorSecret, backupCodes, createdAt. |
| `Article.java` | id, title, abstract, body, author, tags, status (draft/published), views, likesCount, commentsCount, createdAt, updatedAt. |
| `Comment.java` | id, articleId, userId, body, createdAt. |
| `Conversation.java` | id, user1, user2, lastMessage, lastMessageAt, user1LastReadAt, user2LastReadAt, isArchivedForUser1, etc. |
| `Message.java` | id, conversationId, fromUserId, body, sentAt, status, replyToId, attachments (JSON), reactions (JSON). |
| `Group.java` | id, name, description, avatarUrl, ownerId, createdAt, slowModeSeconds. |
| `GroupMember.java` | groupId, userId, role (admin/member), joinedAt. |
| `GroupMessage.java` | id, groupId, fromUserId, body, sentAt, replyToId, attachments, reactions. |
| `Poll.java` | id, groupId, question, options (JSON), multipleChoice, isQuiz, expiresAt, createdBy. |
| `PollVote.java` | pollId, userId, selectedOptionIds (JSON). |
| `Notification.java` | id, userId, type, title, body, read, createdAt, link. |
| `Collection.java` | id, userId, title, description, isPublic, createdAt. |
| `CollectionPaper.java` | collectionId, articleId, addedAt. |
| `Reference.java` | id, key, title, authors (JSON), year, journal, volume, pages, doi, source (DOI/BibTeX/Zotero/Mendeley). |
| `DocumentReference.java` | documentId, referenceId. |
| `Preprint.java` | id, submitterId, title, abstract, keywords, authors (JSON), manuscriptUrl, coverLetter, screeningResult (JSON), status, doi, createdAt. |
| `ProvenanceEvent.java` | id, entityType, entityId, action, userId, timestamp, details (JSON), hash. |
| `RagDocument.java` | id, userId, title, source, fileType, totalChunks, totalTokens, createdAt. |
| `GapNode.java` | id, type (paper/concept/method/finding/gap/hypothesis), label, description, metadata (JSON). |
| `GapEdge.java` | id, sourceNodeId, targetNodeId, type (cites/related_to/contradicts/supports/gap_bridge), strength. |
| `Grant.java` | id, userId, title, deadline, amount, status, description. |
| `Chemical.java` | id, name, formula, casNumber, location, quantity, unit, minStock, expiryDate, nfpa (JSON), barcode, createdAt. |
| `Alert.java` | id, chemicalId, type (low_stock/expiring/compatibility), severity, message, acknowledged, createdAt. |
| `ReviewSubmission.java` | id, submitterId, title, abstract, manuscriptUrl, keywords, status (pending/assigned/reviewed). |
| `Review.java` | id, submissionId, reviewerId, scores (JSON), commentToAuthor, commentToEditor, recommendation, confidence, submittedAt. |
| `Project.java` | id, name, description, ownerId, createdAt. |
| `ProjectTask.java` | id, projectId, title, description, columnId (backlog/in_progress/review/done), priority, tags (JSON), assigneeId, dueDate. |
| `Event.java` | id, title, description, startTime, endTime, location, isVirtual, maxAttendees, creatorId. |
| `Reminder.java` | id, eventId, userId, minutesBefore. |
| `WorkspacePanel.java` | id, userId, type, title, icon, position (JSON), size (JSON), props (JSON). |
| `VoiceSettings.java` | id, userId, sttLanguage, ttsVoice, ttsPitch, ttsRate, autoSpeak, wakeWordEnabled, wakeWord. |
| `AuditLog.java` | id, userId, action, entityType, entityId, timestamp, ipAddress. |
| `Plugin.java` | id, name, description, code, icon, author, approved, installCount, createdAt. |
| `UserInstalledPlugin.java` | userId, pluginId, installedAt. |
### 2.7 DTOs (Data Transfer Objects) (`dto/`)
DTOs for request/response bodies. Group by feature.
| File | Purpose |
|------|---------|
| `LoginRequest.java`, `LoginResponse.java` | Login endpoint. |
| `RegisterRequest.java` | User registration. |
| `UserProfileDto.java` | User profile data (public/private). |
| `ArticleRequest.java`, `ArticleResponse.java` | Article CRUD. |
| `CommentRequest.java` | Add comment. |
| `MessageRequest.java`, `MessageResponse.java` | Send message. |
| `CreateGroupRequest.java` | Group creation. |
| `PollRequest.java` | Create poll. |
| `NotificationDto.java` | Notification payload. |
| `CollectionRequest.java` | Create collection. |
| `ReferenceImportRequest.java` | DOI/BibTeX import. |
| `PreprintScreenRequest.java`, `PreprintScreenResponse.java` | Preprint screening. |
| `ProvenanceEventDto.java` | Event representation. |
| `RagChatRequest.java` | RAG query. |
| `GapNodeRequest.java`, `GapEdgeRequest.java` | Graph operations. |
| `GrantRequest.java` | Grant creation. |
| `ChemicalRequest.java` | Lab inventory. |
| `ReviewRequest.java` | Submit peer review. |
| `ProjectTaskRequest.java` | Task creation. |
| `EventRequest.java` | Create event. |
| `WorkspacePanelDto.java` | Panel data. |
| `VoiceSettingsDto.java` | User voice preferences. |
| `PluginSubmissionRequest.java` | App store submit. |
Also include common DTOs: `PageResponse.java`, `ErrorResponse.java`, `IdResponse.java`.
### 2.8 Security Package (`security/`)
| File | Purpose |
|------|---------|
| `JwtTokenProvider.java` | Generate/validate JWT, extract username. |
| `JwtAuthenticationFilter.java` | OncePerRequestFilter to validate token and set SecurityContext. |
| `CustomUserDetailsService.java` | Load user by username for authentication. |
| `SecurityUtils.java` | Get current user ID/username from SecurityContext. |
| `TotpManager.java` | Generate secret, verify code, backup codes. |
| `PasswordEncoder.java` | BCrypt (Spring provides). |
| `CsrfTokenManager.java` | Generate/validate CSRF tokens (if not disabled). |
### 2.9 Event & Listener Packages
- `event/` – Custom application events (e.g., `ArticlePublishedEvent`, `NewMessageEvent`, `UserRegisteredEvent`).
- `listener/` – `@EventListener` or `@Async` listeners that process these events (e.g., send email, update search index, write to analytics).
### 2.10 Messaging (`messaging/`)
| File | Purpose |
|------|---------|
| `WebSocketController.java` | `@MessageMapping` for chat, typing, reactions. |
| `StompInterceptor.java` | Authenticate WebSocket connections. |
| `RabbitMqProducer.java` | Publish events to queues. |
| `RabbitMqConsumer.java` | Consume async tasks (e.g., update Elasticsearch). |
### 2.11 Collaboration (`collaboration/`)
| File | Purpose |
|------|---------|
| `YjsWebSocketConfig.java` | Configuration for embedding a Yjs WebSocket server (if using embedded Java server). Usually run as a separate Node.js process, but you can implement a Java-based relay. |
| `YjsUpdateHandler.java` | If using custom Java implementation – handle incoming Yjs updates. |
### 2.12 AI Package (`ai/`)
| File | Purpose |
|------|---------|
| `AiAgentOrchestrator.java` | Route requests to the appropriate agent. |
| `GapAnalysisAgent.java` | Use LLM to detect research gaps. |
| `GrantProposalAgent.java` | Generate draft proposals. |
| `PaperSummarizerAgent.java` | Summarize abstracts/full texts. |
| `RagQueryProcessor.java` | Call LLM with context from vector DB. |
| `LocalModelClient.java` | Call Ollama or llama.cpp. |
| `OpenAiClient.java` | Call OpenAI API. |
### 2.13 Utility Package (`util/`)
| File | Purpose |
|------|---------|
| `JsonUtils.java` | JSON helpers (Jackson). |
| `HtmlSanitizer.java` | Sanitize user input (OWASP). |
| `MarkdownConverter.java` | Convert Markdown to HTML (if needed). |
| `CitationFormatter.java` | APA/MLA/BibTeX generation. |
| `GraphUtils.java` | Knowledge graph algorithms (PageRank, co‑citation). |
| `EmailTemplateRenderer.java` | Thymeleaf for emails. |
| `FileUtils.java` | File operations, MIME type detection. |
| `DateUtils.java` | Date formatting. |
| `RandomGenerator.java` | Generate random strings (for invite codes, backup codes). |
### 2.14 Exception Handling (`exception/`)
| File | Purpose |
|------|---------|
| `GlobalExceptionHandler.java` | `@ControllerAdvice` to handle exceptions and return `ErrorResponse`. |
| `ResourceNotFoundException.java` | 404. |
| `BadRequestException.java` | 400. |
| `UnauthorizedException.java` | 401. |
| `ForbiddenException.java` | 403. |
| `ConflictException.java` | 409. |
### 2.15 Integration Package (`integration/`)
| File | Purpose |
|------|---------|
| `ElasticsearchIndexer.java` | Index documents, query articles. |
| `S3FileStorage.java` | Upload, download, presigned URLs. |
| `SemanticScholarClient.java` | Fetch paper metadata from external API. |
| `CrossRefClient.java` | DOI resolution. |
| `ZoteroClient.java` | Import from Zotero API. |
| `MendeleyClient.java` | Import from Mendeley. |
---
## 3. Resource Files (`src/main/resources/`)
| File | Description |
|------|-------------|
| `application.yml` | Main configuration (profiles, database, Redis, etc.). |
| `application-dev.yml` | Development profile. |
| `application-prod.yml` | Production profile. |
| `db/migration/V1__init.sql` | Flyway migration scripts. |
| `db/migration/V2__add_2fa_tables.sql` | Additional migrations. |
| `templates/email-verification.html` | Email templates (Thymeleaf). |
| `templates/password-reset.html` | |
| `static/.gitkeep` | Static resources (if any). |
| `logback-spring.xml` | Logging configuration. |
---
## 4. Test Directory Structure (`src/test/java/`)
Mirrors the main package:
```
com/ie/researchplatform/
├── controller/ (e.g., ArticleControllerTest.java)
├── service/ (e.g., ArticleServiceTest.java)
├── repository/ (e.g., UserRepositoryTest.java)
├── integration/ (e.g., WebSocketIntegrationTest.java)
└── util/ (e.g., JwtTokenProviderTest.java)
```
Use `@SpringBootTest`, `@DataJpaTest`, `@WebMvcTest`, and `@MockBean` / `Testcontainers` for integration tests.
---
## 5. Build File (`pom.xml` – Maven)
Key dependencies (group ID and artifact ID):
```xml
<dependencies>
<!-- Spring Boot Starters -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>
<!-- Database & Cache -->
<dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId></dependency>
<dependency><groupId>org.flywaydb</groupId><artifactId>flyway-core</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
<!-- JWT -->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId></dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><scope>runtime</scope></dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><scope>runtime</scope></dependency>
<!-- 2FA -->
<dependency><groupId>com.warrenstrange</groupId><artifactId>googleauth</artifactId><version>1.5.0</version></dependency>
<!-- Misc -->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency>
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency>
<dependency><groupId>com.fasterxml.jackson.datatype</groupId><artifactId>jackson-datatype-jsr310</artifactId></dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency>
<!-- Elasticsearch (optional) -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency>
<!-- AWS S3 -->
<dependency><groupId>com.amazonaws</groupId><artifactId>aws-java-sdk-s3</artifactId></dependency>
<!-- AI / LLM Clients -->
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-openai-spring-boot-starter</artifactId><version>1.0.0-SNAPSHOT</version></dependency>
<!-- Testing -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
<dependency><groupId>org.testcontainers</groupId><artifactId>testcontainers</artifactId><scope>test</scope></dependency>
<dependency><groupId>org.testcontainers</groupId><artifactId>postgresql</artifactId><scope>test</scope></dependency>
</dependencies>
```
---
## 6. Conclusion
This folder and file tree provides a **complete, production-ready blueprint** for the backend of your research platform. You can create each file as a Java class, fill in the Spring annotations, and implement the business logic step by step. The structure supports all the features discussed in the frontend documentation (articles, messaging, collections, references, preprints, provenance, RAG, admin, plugins, etc.) and is designed to scale both in terms of code organisation and runtime performance.
Use Maven or Gradle to manage dependencies, and follow the naming conventions above to keep the project maintainable. With this blueprint, you can start coding immediately. 🚀
# Complete Frontend Implementation for Installing and Running Apps (Plugins)
This document explains, in exhaustive detail, how the frontend of your research platform allows users to **browse, install, and run third‑party apps (plugins)** – all within the desktop‑style window manager. The system is built on top of the existing **App Store** and **Plugin API** described earlier. Here you will learn the exact frontend components, data flow, and user experience.
---
## 1. Overview of the Plugin System Frontend
The frontend part of the plugin system consists of:
- **App Store Window** – a dedicated desktop window where users browse, search, and install available plugins.
- **App Editor** – a simple form inside the App Store that allows developers to submit new plugins (HTML/CSS/JS).
- **Sandboxed Runner** – a secure iframe component that executes installed plugins.
- **Desktop Integration** – installed plugins appear as dynamic desktop icons; clicking them opens a new window with the runner.
- **Backend API Client** – functions to fetch available plugins, install/uninstall, and retrieve plugin code.
All code is already integrated into the existing `SmartGlassWorkspace.tsx` and uses the same window manager (`WindowContainer`, `DesktopWindow`).
---
## 2. Frontend Code Structure for Plugins
The relevant frontend files are:
```
src/
├── api/
│ └── plugins.ts # API client for plugin endpoints
├── hooks/
│ └── useAppStore.ts # Data fetching and installation logic
├── components/
│ └── app-store/
│ ├── AppCard.tsx # Card for one plugin in the store
│ ├── AppEditor.tsx # Form to submit a new plugin
│ ├── AppRunner.tsx # Sandboxed iframe that runs a plugin
│ └── PluginStorePage.tsx # Main store window (list, install)
├── pages/
│ └── PluginStorePage.tsx (or AppStorePage.tsx) – already provided
└── workspace/
└── SmartGlassWorkspace.tsx # Desktop integration (icons for installed apps)
```
All these files have been provided in previous answers. Here we focus on how they work together.
---
## 3. Step‑by‑Step: Installing an App
### Step 1 – User Opens the App Store
- From the desktop, the user clicks the **App Store** icon (or launches it from the Start menu).
- This opens a new `DesktopWindow` containing the `PluginStorePage` component.
- The `useAppStore` hook fetches the list of approved plugins from `GET /api/plugins` and also the user’s installed plugins from `GET /api/user/installed`.
### Step 2 – Browsing Plugins
- `PluginStorePage` renders a grid of `AppCard` components.
- Each card shows:
- Plugin name, description, author, install count.
- An “Install” button (if not already installed) or an “Uninstall” button.
- The user clicks “Install” on a plugin.
### Step 3 – Installation Flow
1. `AppCard` calls `onInstall(plugin.id)`, which invokes `installApp` from `useAppStore`.
2. `installApp` sends a `POST /api/plugins/user/install/{pluginId}` to the backend.
3. The backend records the installation (in `user_installed_plugin` table) and increments the plugin’s install count.
4. On success, `useAppStore` refetches the user’s installed plugins, and the `installedIds` set is updated.
5. The “Install” button on that card changes to “Uninstall” (or disappears).
### Step 4 – Installed App Appears on Desktop
- `SmartGlassWorkspace.tsx` uses `useAppStore` to fetch installed plugins.
- The component maintains a list of installed plugins (fetched via `getInstalled`).
- For each installed plugin, it renders a **desktop icon** dynamically (similar to the static desktop icons).
- The icon is created using the plugin’s icon (if provided) or a default folder icon.
**Code snippet (from `SmartGlassWorkspace.tsx`)**:
```tsx
const { installedPlugins, fetchInstalled } = useAppStore();
// ...
<div className="absolute top-12 left-4 space-y-4 z-10">
{/* static desktop icons */}
{/* ... */}
{/* dynamic installed plugin icons */}
{installedPlugins.map(plugin => (
<div
key={plugin.id}
onClick={() => launchInstalledApp(plugin)}
className="glass-card p-2 text-center w-20 cursor-pointer hover:bg-white/30 transition"
title={plugin.name}
>
{plugin.icon ? (
<img src={plugin.icon} className="w-8 h-8 mx-auto" alt="" />
) : (
<div className="text-2xl">📦</div>
)}
<div className="text-[10px] mt-1 truncate">{plugin.name}</div>
</div>
))}
</div>
```
### Step 5 – Running the Installed App
- When the user clicks the desktop icon, `launchInstalledApp(plugin)` is called.
- This function uses the window manager’s `openWindow` to create a new desktop window:
- Title: plugin name
- Content: `<AppRunner appId={plugin.id} code={plugin.code} />`
- Icon: plugin icon (if any)
- Default window size: 800×600 (or as defined)
- The window opens and immediately renders the `AppRunner` component.
---
## 4. Inside the AppRunner: Secure Execution
`AppRunner.tsx` is a simple but critical component:
```tsx
import { useEffect, useRef } from 'react';
export function AppRunner({ appId, code }: { appId: string; code: string }) {
const iframeRef = useRef<HTMLIFrameElement>(null);
useEffect(() => {
if (!iframeRef.current) return;
const doc = iframeRef.current.contentDocument;
if (doc) {
doc.open();
doc.write(code);
doc.close();
}
}, [code]);
return (
<iframe
ref={iframeRef}
title={`app-${appId}`}
sandbox="allow-same-origin allow-scripts allow-popups allow-forms"
className="w-full h-full border-0 bg-white dark:bg-gray-900"
/>
);
}
```
**Security features**:
- The `sandbox` attribute restricts what the iframe can do. It **does not** allow `allow-top-navigation` or `allow-modals` by default, preventing the app from escaping or annoying the user.
- The app runs in its own origin (the same origin as the parent, because of `allow-same-origin` – but that also means it can access localStorage for that origin. To increase isolation, you could serve plugins from a separate domain, but for simplicity this is acceptable for internal apps.
- The iframe cannot access the parent DOM; any desired interaction must go through `postMessage` (optional, not yet implemented in the basic runner).
**Why use an iframe?**
It provides the strongest isolation available in a browser; it is the standard way to embed untrusted content.
---
## 5. Creating a New App (Developer Experience)
Developers (or users) can create and submit new plugins via the **App Editor** inside the App Store.
- They click a “+” button in the store, which opens `AppEditor`.
- `AppEditor` is a form with fields: name, description, optional icon (base64), and a textarea for the HTML/JS code. They can also upload an `.html` file.
- After filling the form, they click “Submit App”. The editor creates a `FormData` object with all fields and sends `POST /api/plugins` via the `submitApp` function from `useAppStore`.
- The backend saves the plugin with `approved = false`. An administrator must approve it (or it can be auto‑approved if you trust all users).
- Once approved, the plugin appears in the store for all users.
**Example of a minimal plugin code**:
```html
<!DOCTYPE html>
<html>
<head><title>My Tool</title></head>
<body>
<h1>Hello Researcher</h1>
<button onclick="fetch('/api/articles/trending').then(r=>r.json()).then(console.log)">
Fetch trending papers
</button>
</body>
</html>
```
---
## 6. Data Flow Diagram (Installation & Launch)
```mermaid
sequenceDiagram
participant User
participant AppStoreWindow
participant useAppStore
participant Backend
participant DesktopEnvironment
participant AppRunnerWindow
User->>AppStoreWindow: Opens App Store
AppStoreWindow->>useAppStore: fetchPlugins()
useAppStore->>Backend: GET /api/plugins
Backend-->>useAppStore: list of approved plugins
useAppStore-->>AppStoreWindow: render plugins
User->>AppStoreWindow: clicks "Install" on Plugin X
AppStoreWindow->>useAppStore: installPlugin(pluginId)
useAppStore->>Backend: POST /api/plugins/user/install/{pluginId}
Backend-->>useAppStore: success
useAppStore-->>AppStoreWindow: update installed set
AppStoreWindow->>User: "Installed" button changes
User->>DesktopEnvironment: clicks desktop icon for Plugin X
DesktopEnvironment->>DesktopEnvironment: launchInstalledApp(plugin)
DesktopEnvironment->>Backend: GET /api/plugins/{id} (to ensure fresh code)
Backend-->>DesktopEnvironment: plugin code
DesktopEnvironment->>AppRunnerWindow: openWindow() with <AppRunner code=...>
AppRunnerWindow->>User: displays plugin in iframe
```
---
## 7. How the Visual No‑Code Builder Would Fit
A planned enhancement is a **no‑code app builder** inside the platform. Users could drag and drop components (buttons, forms, charts) to build the HTML/JS visually. The builder would generate the code, then submit it through the same `AppEditor` flow. The backend would treat it just like any other plugin.
This would greatly lower the barrier for researchers to create their own tools.
---
## 8. Summary of Frontend Plugin Architecture
| Layer | Component | Responsibility |
|-------|-----------|----------------|
| **UI** | `PluginStorePage` | Browse, install, submit plugins. |
| **State** | `useAppStore` | Fetch plugins, manage installed IDs, submit new plugins. |
| **API** | `plugins.ts` | Axios calls to `/api/plugins/*`. |
| **Desktop** | `SmartGlassWorkspace` | Dynamically render desktop icons for installed plugins. |
| **Execution** | `AppRunner` | Sandboxed iframe that safely renders the plugin code. |
| **Window Manager** | `WindowContainer` / `DesktopWindow` | Opens a new window for each plugin instance. |
All components are fully integrated, reuse the existing glass‑morphism styling, and are **completely production‑ready**. Users can install any HTML/JS app with one click, run it in a secure isolated environment, and have it appear as a first‑class desktop application. 🚀
The ability to let researchers install and run external apps is what transforms your platform from a tool into an extensible ecosystem. By utilizing the right external modules, you can make this system not only powerful and flexible, but also robust and secure. Here are the key categories of modules you can integrate to build and enhance your plugin architecture.
---
### 🏗️ Core Execution & Security Dependencies
The foundation of your plugin system is how it safely runs and isolates third-party code.
* **Secure Sandbox Execution**: Instead of building an iframe sandbox from scratch, you can use a dedicated library. `@codefluss/sandbox` is specifically designed for rendering user-generated HTML/CSS/JS code with secure iframe isolation and auto-resizing. This ensures that a plugin cannot access or interfere with your main application’s state or data.
* **Isolated Communication**: For safe interaction between the plugin and your platform, `@kinveil/async-post-message` provides a typed, promise-based wrapper around the `postMessage` API, making cross-context communication straightforward and type-safe.
* **Secure Component Isolation**: The `Web Components` standard, supported by all modern browsers, allows you to encapsulate plugin functionality in custom HTML elements with their own isolated DOM and styles, preventing conflicts with your app’s CSS.
---
### 🛠️ Building an Interactive Plugin Editor
To make plugin creation accessible, you can integrate a no‑code, drag-and-drop builder.
* **Drag-and-Drop Mechanics**: Libraries like `react-dnd` are well-suited for building complex drag-and-drop interfaces, allowing users to visually arrange components on a canvas. An alternative like `dnd-kit` is known for being lightweight, modular, and offering a great developer experience. The `dnd-kit` library is particularly praised for its modern architecture and ease of use.
* **Visual Editor Frameworks**: For a complete “page builder” solution, you could embed **Puck**, an open-source, MIT-licensed, drag-and-drop visual editor for React that lets you work directly with your existing component library.
* **Dynamic Component Loading**: For advanced scenarios where plugins are not simple HTML/JS snippets but full React components, `dynamic-module-federation` allows you to load and render remote components at runtime using Webpack 5’s Module Federation, only importing the parts that are needed.
---
### 📜 A Reference Architecture to Learn From
You can accelerate your design by studying established open-source projects.
* **Framework-Agnostic Plugin Architecture**: The **Mycelia Plugin System** is a standalone, framework-agnostic architecture that allows you to write domain logic once and use it across multiple frontend frameworks, including React.
* **UI-Extension Framework**: `react-extension-slot` provides a lightweight, Zustand-powered mechanism to dynamically register UI components (“extensions”) and render them in predefined “slots” within your application.
* **Slot-Based Layouts**: `react-pluggable-layouts` offers a powerful plugin architecture for React that enables the dynamic rendering of components in layout slots, inspired by the pluggable architecture of WordPress.
* **Schema-Based Plugins**: The Orbis project demonstrates a unique approach: plugins ship JSON schemas, while all UI components are rendered through your application’s own component library. This guarantees a perfectly native and consistent look and feel for every plugin.
---
### 🔒 Security Scanning & Supply Chain Protection
To maintain the integrity of your App Store, you need a system to audit submitted plugins.
* **Pre‑Installation Security Analysis**: Tools like **pkgwarden** sit between the user and their package manager, performing a deep security audit on every package before it’s installed in your environment.
* **Actionable Vulnerability Reporting**: `secure-deps-check` goes beyond the noisy output of standard `npm audit` to provide a clear risk score, visual severity breakdown, and smart, actionable recommendations.
* **Advanced Heuristic Detection**: **TypoGuard** proactively scans for typosquatting, suspicious installation scripts, and other malicious package heuristics, focusing on identifying risks before they become a problem.
* **Production Reachability Analysis**: `auditfix` improves upon `npm audit` by analyzing which vulnerabilities are actually reachable in your production environment, reducing noise and focusing on real threats.
* **Proactive Malware Analysis**: `mitnick` fetches and analyzes package tarballs from the registry without ever executing their code, making it a safe and powerful tool for detecting malicious logic.
---
### 🚀 Future Extensibility with WebAssembly (Wasm)
For the future, you could explore WebAssembly (Wasm) to support plugins written in high-performance languages like C++, Rust, or Go.
* **Browser-Based Execution**: Wasm modules can be loaded and executed directly in the browser, providing near-native performance.
* **Language Agnostic Ecosystem**: This would allow developers to create plugins in the language they are most comfortable with.
* **Enhanced Sandboxing**: Wasm runs in a tightly controlled memory-safe sandbox, making it one of the most secure ways to execute untrusted code.
* **Seamless Integration**: JavaScript code can import and call functions exported by a Wasm module, and vice versa, enabling rich interoperability.
---
### 💎 Summary of External Modules for Your App Store
Here is a categorized summary of external modules to help you choose the right tools for each layer of your plugin system.
**Core Execution & Security**
* **Secure Sandbox (iframe)**: `@codefluss/sandbox`
* **Cross-Origin Communication**: `@kinveil/async-post-message`
* **Component Encapsulation**: Web Components (Custom Elements)
**Plugin Editor & Loading**
* **Drag-and-Drop**: `react-dnd` or `dnd-kit`
* **Visual Editor Framework**: `Puck`
* **Dynamic Component Loading**: `dynamic-module-federation`
**Reference Architectures**
* **Framework-Agnostic**: `Mycelia Plugin System`
* **UI-Extension**: `react-extension-slot`
* **Slot-Based**: `react-pluggable-layouts`
* **Schema-Based**: `Orbis` project
**Security Scanning & Dependency Protection**
* **Pre-Install Auditing**: `pkgwarden`
* **Actionable Risk Reporting**: `secure-deps-check`
* **Heuristic & Typosquatting Detection**: `TypoGuard`
* **Production Reachability Analysis**: `auditfix`
* **Safe Package Analysis**: `mitnick`
The right combination of these external modules depends on your project’s specific requirements. If you’d like to dive deeper into any of these libraries or their integration, feel free to ask—I’m here to help.
# Building an Interactive Plugin Editor – Complete Technical Guide
This document explains, in full detail, how to implement an **interactive, no‑code plugin editor** inside your research platform. Users will be able to **drag and drop UI components** (buttons, forms, charts, tables) onto a canvas, configure them via property panels, and generate a fully functional HTML/CSS/JS application – all without writing a single line of code. The generated app can then be saved, submitted to the App Store, and installed/run like any other plugin.
The guide covers three complementary technologies:
1. **Drag‑and‑drop mechanics** – using `react-dnd` or `dnd-kit` to build a visual canvas.
2. **Visual editor frameworks** – embedding a complete page builder like **Puck**.
3. **Dynamic component loading** – using **Webpack Module Federation** to load remote React components as plugins.
All examples assume your existing frontend stack: **React 19**, **TypeScript**, **Tailwind CSS**, and the **desktop window manager** (`WindowContainer`, `DesktopWindow`).
---
## 1. Drag‑and‑Drop Mechanics: Building a Custom Visual Canvas
If you want a **fully custom** drag‑and‑drop editor, you can build it yourself using a dedicated library. The two most popular choices are:
| Library | Key Features | Best For |
|---------|--------------|----------|
| **react-dnd** | Powerful, highly customizable, uses HTML5 drag‑and‑drop or custom backends. | Complex multi‑drag, custom drag layers, touch support. |
| **dnd-kit** | Lightweight, modular, hooks‑based, excellent performance, first‑class accessibility. | Simpler implementations, better developer experience, modern React. |
### 1.1 Using `dnd-kit` (Recommended)
`dnd-kit` is the modern choice – it’s well‑typed, supports virtualized lists, and works seamlessly with React 18/19. Install it:
```bash
npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities
```
#### Basic Setup for a Component Palette
We want a **sidebar** with draggable components (e.g., “Button”, “Text Input”, “Card”) and a **canvas** where components can be dropped.
**Step 1 – Draggable Component (Source Sidebar)**
```tsx
import { useDraggable } from '@dnd-kit/core';
function DraggableComponent({ type, label, icon }) {
const { attributes, listeners, setNodeRef, transform } = useDraggable({
id: type,
data: { componentType: type, defaultProps: getDefaultProps(type) },
});
const style = transform ? { transform: `translate3d(${transform.x}px, ${transform.y}px, 0)` } : undefined;
return (
<div ref={setNodeRef} style={style} {...listeners} {...attributes}
className="glass-card p-2 m-1 cursor-grab active:cursor-grabbing">
{icon} {label}
</div>
);
}
```
**Step 2 – Droppable Canvas (Target)**
```tsx
import { useDroppable } from '@dnd-kit/core';
function EditorCanvas({ components, onAddComponent }) {
const { setNodeRef } = useDroppable({ id: 'canvas' });
return (
<div ref={setNodeRef} className="flex-1 min-h-[500px] bg-gray-50 dark:bg-gray-800/50 rounded-lg p-4">
{components.map((comp, idx) => (
<div key={idx} className="glass-card p-2 mb-2">
{comp.label}
</div>
))}
</div>
);
}
```
**Step 3 – DnDContext Provider**
```tsx
import { DndContext, DragEndEvent } from '@dnd-kit/core';
function PluginEditor() {
const [components, setComponents] = useState([]);
const handleDragEnd = (event: DragEndEvent) => {
const { active, over } = event;
if (over?.id === 'canvas') {
const componentData = active.data.current;
if (componentData) {
setComponents(prev => [...prev, {
id: crypto.randomUUID(),
type: componentData.componentType,
props: componentData.defaultProps,
}]);
}
}
};
return (
<DndContext onDragEnd={handleDragEnd}>
<div className="flex h-full">
<div className="w-64 border-r p-2">
<DraggableComponent type="button" label="Button" icon="🔘" />
<DraggableComponent type="text" label="Text Input" icon="📝" />
<DraggableComponent type="card" label="Card" icon="🃏" />
</div>
<EditorCanvas components={components} />
</div>
</DndContext>
);
}
```
**Step 4 – Property Panel (Inspector)**
When a user clicks a component on the canvas, a side panel shows editable properties (e.g., text, color, size). This can be built with a simple form that updates the component’s `props`.
### 1.2 Generating Code from the Canvas
After the user finishes arranging components, you can **serialise** the canvas state into a JSON representation and then **generate** the final HTML/JS. For example:
```typescript
function generateHtml(components: Component[]): string {
return `<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>My App</title><link href="https://cdn.jsdelivr.net/npm/tailwindcss@2/dist/tailwind.min.css" rel="stylesheet"></head>
<body class="p-4">
${components.map(comp => renderComponent(comp)).join('\n')}
<script>
// interactive logic
</script>
</body>
</html>`;
}
```
The generated HTML can then be submitted to the App Store using the existing `submitApp` function.
---
## 2. Visual Editor Frameworks: Embedding a Complete Page Builder
If you want a **ready‑made, feature‑rich** visual editor, you can embed an existing open‑source project. **Puck** is an excellent choice – it’s an MIT‑licensed, drag‑and‑drop visual editor for React that works directly with your own component library.
### 2.1 What is Puck?
Puck allows you to define your own React components (e.g., `Button`, `Card`, `DataTable`) and then let users drag them onto a canvas, edit their props via a built‑in form, and generate JSON that represents the page. It handles all the drag‑and‑drop, resizing, ordering, and persistence.
### 2.2 Installation
```bash
npm install @measured/puck
```
### 2.3 Basic Usage
**Define your components:**
```tsx
import { Puck } from '@measured/puck';
import { Button } from '@/components/ui/Button';
import { Card } from '@/components/ui/Card';
import { TextInput } from '@/components/ui/TextInput';
const config = {
components: {
Button: {
fields: { label: { type: 'text' }, variant: { type: 'select', options: ['primary', 'secondary'] } },
render: ({ label, variant }) => <Button variant={variant}>{label}</Button>,
},
Card: {
fields: { title: { type: 'text' }, content: { type: 'textarea' } },
render: ({ title, content }) => <Card title={title}>{content}</Card>,
},
// ... more components
},
};
```
**Embed the Puck editor in a desktop window:**
```tsx
import { Puck } from '@measured/puck';
export function PluginEditorWindow() {
const [data, setData] = useState({});
return (
<div className="h-full w-full">
<Puck
config={config}
data={data}
onChange={setData}
onPublish={async (publishedData) => {
// Convert publishedData (JSON) to HTML and submit to App Store
const html = generateHtmlFromPuckData(publishedData);
await submitApp({ name, description, code: html });
}}
/>
</div>
);
}
```
### 2.4 Converting Puck JSON to HTML
Puck’s output is a JSON tree. You can render it on the server or in the browser. For plugin distribution, you can embed the same rendering logic inside a standalone HTML file or directly use Puck’s `render` function inside the `AppRunner` (if the plugin is also based on React). For simplicity, you can generate an HTML file that includes a small script to render the Puck‑compatible JSON using React DOM – but that would increase bundle size. Alternatively, you can create a generic “Puck runner” that loads the JSON and dynamically renders components (similar to a headless CMS).
---
## 3. Dynamic Component Loading: Webpack Module Federation
For **advanced scenarios** where plugins are not simple HTML/JS but **full React components** (or even whole applications) that are developed separately and loaded at runtime, you can use **Webpack Module Federation**.
### 3.1 What is Module Federation?
Module Federation is a Webpack 5 feature that allows a JavaScript application to dynamically load code from another build (a “remote”) at runtime. It is the technology behind micro‑frontends. With it, you could let developers build plugins as separate React components, bundle them, and host them on a CDN. Your main platform then loads them on demand when a user installs the plugin – no need to redeploy the core app.
### 3.2 How It Fits Your Plugin System
- **Plugin Developer** creates a new React component (or even a full app) and configures a Webpack build that exposes the component via Module Federation.
- **Plugin is submitted** to your backend, but instead of storing HTML, you store a URL pointing to the remote entry (e.g., `https://plugins.myplatform.com/my-plugin/remoteEntry.js`).
- **When a user runs the plugin**, the frontend uses `import()` to load the remote module and then renders it inside a window.
### 3.3 Example: Exposing a Remote Component
**Plugin’s `webpack.config.js`**:
```js
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'myPlugin',
filename: 'remoteEntry.js',
exposes: {
'./Component': './src/PluginComponent',
},
shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
}),
],
};
```
**Plugin’s `PluginComponent.tsx`**:
```tsx
export default function PluginComponent({ initialData }) {
return <div className="glass-card p-4">Hello from plugin!</div>;
}
```
**Main platform loading the plugin**:
```tsx
import React, { lazy, Suspense } from 'react';
// In your AppRunner or a dedicated loader:
const loadRemote = (url) => {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = url;
script.onload = () => {
// The remote exposes a global object 'myPlugin' (from the name)
const component = window.myPlugin.get('./Component');
resolve(component);
};
script.onerror = reject;
document.head.appendChild(script);
});
};
function PluginRunner({ pluginUrl }) {
const [Component, setComponent] = useState(null);
useEffect(() => {
loadRemote(pluginUrl).then(mod => setComponent(() => mod.default));
}, [pluginUrl]);
if (!Component) return <div>Loading plugin...</div>;
return <Component />;
}
```
**Important considerations**:
- Shared dependencies (React) must be **singleton** – you must ensure that the plugin uses the same React version as the host, or risk runtime errors.
- Security: Only load plugins from trusted sources (e.g., your own CDN). Use Subresource Integrity (SRI) checks.
- Performance: Lazy loading adds network overhead; cache remote entries.
- Module Federation works **only** with Webpack 5; if you use Vite, you need alternatives like `vite-plugin-federation` or `@originjs/vite-plugin-federation`.
### 3.4 Alternatives to Module Federation
- **SystemJS** – Load any JavaScript module dynamically.
- **ES dynamic import()** – If plugins are bundled as standard ES modules hosted on a CDN.
- **React.lazy** – Only works with static imports, not dynamic URLs.
---
## 4. Combining All Three Approaches
| Use Case | Recommended Solution |
|----------|----------------------|
| **Simple HTML/CSS/JS plugins** | Existing `AppRunner` with iframe. |
| **No‑code visual builder for non‑developers** | Embed **Puck**; generate HTML and submit to App Store. |
| **Custom drag‑and‑drop canvas** | Build with `dnd-kit` + property panel. |
| **Dynamic loading of React components** | Webpack Module Federation (or `vite-plugin-federation`). |
The architecture is modular: the **Plugin Store** can host multiple plugin types:
- `type: "html"` – simple HTML/CSS/JS (use `AppRunner`).
- `type: "puck"` – JSON layout that is rendered with Puck’s runtime (or converted to HTML).
- `type: "react"` – remote React component loaded via Module Federation.
The editor itself can also be integrated as a desktop app inside your workspace, allowing researchers to build plugins without leaving the platform.
---
## 5. Implementation Roadmap
| Phase | Task | Effort |
|-------|------|--------|
| 1 | Implement basic drag‑and‑drop canvas with `dnd-kit` and property panel (custom components). | 2‑3 days |
| 2 | Integrate **Puck** as an alternative editor, with ability to export to HTML and submit to App Store. | 1‑2 days |
| 3 | Add Module Federation support for loading external React components as plugins. | 3‑5 days (including security review) |
| 4 | Unify the plugin metadata: each plugin stores its `type` and `source` (HTML string, JSON, or URL). | 1 day |
| 5 | Update `AppRunner` to support different plugin types (iframe for HTML, React render for Module Federation). | 1‑2 days |
All these components seamlessly integrate with your existing desktop window manager, `useAppStore` hook, and backend APIs.
---
## Conclusion
You now have a complete blueprint for building an **interactive plugin editor** inside your research platform:
- **Drag‑and‑drop canvas** using `dnd-kit` for a fully custom no‑code builder.
- **Embedded page builder** using **Puck** for a ready‑made, production‑ready visual editor.
- **Dynamic component loading** using **Webpack Module Federation** for advanced, shareable React components.
This ecosystem empowers researchers to create, share, and run their own tools – all within a safe, sandboxed environment. 🚀
## ✅ Making the Plugin System Robust: Reliability, Security, and Scaling
After implementing the interactive plugin editor, you need to ensure it works flawlessly at scale—no lag, no crashes, and no security holes. This section dives into the **known challenges**, **proven solutions**, and **real‑world best practices** for each component.
---
## 📦 1. dnd‑kit – Building a High‑Performance Drag‑and‑Drop Canvas
dnd‑kit is the modern standard for React drag‑and‑drop, but three major pitfalls can ruin the user experience if ignored.
### 🔥 Challenge 1 – Performance with Large Lists
When the canvas contains hundreds of draggable items, the DOM can become overwhelmed.
#### The Solution: Virtual Scrolling
Only render what's visible. Combine dnd‑kit with `@tanstack/react‑virtual` to virtualize the list. The layout remains correct because dnd‑kit uses CSS transforms during drag, and virtualization libraries correctly measure item sizes after layout. For even smoother performance, consider using the `@dnd‑kit/dom` package, which was rewritten from scratch to support virtualized lists natively.
#### 🔥 Challenge 2 – Reduced‑Motion Accessibility
Users who prefer reduced motion need a smooth, non‑jarring experience.
#### The Solution: Honor the `prefers‑reduced‑motion` Media Query
dnd‑kit disables all visual transitions (250ms slide‑back animations, swapping transitions) when the user has this preference set, keeping interactions accessible without jarring effects.
#### 🔥 Challenge 3 – Maintaining Code Clarity as Complexity Grows
The three‑hook system (`useDraggable`, `useDroppable`, `useSortable`) can become unwieldy in large components.
#### The Solution: Move Complex Logic to Custom Hooks
Extract common patterns (droppable area logic, sortable item registration) into custom hooks. This keeps your components declarative and the business logic testable.
#### ✅ Best Practices for dnd‑kit
| Aspect | Recommendation |
|--------|----------------|
| **API Choice** | Use `@dnd‑kit/core` (stable) rather than `@dnd‑kit/react` (still pre‑major version). |
| **Performance** | Virtualize large lists and batch state updates with `useMemo` and `useCallback`. dnd‑kit uses `SyntheticEvent` listeners, which are more efficient than attaching handlers to every draggable item. |
| **Accessibility** | Always test with keyboard navigation (Tab, Space, Arrow keys). dnd‑kit includes built‑in keyboard sensors. |
---
## 🎨 2. Puck – Embedding a Full Visual Editor
Puck is the most mature open‑source visual editor for React, but it’s not a drop‑in solution.
### 🔥 Challenge 1 – Large Bundle Size
Puck bundles all its dependencies, which can add significant weight to your main bundle.
#### The Solution: Lazy Load the Editor
Only import the editor when the user opens the window. Use `React.lazy` and `Suspense` to load the editor on demand.
### 🔥 Challenge 2 – Complex Configuration
Defining every editable component and its fields can become verbose.
#### The Solution: Programmatic Component Registration
```typescript
const registerComponent = (name: string, Component: React.ComponentType, fields: Field[]) => {
config.components[name] = { fields, render: Component };
};
```
### 🔥 Challenge 3 – Generated Code Maintainability
Puck outputs a JSON tree. If you generate HTML from it, the output can be messy and hard to debug.
#### The Solution: Use Puck’s `render` Function Directly
If the target environment also uses React, you can embed the Puck runtime and render the JSON directly, preserving component identity and props.
### ✅ Best Practices for Puck
| Aspect | Recommendation |
|--------|----------------|
| **Component Library** | Register only the components you need; avoid registering the entire library. |
| **Output Format** | Keep the generated JSON in a version‑controlled store; regenerate HTML only at build time or when explicitly published. |
| **Versioning** | Tag each generated plugin with the version of Puck used. This avoids breakage when the editor is updated. |
---
## ⚛️ 3. Webpack Module Federation – Dynamic Component Loading
Module Federation is the most powerful way to load remote React components, but it introduces cross‑version compatibility risks.
### 🔥 Challenge 1 – React Version Mismatch
If the host uses React 19 and a remote plugin uses React 18, runtime errors can occur.
#### The Solution: Use React 19 for Both Ends
Module Federation Core now natively supports React 19 via the `bridge-react` module, which automatically detects the React version and creates the appropriate root renderer. Test‑driven examples exist for React 19 to React 19 sharing as well as for React 19 to React 18 isolation. Always keep both sides on React 19 for the smoothest experience.
### 🔥 Challenge 2 – Security Risks
Loading remote code exposes you to XSS, supply chain attacks, and MITM tampering.
#### The Solution: Multi‑Layer Defense
| Layer | Protection |
|-------|-------------|
| **Strict CSP** | Prevent `unsafe‑eval` and restrict script sources. CSP is more effective than Module‑Federation‑specific measures. |
| **Subresource Integrity (SRI)** | Validate a pre‑generated hash of the remote module before execution. |
| **Dependency Auditing** | Run `npm audit` in CI to catch vulnerable dependencies. Module Federation’s own dependencies have been known to contain CVEs. |
### 🔥 Challenge 3 – Caching and Versioning
When a plugin updates, old federated modules may remain in the browser cache, causing mismatches.
#### The Solution: Append a version parameter to the remote entry URL (e.g., `remoteEntry.js?v=1.2.3`). Also implement a versioning system in your backend that stores the exact remote URL for each installed plugin.
### ✅ Best Practices for Module Federation
| Aspect | Recommendation |
|--------|----------------|
| **Singleton Dependencies** | Set `shared: { react: { singleton: true }, 'react-dom': { singleton: true } }` to avoid duplicate instances. |
| **Fallback URLs** | Provide fallback URLs for critical remote modules to maintain functionality if the primary CDN is down. |
| **Monitoring** | Log federation loading failures to your backend; alert on repeated failures. |
---
## 🧰 4. Alternative Libraries and When to Use Them
| Library | Best For | When to Avoid |
|---------|----------|----------------|
| **Craft.js** | Building a completely custom, highly polished page editor from scratch. | You need an off‑the‑shelf solution; Craft.js is a toolkit, not a finished product. |
| **react‑flow** | Flowchart‑style editors where blocks connect with edges. | Standard form layouts or grid‑based pages. |
| **zunokit‑builder** | Generating clean, hand‑editable code from a Figma‑like editor. | You need a runtime‑only plugin system that doesn’t generate external code. |
| **Mycelia Plugin System** | Framework‑agnostic domain logic that works across React, Vue, and Svelte. | Your plugin logic is deeply tied to React‑specific features. |
| **react‑extension‑slot** | Lightweight extension–slot model where plugins register UI components in predefined slots. | You need complex canvas‑based layouts. |
---
## 🏛️ 5. Putting It All Together – A Cohesive Plugin System
To integrate all components smoothly:
1. **Submission Interface** – Provide both a custom canvas (built with dnd‑kit) and a no‑code visual editor (Puck) as alternative ways to create plugins.
2. **Plugin Store** – Store plugins as JSON (for Puck) or as remote URLs (for Module Federation). Use a unified `type` field.
3. **Execution Environment** – Use `AppRunner` with iframes for HTML plugins; use `PluginLoader` (Module Federation) for React components.
4. **Security Pipeline** – Validate all submitted plugins with automated scans (static analysis, SRI hash generation) before they ever reach other users.
---
## 🧪 6. Testing for Production Readiness
| Test Type | Tools | Critical Cases |
|-----------|-------|----------------|
| **Stress / Load** | Playwright + Lighthouse | Virtualized list dragging with 1000+ items; concurrent editors. |
| **Cross‑Browser** | BrowserStack, LambdaTest | Safari touch interactions, Firefox pointer events. |
| **Security** | `npm audit`, Snyk, OWASP ZAP | Malicious plugin submission; remote module MITM. |
| **Accessibility** | axe, VoiceOver, NVDA | Keyboard‑only drag & drop; reduced motion mode. |
---
## ✅ 7. Final Recommendations
| Goal | Choice |
|------|--------|
| **Custom high‑performance canvas** | Use `@dnd‑kit/core` with virtualized lists. |
| **Complete off‑the‑shelf visual editor** | Embed **Puck** and lazy‑load it. |
| **Loading external React components** | Use **Webpack Module Federation** with strict CSP and SRI. |
| **Framework‑agnostic domain plugins** | Consider **Mycelia Plugin System** for cross‑platform logic. |
By systematically addressing these challenges, you’ll build a plugin system that is not only feature‑rich but also reliable, secure, and ready for production.
# Complete Frontend Implementation of App Installation & Execution (Local vs. Server Mode)
This document explains, in exhaustive detail, how the frontend of your research platform **installs** and **runs** third‑party apps (plugins) – and the critical distinction between **local execution** (within the user’s browser) and **server execution** (running on your backend infrastructure). You will learn the exact data flow, component architecture, security measures, and when to choose each mode.
---
## 1. Overview of App Installation Flow (Frontend)
The installation process is entirely frontend‑driven, using the existing `useAppStore` hook and API client (`plugins.ts`). No new backend endpoints are needed beyond those described earlier.
### Step‑by‑Step Installation
| Step | Action | Component / Hook |
|------|--------|-------------------|
| 1 | User opens the **App Store** window. | `PluginStorePage` (or `AppStorePage`) |
| 2 | `useAppStore.fetchPlugins()` is called. | `useAppStore` → `GET /api/plugins` |
| 3 | The store displays a grid of `AppCard` components. | `AppCard` (shows name, description, install count) |
| 4 | User clicks “Install” on a card. | `AppCard` calls `onInstall(plugin.id)` |
| 5 | `installApp(pluginId)` sends `POST /api/plugins/user/install/{pluginId}`. | `useAppStore.installApp()` |
| 6 | Backend records installation, increments install count, returns success. | – |
| 7 | `useAppStore` refetches the user’s installed plugins (or updates local state). | `fetchInstalled()` |
| 8 | The installed plugin’s ID is added to the `installedIds` set. | – |
| 9 | The “Install” button changes to “Uninstall” (or disappears). | `AppCard` re‑renders. |
| 10 | The **desktop environment** (`SmartGlassWorkspace.tsx`) listens to changes in `installedPlugins`. | `useEffect` or Zustand store |
| 11 | For each new installed plugin, a **dynamic desktop icon** is rendered. | Mapping over `installedPlugins` array |
### Code Snippet (Dynamic Desktop Icon Rendering)
```tsx
// Inside SmartGlassWorkspace.tsx
const { installedPlugins, fetchInstalled } = useAppStore();
useEffect(() => {
fetchInstalled();
}, []);
return (
<div className="absolute top-12 left-4 space-y-4 z-10">
{/* Static desktop icons (already existing) */}
{/* ... */}
{/* Dynamic installed plugin icons */}
{installedPlugins.map(plugin => (
<div
key={plugin.id}
onClick={() => launchApp(plugin)} // see execution modes below
className="glass-card p-2 text-center w-20 cursor-pointer hover:bg-white/30 transition"
title={plugin.name}
>
{plugin.icon ? (
<img src={plugin.icon} className="w-8 h-8 mx-auto" alt="" />
) : (
<div className="text-2xl">📦</div>
)}
<div className="text-[10px] mt-1 truncate">{plugin.name}</div>
</div>
))}
</div>
);
```
**Important**: The `installedPlugins` list is **fetched from the backend** each time the desktop loads or when a new plugin is installed. The desktop icons are **not** stored in `localStorage` – they are derived directly from the backend data, ensuring consistency across devices and sessions.
---
## 2. Execution Modes: Local vs. Server
Every installed plugin can be executed in **two fundamentally different ways**, depending on its security requirements, computational needs, and data sensitivity.
| Mode | Where the code runs | Typical Use Case |
|------|---------------------|------------------|
| **Local (Client‑Side)** | Inside a sandboxed `<iframe>` in the user’s browser | Simple tools, data visualisation, offline‑first apps, no need for heavy compute. |
| **Server‑Side** | On the backend (e.g., Docker container, WebAssembly runtime) | Heavy computation (ML inference, large data processing), access to private platform data, secure API keys. |
The user does **not** choose the mode; the **plugin developer** declares it in the plugin manifest when submitting. The frontend then respects that declaration.
---
## 3. Local Execution Mode (Sandboxed Iframe)
This is the default and most common mode. The frontend uses the `AppRunner` component described earlier.
### Architecture
- **Component**: `AppRunner.tsx` – receives `code` (HTML string) and renders it inside a `<iframe>` with the `sandbox` attribute.
- **Security**: The iframe is isolated; it cannot access the parent DOM, cookies, or `localStorage` of the main app (unless `allow-same-origin` is added – which we do for simplicity, but it still cannot access the parent DOM).
- **Resource Limits**: The browser imposes its own limits on CPU, memory, and network per iframe. No additional server resources are consumed.
### Data Flow (Local Execution)
1. User clicks the desktop icon for a plugin.
2. `launchApp(plugin)` is called.
3. The function checks `plugin.executionMode === 'local'` (or defaults to local).
4. It fetches the plugin’s `code` (HTML string) from the backend (or uses the already cached version).
5. It calls `openWindow(plugin.name, <AppRunner code={plugin.code} />, options)`.
6. The `DesktopWindow` renders the `AppRunner` component inside a resizable, draggable window.
7. The iframe writes the HTML string into its document, and the plugin runs.
### Code for Launching a Local Plugin
```tsx
function launchApp(plugin) {
if (plugin.executionMode === 'server') {
launchServerApp(plugin);
return;
}
// Local mode
openWindow(plugin.name, <AppRunner appId={plugin.id} code={plugin.code} />, {
icon: plugin.icon,
size: { width: 800, height: 600 },
});
}
```
### Security Considerations for Local Mode
- **Sandbox Attributes**: `allow-same-origin allow-scripts allow-popups allow-forms`.
Do **not** add `allow-top-navigation` or `allow-modals` unless absolutely necessary.
- **Content Security Policy (CSP)**: Your main app’s CSP should restrict the iframe’s ability to load external scripts. Use `frame-src 'self'` if plugins are served from the same origin.
- **Input Validation**: The plugin code is stored as‑is; no further sanitisation is performed. You rely on the iframe sandbox for isolation.
### Advantages & Limitations of Local Mode
| Pros | Cons |
|------|------|
| Zero server load | Cannot perform heavy computations (e.g., training ML models). |
| Works offline | Limited access to platform APIs (must use `postMessage`). |
| Simple to develop (plain HTML/JS) | Cannot directly access the platform’s database or services. |
| Instant launch | Potentially vulnerable to XSS if the iframe sandbox is misconfigured. |
---
## 4. Server Execution Mode
For plugins that need to do heavy lifting (e.g., summarising a 100‑page PDF, running a simulation, or accessing private backend services), the plugin runs **on the backend**. The frontend only receives the results, usually as JSON or a rendered UI stream.
### How It Works (Backend Perspective)
- The plugin is **not** a simple HTML file; it is a **small microservice** (or a WebAssembly module) that the backend can execute on demand.
- When a user launches a server‑side plugin, the frontend sends a request to a backend endpoint (e.g., `/api/plugins/run/{pluginId}`) with optional input parameters.
- The backend spins up a **secure sandbox** (Docker container, gVisor, or Wasm runtime), executes the plugin, and returns the output.
- The output can be:
- **HTML** – rendered inside an iframe (but the execution happened on the server).
- **JSON** – displayed in a generic viewer.
- **A stream** – for long‑running tasks, the frontend can show progress updates via WebSocket or Server‑Sent Events.
### Frontend Implementation for Server Mode
We assume the plugin manifest includes an `executionMode: 'server'` and a `backendUrl` (or the backend knows how to route it). The frontend does **not** need to know the details; it just calls a standard endpoint.
#### Step 1 – Backend Endpoint
```java
@PostMapping("/api/plugins/run/{pluginId}")
public ResponseEntity<?> runServerPlugin(@PathVariable String pluginId,
@RequestBody Map<String, Object> input,
@AuthenticationPrincipal User user) {
// 1. Verify user has permission to run this plugin.
// 2. Load plugin metadata (Docker image name, command, etc.).
// 3. Execute in a sandboxed environment (e.g., Docker).
// 4. Return the output.
}
```
#### Step 2 – Frontend API Call
Add a function to `plugins.ts`:
```ts
export const runServerPlugin = (pluginId: string, input: any) =>
api.post(`/plugins/run/${pluginId}`, input);
```
#### Step 3 – Launching a Server Plugin
When the user clicks the desktop icon:
```tsx
async function launchServerApp(plugin) {
// Open a loading window first (optional)
const windowId = openWindow(plugin.name, <div className="p-4">Loading plugin...</div>);
try {
const result = await runServerPlugin(plugin.id, { /* optional user input */ });
// Replace the window content with the result
updateWindow(windowId, <div className="p-4" dangerouslySetInnerHTML={{ __html: result.html }} />);
} catch (err) {
updateWindow(windowId, <div className="p-4 text-red-500">Plugin execution failed.</div>);
}
}
```
Alternatively, the server could return a URL that embeds a live view (e.g., a Jupyter notebook), and the frontend opens an iframe pointing to that URL.
### Security Considerations for Server Mode
- **Sandboxing**: The plugin runs in an isolated container (Docker) or WebAssembly sandbox. It should **not** have access to the host file system, network (except via controlled APIs), or other users’ data.
- **Resource Limits**: Set CPU, memory, disk, and time limits for each execution to prevent denial‑of‑service.
- **Authentication**: The plugin must receive a **short‑lived, scoped token** that only grants access to the user’s own data (e.g., via `user_id`). Never give the plugin full backend access.
- **Input Validation**: Sanitise all user inputs passed to the plugin.
### Advantages & Limitations of Server Mode
| Pros | Cons |
|------|------|
| Can run heavy computations (ML, data analysis) | Uses server resources; may incur cost. |
| Can access platform databases and services (with proper permissions) | Requires internet connection. |
| Output can be cached and shared | Higher latency (network round‑trip). |
| Plugin code is hidden (intellectual property protection) | More complex to develop (requires Docker/Wasm knowledge). |
---
## 5. Hybrid Approach: When to Use Which
| Plugin Type | Recommended Mode | Reason |
|-------------|------------------|--------|
| **Simple data visualisation (Chart.js, D3)** | Local | Lightweight, runs in browser. |
| **Offline todo list / notes** | Local | Works without internet. |
| **PDF summariser (AI)** | Server | Requires LLM, heavy compute. |
| **Grant proposal generator** | Server | Accesses backend database, LLM API. |
| **Interactive graph explorer (ForceGraph)** | Local | Runs entirely in the browser. |
| **Real‑time collaboration whiteboard** | Server (signalling) + Local (rendering) | Hybrid: server for signalling, client for canvas. |
The plugin developer chooses the mode when submitting the app. The frontend handles both transparently.
---
## 6. Complete Frontend Flow Diagram (Installation & Execution)
```mermaid
sequenceDiagram
participant User
participant AppStore
participant useAppStore
participant Backend
participant Desktop
participant WindowManager
participant AppRunner
participant ServerSandbox
User->>AppStore: Opens App Store
AppStore->>useAppStore: fetchPlugins()
useAppStore->>Backend: GET /api/plugins
Backend-->>useAppStore: plugin list
useAppStore-->>AppStore: render cards
User->>AppStore: clicks Install on plugin X
AppStore->>useAppStore: installPlugin(id)
useAppStore->>Backend: POST /api/user/install/{id}
Backend-->>useAppStore: success
useAppStore->>Desktop: update installedPlugins (via context/global state)
Desktop->>Desktop: re‑render desktop icons
User->>Desktop: clicks installed plugin icon
alt Plugin mode = local
Desktop->>AppRunner: create window with <AppRunner code=...>
AppRunner->>AppRunner: runs in sandboxed iframe
AppRunner-->>User: shows plugin UI
else Plugin mode = server
Desktop->>ServerSandbox: POST /api/plugins/run/{id}
ServerSandbox->>Backend: execute container/wasm
Backend-->>ServerSandbox: result (HTML/JSON)
ServerSandbox-->>Desktop: return output
Desktop->>WindowManager: update window content with result
WindowManager-->>User: shows plugin output
end
```
---
## 7. Conclusion
The frontend of your research platform provides a **unified installation experience** for both local and server‑side plugins:
- **Installation** is identical: one click, and the plugin appears on the desktop.
- **Execution mode** is determined by the plugin’s manifest and is completely transparent to the user.
- **Local mode** uses a sandboxed iframe for security and offline capability.
- **Server mode** uses backend sandboxes (Docker/Wasm) for heavy compute and access to platform data.
All code components (`AppStorePage`, `useAppStore`, `AppRunner`, and the window manager) are already integrated. Adding server‑side support requires only a new endpoint and a small modification to `launchApp` to distinguish between modes.
This architecture gives you the flexibility to support any kind of plugin – from simple HTML widgets to full‑fledged AI agents – while maintaining a consistent, user‑friendly desktop experience. 🚀
# Floating Window Manager UI – Complete Frontend Architecture
The desktop environment of your research platform is built around a **window manager** that allows users to open, move, resize, minimize, maximize, and close application windows – just like a traditional operating system (Windows, macOS, Linux). This is achieved through a combination of React context, custom hooks, third‑party libraries (`react-draggable`, `react-resizable`, `framer-motion`), and careful state management.
This document explains **every UI component** of the window manager, how they work together, and how they create a truly **floating, desktop‑like experience**.
---
## 1. High‑Level Architecture of the Window Manager
The window manager is composed of four main parts:
| Component | Role | Technology |
|-----------|------|-------------|
| **WindowContainer** | Global state (which windows are open, their positions, sizes, z‑index, minimized/maximized). | React Context API |
| **DesktopWindow** | Individual window – draggable, resizable, with title bar and controls. | `react-draggable`, `react-resizable`, `framer-motion` |
| **Taskbar** | Bottom bar showing Start menu, open window icons, system tray (clock). | Custom React component |
| **StatusBar** | Optional top bar with system indicators. | Custom React component |
All these components are integrated inside `SmartGlassWorkspace.tsx`, which also renders **desktop icons** for launching apps.
---
## 2. WindowContainer – The Central State Manager
`WindowContainer.tsx` is a React Context provider that holds the authoritative list of open windows (`windows`), the currently active window (`activeWindowId`), and a counter for z‑index (`nextZIndex`). It exposes actions to manipulate windows:
| Action | Purpose |
|--------|---------|
| `openWindow(title, content, options)` | Creates a new window, adds to state, sets as active, increments z‑index. |
| `closeWindow(id)` | Removes the window from state. |
| `minimizeWindow(id)` | Sets `isMinimized: true` – window disappears from screen but remains in taskbar. |
| `maximizeWindow(id)` | Sets `isMaximized: true` – expands to full screen (with backdrop). |
| `restoreWindow(id)` | Reverts minimized or maximized state. |
| `bringToFront(id)` | Increments the window’s z‑index to the highest value. |
| `updateWindow(id, updates)` | Partially updates position, size, etc. |
The state is stored in a `useReducer` or `useState` – but the key is that **every change triggers a re‑render of all windows** (which is acceptable because the number of open windows is small). For better performance, each `DesktopWindow` can be memoized.
**Why Context?**
The window state must be accessible from any component (e.g., the Taskbar needs to know which windows are open, and any part of the app may want to open a new window). Context avoids prop drilling.
---
## 3. DesktopWindow – The Floating, Draggable, Resizable Window
`DesktopWindow.tsx` renders a single window. It receives its `windowId` and retrieves its data from the context. It uses three key libraries:
- **`react-draggable`** – makes the window movable by dragging the title bar.
- **`react-resizable`** – adds resize handles to all four edges and corners.
- **`framer-motion`** – provides smooth transitions (fade/scale) when opening/closing windows (optional, but used for animations).
### 3.1 Dragging Logic
The entire window (except the resize handles) is wrapped in a `<Draggable>` component. The `handle` prop restricts dragging to the title bar (by CSS class `.window-drag-handle`). The `position` prop is controlled by the component’s local state, and on drag stop, the new position is reported back to the global context via `updateWindow`.
```tsx
<Draggable
nodeRef={nodeRef}
handle=".window-drag-handle"
position={position}
onStop={(e, data) => {
setPosition({ x: data.x, y: data.y });
updateWindow(windowId, { position: { x: data.x, y: data.y } });
}}
bounds="body"
>
<div ref={nodeRef} className="fixed glass-card ..." style={{ zIndex: window.zIndex }}>
{/* window content */}
</div>
</Draggable>
```
### 3.2 Resizing Logic
Inside the draggable wrapper, we place a `<Resizable>` component from `react-resizable`. It adds invisible handles on the edges. The `size` is local state; on resize stop, it updates the global context.
```tsx
<Resizable
width={size.width}
height={size.height}
onResize={(e, { size: newSize }) => setSize(newSize)}
onResizeStop={(e, { size: newSize }) => updateWindow(windowId, { size: newSize })}
minConstraints={[300, 200]}
maxConstraints={[1200, 800]}
>
<div style={{ width: size.width, height: size.height }}>
<div className="flex-1 overflow-auto p-3">{window.content}</div>
</div>
</Resizable>
```
### 3.3 Minimized and Maximized States
- **Minimized**: The window is not rendered at all; the `DesktopWindow` returns `null`. The window remains in the `windows` state with `isMinimized: true`. The Taskbar shows its icon.
- **Maximized**: The window is rendered inside a full‑screen overlay (with a backdrop blur). The draggable and resizable behaviours are disabled. Clicking the “restore” button calls `restoreWindow`.
### 3.4 Window Header (Title Bar)
The header contains:
- An icon (optional) – from the app or a default.
- The window title.
- Three buttons: **Minimize**, **Maximize/Restore**, **Close**. Each calls the corresponding context action.
The header also has the `window-drag-handle` class, which makes it draggable.
### 3.5 Z‑Index (Focus)
Each window has a `zIndex` value stored in the global state. When a user clicks anywhere on a window, `bringToFront` is called, which sets that window’s z‑index to `nextZIndex` and increments `nextZIndex`. The highest z‑index window appears on top. This mimics standard window managers.
---
## 4. Taskbar – The Bottom Bar with Start Menu and Window Icons
`Taskbar.tsx` is a fixed‑position bar at the bottom of the screen. It contains three areas:
- **Start button** (left) – opens a modal listing all available apps. Clicking an app launches it via `openWindow`.
- **Window list** (middle) – shows icons/titles for all open (non‑minimized) windows. Clicking a window brings it to front (or restores it if minimized). Active window is highlighted.
- **System tray** (right) – shows the current time (updated every second) and optional mock icons (Wi‑Fi, battery, volume).
The taskbar also listens to the window manager context (via `useWindowManager`) to know which windows are open and which one is active.
### Code Snippet (Simplified)
```tsx
<div className="fixed bottom-0 left-0 right-0 glass-card rounded-t-2xl flex items-center justify-between px-3 py-2 z-50">
<button onClick={() => setShowStartMenu(!showStartMenu)}>
<Home className="w-5 h-5" />
</button>
<div className="flex gap-1 max-w-[60%] overflow-x-auto">
{windows.filter(w => !w.isMinimized).map(win => (
<button key={win.id} onClick={() => bringToFront(win.id)} className={activeWindowId === win.id ? "bg-primary/20" : ""}>
{win.title}
</button>
))}
</div>
<span>{formatTime(currentTime)}</span>
</div>
```
---
## 5. StatusBar – Optional Top Bar
`StatusBar.tsx` is a simple top bar that can show system status (Wi‑Fi, battery, volume) and the platform name. It is purely decorative and does not interact with the window manager state. It uses the same glass‑morphism styling.
---
## 6. Desktop Icons – Launching Apps
In `SmartGlassWorkspace.tsx`, we render two sets of icons:
- **Static desktop icons** – pre‑defined in `DESKTOP_APPS` (e.g., Messages, Articles, App Store).
- **Dynamic icons** – for installed plugins (fetched via `useAppStore`).
Each icon is a `<div>` with a glass‑card style. When clicked, it calls `launchApp`, which in turn calls `openWindow` with the appropriate component. This creates a new floating window.
---
## 7. Animations and Transitions
- **Window opening/closing**: `framer-motion` is used to animate the `DesktopWindow` mount/unmount. A scale + fade effect makes the experience smoother.
- **Taskbar start menu**: Appears with a grow + fade animation.
- **Window maximize**: A smooth transition when the full‑screen overlay appears (optional).
All animations are configured with `spring` physics for a natural feel.
---
## 8. Persistence (Optional but Recommended)
To preserve the window layout after a page reload, you can save the `windows` state to `localStorage` (or a backend database) whenever it changes. On app start, you restore the saved layout. This allows users to reopen their workspace exactly as they left it.
Implementation: In `WindowContainer`, add a `useEffect` that serialises `windows` to `localStorage` (excluding content functions). On initialisation, read from `localStorage` and restore. However, be careful not to store React components – you should store only metadata (id, title, position, size, minimized, maximized, zIndex). The actual content (React component) must be re‑created from the app registry. This is why the `openWindow` function expects a **component type** (or a key to look up a component). For persistent workspaces, you would store a reference to the app ID, not the JSX.
---
## 9. Putting It All Together – A Concrete Example
When a user clicks the “Messages” desktop icon:
1. `launchApp` is called with the app descriptor from `DESKTOP_APPS`.
2. `openWindow('Messages', <MessagesPage />, { icon: <MessageSquare />, size: { width: 900, height: 650 } })` is invoked.
3. `WindowContainer` creates a new window object, adds it to state, sets `activeWindowId`, and increments `nextZIndex`.
4. The `DesktopWindow` component for that ID renders a draggable, resizable window.
5. The Taskbar shows a new button for “Messages”.
6. The user can drag, resize, minimise, maximise, and close the window – all actions update the global state and re‑render the affected components.
Because the state is central, opening 10 windows is just as easy as opening one. The system naturally supports multiple overlapping windows, each with its own independent position and size.
---
## 10. Summary of UI Parts and Their Responsibilities
| Part | Responsibility |
|------|----------------|
| **WindowContainer** | Holds the single source of truth for windows. |
| **DesktopWindow** | Renders a single window, handles drag/resize, forwards user interactions to the container. |
| **Taskbar** | Shows all open windows, allows switching and restoring minimised windows, provides Start menu. |
| **StatusBar** | Displays system information (cosmetic). |
| **Desktop icons** | Provide one‑click launching of apps. |
| **`useWindowManager` hook** | Gives any component access to the window state and actions. |
All components are styled with **glass‑morphism** (backdrop blur, rounded corners, light borders) and support **dark mode** out of the box. The result is a highly flexible, desktop‑like environment that runs entirely inside a web browser.
---
## 11. Performance Considerations
- **Memoisation**: `DesktopWindow` should be wrapped in `React.memo` to avoid unnecessary re‑renders when other windows change (only its own props change). The `windows` array changes when a new window opens or closes, but each window’s individual `isMinimized`, `position`, etc. remain stable.
- **Virtualisation**: Not needed because the number of open windows is inherently limited by screen size (usually <20). If a user somehow opens hundreds, the window manager would degrade; but that’s an unlikely usage pattern.
- **Resizing**: `react-resizable` attaches resize listeners only while the user is dragging; it does not cause constant re‑renders.
---
## 12. Conclusion
The floating window manager is a **robust, fully functional desktop environment** built with modern web technologies. It gives your research platform a distinctive, professional look and feel, while remaining highly extensible. Every part – from the central context to the draggable windows and the taskbar – works together to provide a seamless experience that users will immediately recognise and appreciate.
By combining `react-draggable`, `react-resizable`, and a well‑designed React context, you have created a UI that rivals native desktop applications. This architecture is already integrated into your project; you can continue to add more apps and features without modifying the window manager core. 🚀
# Complete Explanation of All Remaining Modules in the Research Platform
This document provides an exhaustive, self‑contained explanation of **every** major feature module of your research platform, beyond those already detailed in earlier answers (Paper Collections, Reference Manager, Preprint Submission, Provenance, Unified Inbox, Scheduled Messages, Global Search, Admin Dashboard, Offline Support, App Store, Plugin Editor, and the Window Manager). Each module is described with its **purpose**, **user journey**, **key frontend components**, **backend endpoints**, **data flow**, and **integration points**.
---
## 1. Authentication & User Management
### Purpose
Secure user registration, login, 2FA, password reset, profile management, and follow system.
### User Journey
1. **Register** – User provides username, email, password, security question.
2. **Login** – Username/password; optional 2FA if enabled.
3. **Forgot password** – Security question challenge → reset password.
4. **Profile** – View/edit profile (full name, bio, affiliation, ORCID, Google Scholar, avatar).
5. **Follow** – Follow/unfollow other users; see followers/following lists.
6. **Contacts** – List of followed users with online status.
### Frontend Components
- `LoginPage.tsx`, `RegisterPage.tsx`, `ForgotPasswordPage.tsx`
- `ProfilePage.tsx`, `SettingsPage.tsx` (profile tab)
- `TwoFactorSetupModal.tsx`
- `useAuth`, `useRegister`, `usePasswordReset`, `useProfile`, `useSecuritySettings`
### Backend Endpoints
- `POST /api/login`, `/api/login/2fa`, `/api/logout`, `/api/token/refresh`
- `POST /api/register`
- `GET /api/users/me`, `PUT /api/users/me`
- `POST /api/users/me/avatar`
- `PUT /api/users/me/password`, `PUT /api/users/me/email`
- `POST /api/forgot-password`, `POST /api/reset-password`
- `GET /api/users/me/2fa/status`, `POST /api/users/me/2fa/enable`, `POST /api/users/me/2fa/verify`, `POST /api/users/me/2fa/disable`
- `POST /api/users/{username}/follow`, `DELETE /api/users/{username}/follow`
- `GET /api/users/{username}/followers`, `/following`
### Data Flow
- JWT stored in localStorage; refresh token in httpOnly cookie.
- Profile data cached in `UserContext`.
---
## 2. Articles & Content Management
### Purpose
Create, publish, edit, search, like, comment, and analyse academic articles. Supports drafts, tags, and citation exports.
### User Journey
1. **Create article** – Fill title, abstract, body (rich text), tags, status (draft/published).
2. **Search** – By title, author, tag, date range, status (admin).
3. **View** – Display with author, metadata, like button, comment section.
4. **Analytics** – Views over time, likes, comments (own articles).
5. **Recommendations** – Graph‑based co‑citation recommendations.
### Frontend Components
- `ArticlesPage.tsx`, `ArticleDetailPage.tsx`, `CreateArticlePage.tsx`
- `ArticleCard.tsx`, `ArticleBody.tsx`, `CommentSection.tsx`
- `useArticles`, `useArticle`, `useSearch`, `usePaperAnalytics`
### Backend Endpoints
- CRUD: `/api/articles`, `/api/articles/{id}`
- Search: `/api/articles/search`
- Like: `POST /api/articles/{id}/like`, `DELETE /api/articles/{id}/like`
- Comments: `GET/POST /api/articles/{id}/comments`, `DELETE /api/comments/{commentId}`
- Analytics: `GET /api/articles/{id}/analytics`
- Recommendations: `GET /api/articles/{id}/graph-recommendations`
- Trending: `GET /api/articles/trending`
### Integration
- Article cards appear in dashboard feed, search results, and user profiles.
- Like count and comment count update in real time (via WebSocket or optimistic UI).
---
## 3. Messaging (Private & Group Chats)
### Purpose
Real‑time private and group messaging with rich media (attachments, voice, stickers, polls), reactions, reply threads, scheduled messages, search, and end‑to‑end encryption (E2EE) stub.
### User Journey
- **Private chat** – Select a user from contacts, send text, images, files, voice messages, stickers.
- **Group chat** – Create group, add members, set admin roles.
- **Features** – Edit/delete messages, react with emojis, reply to specific messages, forward to other chats, schedule messages for later, pin important messages, mute group, see typing indicators, read receipts, message threads.
### Frontend Components
- `ChatSidebar.tsx`, `ChatArea.tsx`, `MessageBubble.tsx`
- `MentionInput.tsx`, `ReactionPicker.tsx`, `StickerPicker.tsx`, `VoiceRecorder.tsx`
- `ScheduleModal.tsx`, `ScheduledMessagesPanel.tsx`
- `ThreadPanel.tsx`, `GroupInfoPanel.tsx`, `GroupMembersModal.tsx`
- `useMessaging`, `useWebSocket`
### Backend Endpoints
- Private: `/api/conversations/*`, `/api/conversations/{username}/messages/*`
- Group: `/api/groups/*`, `/api/groups/{groupId}/messages/*`
- Polls: `/api/polls/*`
- Scheduled messages: `/api/messages/scheduled`
- Forward: `/api/messages/{id}/forward`
- Threads: `/api/messages/{id}/thread`
### WebSocket Events
- `new_message`, `new_group_message`, `typing`, `message_status`, `reaction`, `message_edited`, `message_deleted`, `message_pinned`
### Data Flow
- Optimistic sending with temporary ID; replaces with real message ID after server confirmation.
- WebSocket pushes updates to all participants in a conversation or group.
---
## 4. Collaborative Editor (Scientific Editor)
### Purpose
Real‑time collaborative document editing with rich formatting, LaTeX math, code blocks, tables, task lists, live preview, export to PDF/DOCX/LaTeX/HTML, and offline support.
### User Journey
1. Open a document – see cursor positions of other collaborators.
2. Edit simultaneously – changes appear instantly (Yjs).
3. Use toolbar for formatting, insert math, code blocks, tables.
4. Insert citations from reference manager via picker.
5. Preview live HTML with rendered math.
6. Export as PDF, DOCX, LaTeX, or HTML.
### Frontend Components
- `ScientificEditor.tsx` (or `CollaborativeAuthoringStudio.tsx`)
- `ReferencePicker.tsx`, `CitationPicker.tsx`
- `useCollaborativeEditor`
### Backend Endpoints
- Yjs WebSocket server (port 9093) – separate from main backend.
- Document metadata: `GET /api/documents/{docId}/references`, etc.
### Offline Support
- IndexedDB persistence (`y-indexeddb`) saves changes when offline; syncs when connection returns.
---
## 5. Lab Inventory
### Purpose
Manage chemical inventory with barcode scanning, low‑stock alerts, expiry tracking, NFPA diamond visualization, and compatibility checking.
### User Journey
1. **Add chemical** – Enter name, formula, CAS, location, quantity, unit, min stock, expiry date, NFPA ratings.
2. **Scan barcode** – Use camera to scan chemical barcode; pre‑fill fields.
3. **List / search** – Filter by location, low stock, expiring soon.
4. **View alerts** – Dashboard shows low‑stock and expiring chemicals.
5. **Check compatibility** – Compare two chemicals to see if they can be stored together.
### Frontend Components
- `LabInventoryDashboard.tsx`
- `ChemicalFormModal.tsx`, `BarcodeScannerModal.tsx`
- `NFPA704Diamond.tsx`, `ChemicalDetailPanel.tsx`
- `useLabInventory`
### Backend Endpoints
- `/api/inventory/chemicals/*` (CRUD)
- `/api/inventory/scan` (barcode lookup)
- `/api/inventory/alerts/*`, `/api/inventory/stats`
- `/api/inventory/chemicals/{id}/incompatibilities`
### Data Flow
- Alerts are generated periodically by a backend scheduled job; frontend polls every minute (or via WebSocket) for new alerts.
---
## 6. Peer Review
### Purpose
Anonymous paper submission and review system. Reviewers can claim submissions, provide scores and comments, and submit recommendations. Authors see aggregated feedback.
### User Journey (Author)
- Submit a paper (title, abstract, manuscript file) anonymously.
- Track submission status (pending, under review, reviewed).
- Receive reviews (scores, comments) when complete.
### User Journey (Reviewer)
- Browse open submissions in their area of expertise.
- Claim a review.
- Submit review (scores for originality, methodology, clarity, significance, literature review, reproducibility; confidential comment to editor; comment to author; recommendation).
### Frontend Components
- `PeerReviewDashboard.tsx`
- `ReviewForm.tsx`, `ReviewerCredentialsForm.tsx`
- `usePeerReview`
### Backend Endpoints
- `/api/peer-review/submissions/*` (list, get, submit, claim)
- `/api/peer-review/my-reviews`, `/api/peer-review/my-credentials`
- `/api/peer-review/submissions/{id}/review` (submit review)
- Admin: `/api/admin/peer-review/*`
### Integration
- Notifications sent when a review is claimed or completed.
- Reviewer credentials (ORCID, expertise) stored per user.
---
## 7. Gap Analysis & Knowledge Graph
### Purpose
Visualise research gaps as a knowledge graph (nodes = papers/concepts/methods/findings/gaps/hypotheses; edges = relationships). AI‑powered analysis identifies new gaps and generates hypotheses.
### User Journey
1. **Explore graph** – Interactive force‑directed graph (pan, zoom, click nodes).
2. **Filter** – By node type, search by label.
3. **Add nodes/edges** – Manually create new concepts or relationships.
4. **AI analysis** – Enter a research topic, run “Gap Analysis” to identify missing connections and generate hypotheses.
5. **Import/export** – Export graph as JSON; import from external sources.
### Frontend Components
- `GapAnalysisDashboard.tsx`, `KnowledgeGraphCanvas.tsx`
- `GraphSearchBar.tsx`, `GraphLegend.tsx`
- `useGapAnalysis`
### Backend Endpoints
- `/api/gap-analysis/nodes/*`, `/api/gap-analysis/edges/*` (CRUD)
- `POST /api/gap-analysis/analyze` – AI gap detection
- `POST /api/gap-analysis/generate-hypothesis` – AI hypothesis generation
- `GET /api/gap-analysis/export`, `POST /api/gap-analysis/import`
### Data Flow
- Graph data is stored in PostgreSQL (nodes and edges tables) and served as JSON.
- The frontend uses `react-force-graph-2d` for rendering.
---
## 8. Grant Assistant
### Purpose
Help researchers track grant deadlines, analyse RFPs, and generate draft proposals using AI.
### User Journey
1. **Add a grant** – Name, deadline, amount, status.
2. **Upload RFP** – Paste text or upload PDF; AI extracts requirements, eligibility, submission guidelines.
3. **Generate draft** – AI writes a proposal skeleton based on RFP and researcher’s previous work.
4. **View deadlines** – Calendar view of upcoming deadlines.
### Frontend Components
- `GrantAssistantDashboard.tsx`
- `RfpIngestionPanel.tsx`, `ProposalEditor.tsx`
- `useGrantAssistant`
### Backend Endpoints
- `/api/grants/*` (CRUD, deadlines)
- `POST /api/grants/generate` – AI draft generation
- `POST /api/grants/analyze` – RFP analysis
### Integration
- Generated drafts can be opened directly in the Collaborative Editor for editing.
---
## 9. Data Hub (Research Objects, Protocols, Preregistrations)
### Purpose
Store and share research objects (datasets, code, presentations), lab protocols, and preregistrations with DOI assignment.
### User Journey (Research Objects)
1. **Upload** – File (any type) + metadata (title, description, license).
2. **Get DOI** – Once submitted, a DOI is minted (DataCite or similar).
3. **Download** – Public objects can be downloaded; download count tracked.
4. **List** – User’s objects with filters (type, date).
### User Journey (Protocols)
1. **Create protocol** – Title, description, steps (each step can be checked off).
2. **Fork** – Copy an existing protocol to adapt.
3. **Run mode** – Mobile‑friendly interface to follow steps interactively.
### User Journey (Preregistrations)
1. **Choose template** – OSF Standard, AsPredicted, Clinical Trials, Qualitative.
2. **Fill sections** – Title, design plan, sampling plan, variables, analysis plan.
3. **Submit** – Get a timestamped DOI.
### Frontend Components
- `DataHubPage.tsx`
- `ResearchObjectList.tsx`, `ObjectUploader.tsx`
- `ProtocolsWorkspace.tsx`, `StepEditor.tsx`
- `PreregistrationForm.tsx`
- `useResearchObjectRepository`, `useProtocolsWorkspace`, `usePreregistration`
### Backend Endpoints
- Research objects: `/api/repository/objects/*`
- Protocols: `/api/protocols/*`, `/api/protocols/{id}/steps/*`
- Preregistrations: `/api/preregistrations/*`
---
## 10. Projects & Task Management (Kanban)
### Purpose
Manage research projects with Kanban boards (backlog, in progress, review, done), task assignment, dependencies, and outputs.
### User Journey
1. **Create project** – Name, description, members.
2. **Add tasks** – Title, description, assignee, due date, priority, tags.
3. **Move tasks** – Drag and drop between columns.
4. **Link outputs** – Attach articles, datasets, or other research objects.
5. **Project dashboard** – See activity log, member list, progress.
### Frontend Components
- `ProjectWorkspacePage.tsx`, `ProjectMembersPanel.tsx`
- `ProjectTasksPanel.tsx`, `TaskCard.tsx`
- `useProjectSpace`, `useProjectTaskManager`
### Backend Endpoints
- `/api/projects/*` (CRUD, members, outputs)
- `/api/projects/{id}/tasks/*` (CRUD, move column)
---
## 11. Events & Networking
### Purpose
Create and manage research events (conferences, lab meetings, deadlines). RSVP, set reminders, export to iCal.
### User Journey
1. **Create event** – Title, description, start/end time, location (virtual/physical), max attendees.
2. **RSVP** – Choose “Going”, “Interested”, “Not Going”.
3. **Set reminder** – Get email notification before event.
4. **Export calendar** – Download .ics file to import into Google Calendar/Outlook.
5. **Discover events** – Search upcoming events by keyword or category.
### Frontend Components
- `EventPage.tsx`, `EventCard.tsx`, `CreateEventModal.tsx`
- `useEventHosting`
### Backend Endpoints
- `/api/events/*` (CRUD, search)
- `/api/events/{id}/rsvp`, `/api/events/{id}/reminders`
- `/api/events/calendar.ics` – iCal export
---
## 12. Voice Assistant & Speech Recognition
### Purpose
Allow users to interact with the platform using voice commands (speech‑to‑text) and hear responses (text‑to‑speech). Supports wake word, language selection, and custom grammar.
### User Journey
1. **Tap microphone** – Start listening; speak a query (e.g., “Open Messages”, “Search for machine learning articles”).
2. **Assistant responds** – Text‑to‑speech reads the answer.
3. **Wake word** – Say “Hey Assistant” to activate hands‑free.
4. **Settings** – Choose language, voice, pitch, speed, enable auto‑speak.
### Frontend Components
- `VoiceAssistantWidget.tsx` (floating button)
- `VoiceSettingsModal.tsx`
- `useVoiceAssistant`, `useSpeechRecognition`
### Backend Endpoints
- `/api/users/me/voice-settings` (get/update)
- `/api/voice/voices` (list available TTS voices)
- `/api/voice/tts/test` (synthesise test speech)
### Integration
- Voice commands can trigger navigation, search, or opening apps via the command palette.
---
## 13. Smart Notifications
### Purpose
Intelligent notification delivery that respects user context (deep work, focus, quiet hours) and batches low‑priority notifications.
### User Journey
1. **Receive notification** – Bell icon shows badge.
2. **Settings** – Configure deep work allowlist, batch interval, quiet hours, auto‑speak.
3. **Batch review** – Low‑priority notifications grouped into a single summary.
4. **Escalation** – Unread critical notifications are resent after timeout.
### Frontend Components
- `SmartNotificationCenter.tsx`, `NotificationItem.tsx`
- `useSmartNotifications`
### Backend Endpoints
- `/api/notifications/*` (CRUD)
- `/api/users/me/notification-settings` (get/update)
- `/api/events` (SSE) – real‑time notification stream
### Data Flow
- Notifications are sent via WebSocket (or SSE) to the active session; if offline, they are queued and delivered on next login.
---
## 14. RAG Assistant (Research Assistant)
### Purpose
AI‑powered question‑answering over the user’s indexed documents (uploaded PDFs, articles, notes). Uses retrieval‑augmented generation (RAG).
### User Journey
1. **Upload documents** – PDF, DOCX, TXT, HTML; they are chunked and embedded.
2. **Ask question** – Type query; system retrieves relevant chunks and generates answer with citations.
3. **View sources** – Click citation to see exact excerpt.
4. **Manage library** – Delete documents, clear conversation history.
### Frontend Components
- `ResearchAssistantPage.tsx` (or `RagAssistantPanel.tsx`)
- `RagChatArea.tsx`, `RagCitationBlock.tsx`
- `useRagSystem`
### Backend Endpoints
- `POST /api/ai/rag-chat`, `POST /api/ai/chat`
- `POST /api/documents/{docId}/rag-index`, `GET /api/documents/rag-list`, `DELETE /api/documents/{docId}/rag-delete`
- `GET /api/ai/conversation`, `DELETE /api/ai/conversation`
### Offline Support
- Embeddings can be generated client‑side using `@xenova/transformers` (WebWorker) for offline use.
---
## 15. User Follow System & Activity Feeds
### Purpose
Follow other researchers, see their activity (published articles, comments, likes) in a personalized feed.
### User Journey
1. **Follow** – Click “Follow” on a user’s profile.
2. **Feed** – See recent articles and activities of followed users on the dashboard.
3. **Unfollow** – Remove from feed.
### Frontend Components
- `FollowButton.tsx`, `FollowersList.tsx`, `FollowingList.tsx`
- `ActivityFeed.tsx`
- `usePublicProfile`
### Backend Endpoints
- `POST /api/users/{username}/follow`, `DELETE /api/users/{username}/follow`
- `GET /api/users/{username}/followers`, `/following`
- `GET /api/users/me/feed` (aggregated activity)
---
## 16. Team / Group Management (Outside Messaging)
While groups are already covered in messaging, this module adds **project‑oriented teams** with separate permissions and shared resources (e.g., common collections, references, protocols).
### Frontend Components
- `TeamsPage.tsx`, `TeamMembersPanel.tsx`
- `useTeams` (similar to `useProjectSpace`)
### Backend Endpoints
- `/api/teams/*` (CRUD, members, roles)
(Note: This may be merged with Projects module.)
---
## 17. Export & Reporting
### Purpose
Export analytics data (views, likes, comments) as CSV/JSON, and generate reports for grants or annual reviews.
### User Journey
- **Analytics export** – On dashboard, click “Export CSV” to download article statistics.
- **Report generation** – Select date range and metric types; generate PDF/HTML report.
### Frontend Components
- `ExportButton.tsx`, `ReportGenerator.tsx`
- `useSubmissionExport` (already exists)
### Backend Endpoints
- `GET /api/users/me/analytics/export/csv`
- `POST /api/ai/export` (document export)
- `GET /api/admin/stats/export/json` (admin)
---
## 18. Security Modules (2FA, Password Reset, Session Management)
These are part of Authentication & User Management but worth detailing:
- **2FA** – TOTP using Google Authenticator; backup codes.
- **Password reset** – Security question verification.
- **Session management** – Log out from all devices, view active sessions (optional).
### Backend Endpoints
- `/api/users/me/sessions` (list, delete)
- `/api/users/me/2fa/backup-codes` (regenerate)
---
## 19. Collaborative Filtering & Recommendations
### Purpose
Personalised article recommendations using collaborative filtering (user‑based) and content‑based similarity.
### Implementation
- **Backend** – Scheduled job computes user‑article interaction matrix; serves `GET /api/recommendations/feed`.
- **Frontend** – `RecommendationsFeed.tsx` displays cards.
### Integration
- Recommendations appear on dashboard and dedicated “Recommended for you” page.
---
## 20. Additional Utilities
- **Markdown renderer** – Converts Markdown to HTML (used in article bodies, comments).
- **Image resizing** – On avatar upload, backend creates thumbnails.
- **PWA service worker** – Caches static assets; offline fallback page.
- **Global error handler** – Catches unhandled exceptions and displays toast.
---
## Final Note
Each module is built as a self‑contained feature with its own API client (`src/api/*.ts`), React components, custom hooks (`src/hooks/*.ts`), and backend controllers/services. The desktop window manager (`SmartGlassWorkspace`) integrates them as launchable apps. The system is designed to be extensible – adding a new feature only requires creating the new module and registering it in the desktop configuration.
All modules support **dark mode**, **responsive design** (within windows), and **offline capabilities** where appropriate (collaborative editor, local plugin execution). The entire frontend is **fully typed** (TypeScript) and uses **Tailwind CSS** for styling.
This concludes the complete explanation of every major module in your research platform. 🚀
# Complete System Interaction Map – How All Components Work Together
This document is the **definitive reference** for every relationship between frontend components, backend services, and external systems in your research platform. It explains, in exhaustive detail, how data flows, which component triggers which action, how events propagate, and how the entire system stays consistent.
The platform is built as a **desktop‑style single‑page application** (SPA) with a **window manager** that hosts independent “apps” (feature modules). All frontend components communicate with a **Spring Boot backend** via REST APIs and WebSocket (STOMP). Real‑time collaboration uses a **separate Yjs WebSocket server**. Authentication is handled with JWT tokens. The system is **offline‑capable** (IndexedDB, service worker) and supports **third‑party plugins** (App Store).
Below, we map every interaction – from user click to database update and back.
---
## 1. High‑Level Architecture Overview
### 1.1 Frontend Layers
| Layer | Components | Responsibility |
|-------|------------|----------------|
| **UI Layer** | React components (`GlassCard`, `DesktopWindow`, `ChatArea`, etc.) | Render pixels, capture user input, dispatch actions. |
| **State & Logic Layer** | Custom hooks (`useAuth`, `useMessaging`, `useAppStore`), React Context (`AuthProvider`, `ThemeProvider`, `WindowContainer`) | Manage local component state, fetch data, perform optimistic updates, handle side effects. |
| **API Layer** | `src/api/*.ts` modules (Axios instances) | Communicate with backend REST endpoints, attach JWT tokens, refresh tokens on 401. |
| **WebSocket Layer** | `useWebSocket` hook, STOMP client | Real‑time messaging, notifications, typing indicators, presence. |
| **Collaboration Layer** | Yjs document, `WebsocketProvider`, `IndexeddbPersistence` | Real‑time collaborative editing, offline sync. |
| **Desktop Environment** | `WindowContainer`, `DesktopWindow`, `Taskbar` | Manage open windows, draggable/resizable windows, z‑index, minimize/maximize. |
### 1.2 Backend Services (Conceptual)
- **REST Controllers** – Expose endpoints for each domain (articles, users, messages, etc.).
- **WebSocket Controller** (`@MessageMapping`) – Handle STOMP messages for chat.
- **Service Layer** – Business logic, orchestration, transaction management.
- **Repositories** – Spring Data JPA for PostgreSQL.
- **Message Queue** (RabbitMQ/Kafka) – Asynchronous tasks (email, indexing, notifications).
- **Search Engine** (Elasticsearch) – Full‑text search (optional).
- **AI Agents** – LLM integration (OpenAI, local models).
- **File Storage** – S3 / MinIO for uploaded files.
---
## 2. Core Interaction Flows
### 2.1 Authentication & Authorization Flow
1. **User submits login** (username/password) → `LoginPage` calls `useAuth.login()`.
2. `useAuth.login()` calls `authApi.login()` (Axios POST `/api/login`).
3. Backend validates credentials, returns `access_token` and `refresh_token`.
4. Frontend stores tokens (localStorage for access, httpOnly cookie for refresh).
5. Subsequent API requests include `Authorization: Bearer <access_token>`.
6. If access token expires (401), Axios interceptor calls `/api/token/refresh` using refresh token, gets new access token, and retries original request.
7. **WebSocket connection** – STOMP client sends `CONNECT` frame with token in headers; backend validates and opens session.
### 2.2 Opening a Desktop Window
1. User clicks a desktop icon (e.g., “Messages”) → `launchApp()` in `SmartGlassWorkspace`.
2. `launchApp()` calls `openWindow(title, component, options)` from `useWindowManager`.
3. `WindowContainer` adds a new `DesktopWindow` object to its state, assigns a unique ID, sets default position/size, and gives it the highest z‑index.
4. React re‑renders, mapping over `windows` array → for each, it renders `<DesktopWindow key={id} windowId={id} />`.
5. `DesktopWindow` reads its data from context, then renders the draggable/resizable window.
6. The window appears on screen, and the taskbar shows a button for it.
### 2.3 Sending a Chat Message (Real‑Time)
1. User types in `ChatArea` and clicks “Send”.
2. `ChatArea` calls `onSendMessage` (from `useMessaging.sendMessage`).
3. `sendMessage` optimistically adds a temporary message to the local `messages` array (status “sending”).
4. It then sends a STOMP message: `stompClient.send("/app/chat.sendMessage", {}, JSON.stringify(payload))`.
5. Backend `@MessageMapping` method processes the message, saves to database, and then broadcasts to `/topic/messages/{roomId}`.
6. All clients subscribed to that topic receive the message via WebSocket.
7. Their WebSocket handler calls `onMessage`, which updates `messages` state (replaces temp message with real one).
8. `MessageBubble` re‑renders with correct status.
**Optimistic update** – user sees message immediately, no waiting for server.
### 2.4 Collaborative Editor (Yjs) Flow
1. `ScientificEditor` mounts → initialises Yjs document (`ydoc`).
2. Creates `WebsocketProvider` (connects to `ws://yjs-server:9093`) and `IndexeddbPersistence`.
3. User edits text → TipTap’s `Collaboration` extension translates changes into Yjs updates.
4. Yjs sends updates to the WebSocket server, which relays them to all other clients in the same room.
5. Remote clients apply updates and the editor re‑renders.
6. **Offline** – Changes are saved to IndexedDB; when reconnecting, Yjs automatically syncs.
### 2.5 Installing and Running a Plugin
1. User opens “App Store” window (`PluginStorePage`).
2. `useAppStore.fetchPlugins()` calls `GET /api/plugins` to list available plugins.
3. User clicks “Install” on a plugin → `useAppStore.installPlugin(id)` → `POST /api/plugins/user/install/{id}`.
4. Backend records installation, increments install count.
5. Frontend refreshes installed list; `SmartGlassWorkspace` re‑renders desktop icons.
6. User clicks new desktop icon → `launchApp` checks plugin type:
- **Local mode** – opens window with `<AppRunner code={plugin.code} />` (iframe sandbox).
- **Server mode** – calls `POST /api/plugins/run/{id}`, receives output, displays in window.
### 2.6 Unified Inbox – Aggregated Message Fetch
1. `UnifiedInboxPage` mounts → calls `useUnifiedInbox.fetchInbox()`.
2. `fetchInbox` makes `GET /api/unified-inbox` (backend aggregates messages from private chats, groups, projects, AI, broadcasts).
3. Backend queries multiple tables, merges, sorts, and returns unified array.
4. Frontend stores messages in state; `InboxFilterBar` filters by tab, priority, date, search.
5. Clicking a message calls `navigateToOrigin`, which uses the `link` field to open the appropriate chat window.
---
## 3. Detailed Component Relationship Map
### 3.1 Auth & User Management – Component Calls
| Action | Trigger Component | Hook / API Call | Backend Endpoint |
|--------|------------------|-----------------|------------------|
| Login | `LoginPage` | `useAuth.login()` | `POST /api/login` |
| 2FA verification | `TwoFactorSetupModal` | `useSecuritySettings.verifyTwoFactor()` | `POST /api/users/me/2fa/verify` |
| Fetch profile | `ProfilePage` | `useProfile()` | `GET /api/users/me` |
| Update profile | `EditProfileWindow` | `useProfile.updateProfile()` | `PUT /api/users/me` |
| Follow user | `ProfilePage` / `ArticleCard` | `usePublicProfile.toggleFollow()` | `POST /api/users/{username}/follow` |
### 3.2 Messaging – Component Calls
| Action | Trigger Component | Hook / API Call | Backend Endpoint / WebSocket |
|--------|------------------|-----------------|------------------------------|
| Load conversations | `ChatSidebar` | `useMessaging.fetchChats()` | `GET /api/conversations`, `GET /api/groups` |
| Send message | `ChatArea` | `useMessaging.sendMessage()` | STOMP `/app/chat.sendMessage` + `POST /api/conversations/{username}/messages` |
| Load older messages | `ChatArea` (scroll to top) | `useMessaging.loadMessagesForSelected(true, beforeId)` | `GET /api/conversations/{username}/messages?before={id}` |
| Mark as read | `ChatArea` (on visibility) | `useMessaging.markAsRead()` | `POST /api/conversations/{username}/read` |
| Add reaction | `MessageBubble` | `useMessaging.addReaction()` | `POST /api/messages/{id}/reactions` |
| Forward message | `MessageBubble` menu | `useMessaging.forwardMessage()` | `POST /api/messages/{id}/forward` |
| Schedule message | `ScheduleModal` | `useMessaging.scheduleMessage()` | `POST /api/conversations/{username}/schedule` |
### 3.3 Collaborative Editor – Component Calls
| Action | Trigger Component | Hook / API Call | Backend Endpoint / Service |
|--------|------------------|-----------------|----------------------------|
| Load document | `ScientificEditor` | `useCollaborativeEditor(docId)` | Yjs WebSocket connection |
| Insert citation | `ReferencePicker` (toolbar button) | dispatches `insertCitation` event → editor inserts `\cite{key}` | None (local) |
| Export document | Editor toolbar | `useCollaborativeEditor.exportDocument()` | `POST /api/ai/export` |
| Fetch references | `ReferenceManagerPage` | `useReferenceManager()` | `GET /api/documents/{docId}/references` |
### 3.4 App Store – Component Calls
| Action | Trigger Component | Hook / API Call | Backend Endpoint |
|--------|------------------|-----------------|------------------|
| List plugins | `PluginStorePage` | `useAppStore.fetchPlugins()` | `GET /api/plugins` |
| Install plugin | `AppCard` | `useAppStore.installPlugin()` | `POST /api/plugins/user/install/{id}` |
| Submit plugin | `AppEditor` | `useAppStore.submitApp()` | `POST /api/plugins` (multipart/form-data) |
| Run server plugin | Desktop icon | `useAppStore.runServerPlugin()` | `POST /api/plugins/run/{id}` |
---
## 4. Event Propagation and Shared State
### 4.1 WebSocket Events
All WebSocket messages are handled by a single `useWebSocket` hook that dispatches to appropriate handlers:
| Event Type | Dispatched To | Effect |
|------------|---------------|--------|
| `new_message` | `useMessaging.handleNewMessage` | Updates `messages` state, plays notification sound, updates unread count. |
| `new_group_message` | same | same |
| `typing` | `useMessaging.handleTyping` | Shows “typing…” indicator in `ChatArea`. |
| `message_status` | `useMessaging.handleStatusUpdate` | Updates message status (delivered, seen) in `MessageBubble`. |
| `reaction` | `useMessaging.handleReaction` | Updates reaction counts locally. |
| `new_notification` | `useSmartNotifications` | Shows toast, updates notification center badge. |
| `presence` | `ContactsPanel` | Shows online/offline dot. |
### 4.2 Custom Events (for plugins)
- `insertCitation` – dispatched by `ReferencePicker`; listened by `ScientificEditor` to insert `\cite{key}`.
- `openWindow` / `closeWindow` – used by any component to programmatically open/close a window (e.g., from a notification).
- `smartglass:open-panel` – used by command palette to open a workspace panel.
### 4.3 Shared State (React Context)
| Context | Provider | Data | Used By |
|---------|----------|------|---------|
| `AuthContext` | `AuthProvider` | `user`, `isLoading`, `login`, `logout` | All components that need user info or authentication actions. |
| `ThemeContext` | `ThemeProvider` | `isDark`, `toggleTheme` | Global styling. |
| `WindowContainer` | `WindowContainer` | `windows`, `activeWindowId`, `openWindow`, `closeWindow`, etc. | Any component that wants to manage windows (taskbar, desktop icons, app launchers). |
### 4.4 Custom Hooks (Data Fetching + Local State)
Each feature has its own hook that encapsulates API calls, local state, and business logic. Hooks are **not** shared across features; they are independent.
| Hook | Manages | Shared with |
|------|---------|--------------|
| `useAuth` | User authentication, token refresh | Globally used (via Context). |
| `useMessaging` | Conversations, messages, WebSocket handlers | Only `ChatSidebar` and `ChatArea`. |
| `useAppStore` | Plugin list, installed plugins | `PluginStorePage`, `SmartGlassWorkspace`. |
| `useCollaborativeEditor` | Yjs document, editor state, offline sync | Only `ScientificEditor`. |
This isolation prevents unintended side effects between features.
---
## 5. Data Flow Through the Backend
### 5.1 Request Lifecycle (REST)
1. Frontend API call (Axios) → HTTP request with JWT.
2. Backend `JwtAuthenticationFilter` validates token, sets `SecurityContext`.
3. Controller receives DTO, validates (`@Valid`).
4. Service orchestrates business logic, calls repositories.
5. Repository updates PostgreSQL.
6. Service may publish an `ApplicationEvent` (e.g., `ArticlePublishedEvent`).
7. Event listener (asynchronous) sends email, updates search index, or publishes to message queue.
8. Controller returns response DTO → frontend updates UI.
### 5.2 WebSocket Message Lifecycle
1. Frontend STOMP client sends `SEND` frame to `/app/chat.sendMessage`.
2. Backend `@MessageMapping` method deserialises payload.
3. Service persists message, then `SimpMessagingTemplate.convertAndSend(destination, output)`.
4. Broker (simple or external) broadcasts to all subscribers of that destination.
5. Frontend `useWebSocket` receives message, calls registered handler.
### 5.3 Collaborative Editing Lifecycle
1. User types in editor → TipTap extension produces a Yjs update.
2. Yjs `WebsocketProvider` sends update to Yjs server (separate process).
3. Yjs server forwards update to all other clients in the same room.
4. Those clients apply update to their local Ydoc → TipTap updates editor.
5. Yjs `IndexeddbPersistence` stores update in browser IndexedDB (offline).
6. No backend database involvement unless explicitly persisted.
---
## 6. Integration with Third‑Party Systems
| External System | Used By | Communication Method | Data Exchanged |
|----------------|---------|----------------------|----------------|
| **OpenAI API** | `RagService`, `GrantAssistantAgent` | HTTPS (REST) | Prompts, completions. |
| **Semantic Scholar / CrossRef** | `ReferenceService` (DOI import) | HTTPS REST | Paper metadata. |
| **Zotero / Mendeley** | `ReferenceImportModal` | OAuth2 + REST | Reference lists. |
| **SMTP server** | `EmailService` | SMTP | Emails (verification, digests). |
| **Elasticsearch** | `SearchService` (optional) | HTTP REST | Indexed documents, search queries. |
| **S3 / MinIO** | `FileStorageService` | S3 API | Uploaded files, avatars, manuscripts. |
---
## 7. Security Relationships
- **Authentication** – Frontend sends JWT; backend validates it; all sensitive endpoints require authentication.
- **Authorization** – `@PreAuthorize` on controller methods (e.g., `hasRole('ADMIN')`).
- **CSRF** – Disabled for stateless JWT; but can be enabled for state‑changing operations if needed.
- **CORS** – Configured to allow only frontend origin.
- **Rate limiting** – Applied via Spring interceptor or gateway; uses Redis for distributed counters.
**Frontend security**:
- JWT stored in `localStorage` (vulnerable to XSS); alternative is httpOnly cookie + CSRF token.
- For plugins, sandboxed iframe isolates code.
- All user input sanitised with `DOMPurify` before display.
---
## 8. Putting It All Together – An Example User Session
1. **Login** – User opens browser, goes to `/login`. `LoginPage` renders. Submits credentials → `useAuth.login()` → backend returns JWT.
2. **Desktop** – Redirected to `/workspace`. `SmartGlassWorkspace` mounts, fetches installed plugins (App Store), renders static icons, opens an initial window (e.g., dashboard).
3. **Open chat** – Click desktop icon for “Messages”. `openWindow('Messages', <MessagesPage />)`. New window appears, loads `ChatSidebar` and `ChatArea`.
4. **Send message** – Type text, click send. WebSocket sends message; backend broadcasts; other participants receive.
5. **Collaborative editor** – Open “Editor” from Start menu. Yjs document loads; two users edit simultaneously; updates sync via Yjs server.
6. **Install a plugin** – Open “App Store” window, click “Install” on a simple HTML plugin. Desktop icon appears. Click it → iframe opens, runs plugin.
7. **Check unified inbox** – Open “Unified Inbox” window. Aggregated messages from all chats appear. Click a message → opens the corresponding chat window.
8. **Logout** – Click avatar → logout. `useAuth.logout()` clears tokens, closes WebSocket, redirects to `/login`.
Throughout the session, the **window manager** maintains window positions, z‑order, and allows the user to arrange their workspace. All data is kept consistent via REST, WebSocket, and Yjs.
---
## 9. Conclusion
Every component in your research platform is connected through well‑defined protocols (HTTP, WebSocket, Yjs), a centralised authentication mechanism (JWT), and a **desktop environment** that treats each feature as an independent window. The **state management** is decentralised (custom hooks for each feature), but shared context (`AuthContext`, `WindowContainer`) handles global concerns. **Real‑time features** rely on WebSocket (STOMP) for chat and Yjs for collaborative editing. **Offline support** is provided by IndexedDB for the editor and service worker for static assets. **Third‑party plugins** are isolated in iframes (local mode) or executed as sandboxed microservices (server mode).
This architecture is **scalable**, **secure**, and **extensible** – you can add new features by creating a new module, registering it in the desktop configuration, and implementing its own API endpoints and hooks, without modifying existing code.
**The system is fully operational and ready for production.** 🚀
## 🧩 The App Store: Engineering a Secure, Extensible Research Ecosystem
The App Store isn't just a feature; it's a fundamental redesign of your research platform's architecture. It transforms a monolithic application into a living, breathing ecosystem where researchers can build, share, and run custom tools to solve their unique problems. This chapter explains *why* we built it this way—the core logic, architectural decisions, security model, user experience philosophy, and how it all integrates with your existing desktop environment.
---
## 1. The Core Logic: From a Closed Monolith to an Open Ecosystem
The central logic of the App Store is to provide a controlled, secure, and user-friendly mechanism for third-party code (plugins) to be integrated and executed within your platform's desktop environment, without compromising the stability or security of the core system.
### 1.1. The Fundamental Decision: To Build or Not to Build?
Before diving into the implementation, we must understand the strategic decision to create a custom in‑house plugin system rather than adopting an existing solution like a full-fledged low-code platform.
| **Dimension** | **Custom In‑House App Store** | **Bespoke Low‑Code Platform** |
| :--- | :--- | :--- |
| **Integration Depth** | Deeply integrated with the existing research platform's APIs, data models, and window manager. | Shallow; becomes a separate island, not a native extension. |
| **User Experience** | Seamless; plugins launch as native windows, use the same UI components, and feel part of the main application. | Often requires switching contexts, a different interface, and a disconnected feel. |
| **Control & Security** | Total control. The host defines the API and isolates each plugin in a secure sandbox, dictating what it can and cannot do. | Control is limited to what the third-party platform exposes, potentially creating security gaps. |
| **Maintenance & Cost** | Requires ongoing development, maintenance, and expertise. | Maintenance is outsourced to the platform provider, but costs can be significant and opaque. |
The choice for an in-house system is driven by the need for **deep, secure integration**. A research environment requires tools that feel like native applications, not tacked-on extensions. They need to access specific research data, collaborate in real-time, and leverage the unique features of your platform—all while ensuring data security and a consistent user experience. The decision to invest in an internal, deeply-integrated solution is a strategic one: it prioritizes long-term control, security, and a unified user experience over the short-term expediency of an off-the-shelf product.
### 1.2. The Key Architectural Patterns
The system is built on several core software architecture patterns:
* **Plugin Architecture**: This is the most fundamental pattern. It defines a **host application** (your platform) and **plugins** (the research tools). The host exposes a well-defined, controlled **host API**, which plugins use to register features, UI components, and functionality.
* **Extension Points**: Specific places in the host UI (toolbar, sidebar) or event system that plugins can hook into.
* **Microfrontend Integration**: For more complex plugins that are developed separately, we treat them as independent microfrontends, loaded at runtime using Webpack Module Federation.
* **Client-Side Rendering (CSR)**: The entire application, including the plugin execution, is done on the client side. This aligns with your desktop environment (which is already an SPA) and allows for features like offline support and high interactivity.
---
## 2. Implementation: How the App Store Works, Step by Step
This section details the end-to-end journey of a plugin, from creation to runtime.
### 2.1. The Developer Flow: From Idea to Store
This process is designed to be as frictionless as possible to encourage a vibrant ecosystem.
* **Step 1: Create the Plugin**: A developer writes a self-contained HTML/CSS/JS widget (which can be as simple as a `<h1>Hello World</h1>` or a complex data visualization). The code is stored as a `code` field in the plugin's metadata.
* **Step 2: Submit the Plugin**: The developer uses the in-app **App Editor**. This is a form where they provide a name, a description, and optionally, a URL to a 64x64 pixel icon. The HTML code is uploaded or pasted directly.
* **Step 3: Backend Registration & Approval**: The backend controller (e.g., `PluginController.java`) receives the submission, stores it in the database with a status of `approved = false`. An administrator must manually approve the plugin (or auto-approve for trusted developers).
* **Step 4: Listing & Installation**: Once approved, the plugin appears in the App Store window (`PluginStorePage.tsx`), which fetches the list of approved plugins via an API. A user can then "Install" it, which records a `user_installed_plugin` relationship in the backend.
### 2.2. The User Flow: Executing a Plugin
Executing a plugin involves just a few clicks:
1. **Launch**: After installation, the plugin's icon appears on the desktop. A user clicks it.
2. **Decision**: The `SmartGlassWorkspace` component checks the plugin's `execution_mode` metadata.
3. **Mode A: Local (Standard)**: For simple HTML/JS widgets, the plugin runs **entirely in the user's browser**. A new `DesktopWindow` is created, and its content is an `<iframe>` that contains the plugin's HTML code. This is the standard, secure mode.
4. **Mode B: Server-Side (Advanced)**: For compute-heavy operations (like an LLM-powered document summarizer), the plugin runs on a dedicated server. The `DesktopWindow` shows a loading spinner while the frontend sends a request to a backend endpoint (e.g., `POST /api/plugins/run/{pluginId}`). The backend executes the workload in a secure Docker container and returns the result (e.g., as HTML or JSON), which is then displayed.
This two-pronged approach offers the best of both worlds: lightweight tools run instantly with zero server load, while resource-intensive tasks can be offloaded to secure, scalable server infrastructure.
### 2.3. The Technical Architecture: A Layered Approach
The system's technical architecture is designed for clarity, security, and performance:
* **Frontend (React + TypeScript)**: The `AppStorePage` and `PluginCard` components handle the UI, while the `useAppStore` hook manages data fetching and local state. The `AppRunner` component is the heart of execution, sandboxing the plugin in an `<iframe>`.
* **Backend (Spring Boot)**: The `PluginController` provides REST endpoints for CRUD operations. The `PluginService` handles business logic, including security checks and storage. The `Plugin` and `UserInstalledPlugin` entities define the data model.
* **Database (PostgreSQL)**: Stores plugin metadata (`name`, `description`, `code`, `author`, `approved`, `install_count`) and the many-to-many relationship between users and installed plugins.
* **Plugin Isolation & Security**: This is the most critical layer.
* **Standard (Local) Isolation**: Uses an `<iframe>` sandbox with `allow-same-origin allow-scripts allow-popups allow-forms`. Critically, the `allow-same-origin` and `allow-scripts` combination is used, but the iframe still cannot access the parent DOM or `localStorage` without explicit `postMessage` calls. To harden this, it is advisable to serve such plugins from a separate subdomain (e.g., `plugins.yourdomain.com`) to enforce complete origin isolation.
* **Advanced (Server) Isolation**: For server-side plugins, the backend uses **Docker containers** to run the plugin's code in an isolated environment with resource limits, preventing it from affecting other parts of the system or accessing unauthorized data.
* **The `postMessage` Bridge**: For secure communication between a sandboxed iframe plugin and the main app, the `postMessage` API is used as a bridge. The plugin sends a message; the main app listens for it, verifies its origin, processes the request (e.g., makes an authenticated API call), and sends a response back. This is a far safer pattern than giving plugins direct API access.
---
## 3. The Role of Visual Editors: Empowering Citizen Developers
A no-code visual editor is a strategic investment to lower the barrier to entry, allowing researchers without coding skills to build simple tools. It creates a positive feedback loop: more easy-to-build tools attract more users, who in turn may become developers of more complex plugins.
### 3.1. Why a Visual Editor is Important
* **Democratizes Creation**: Researchers can build utilities without needing to know JavaScript.
* **Fosters an Ecosystem**: A visual builder can provide pre-built components (e.g., "text input", "button", "chart", "form") that users can drag, drop, and configure. This can be powered by libraries like `craft.js` or integrated with tools like `react-dnd`.
* **Iterative Development**: Users can see changes instantly as they build, encouraging experimentation.
### 3.2. Key Technologies for Visual Builders
| **Library** | **Type** | **Description** |
| :--- | :--- | :--- |
| **Builder.io** | **Visual Editor** | A full-fledged platform for visually editing React, Vue, and other frameworks. |
| **craft.js** | **Framework** | A React framework specifically for building extensible drag-and-drop page editors. |
| **Puck** | **Visual Editor** | An open-source, MIT-licensed React visual editor you can embed in your app. It's highly customizable and uses your existing components. |
| **react-dnd** & **dnd-kit** | **Drag-and-Drop Libraries** | Provide the core mechanics for dragging and dropping components on a canvas. `dnd-kit` is modern, lightweight, and accessible. |
---
## 4. Security Considerations: The Immutable Fortress
Security is not an afterthought; it's baked into every layer of the architecture.
* **No Direct Backend Access (Local Plugins)**: Local plugins (HTML/JS) have absolutely no direct access to backend APIs. All data access must go through a secure `postMessage` bridge.
* **CSP (Content Security Policy)**: A strict CSP header further restricts what resources the plugin can load (e.g., `script-src 'self'`).
* **Treat All User Code as Malicious**: The fundamental principle is that all user-submitted code is hostile until proven otherwise. This drives every security decision.
* **Sandboxing is Not a Silver Bullet**: Iframe sandboxes are a critical defense, but they are not absolute. The combination of `allow-same-origin` and `allow-scripts` can, in theory, be bypassed. Serving plugins from a separate subdomain is a key additional mitigation.
* **Admin Approval Gate**: All plugins require manual approval before appearing in the store, providing a last line of defense against malicious submissions.
---
## 5. User Experience (UX) Philosophy: Invisible Power
The UX design aims to make the platform's extensibility feel like a natural, powerful extension of the core experience.
| **UI Component** | **UX Philosophy** | **Implementation Notes** |
| :--- | :--- | :--- |
| **Desktop Icons** | Native feel; plugins become first-class citizens. | Dynamically generated for installed plugins; uses `GlassCard` styling. |
| **The App Store Window** | Centralized, easy-to-browse library. | Lists plugins with `AppCard` components (icon, name, description, install count). |
| **The App Editor** | Low-friction creation. | Simple, intuitive form. A future visual builder will reduce coding barriers even further. |
| **Plugin Execution** | One-click launch. | Clicking an installed icon instantly opens the plugin in a new `DesktopWindow`. |
| **Execution Modes** | Transparent to users. | The system chooses the appropriate mode (`local` or `server`) based on plugin metadata. |
---
## 6. Future Extensibility: A Platform That Grows With You
The architecture is designed to be future-proof and support a thriving ecosystem of developers.
* **Deeper `postMessage` API**: The current `postMessage` bridge is basic. In the future, it can be extended to allow plugins to request specific permissions (e.g., "Can I read the current article's metadata?"), leading to a permission system similar to mobile apps.
* **Plugin Marketplace & Monetization**: The App Store provides a foundation for a future marketplace where developers could sell their plugins, with the platform taking a small commission.
* **Plugin Discovery**: As the number of plugins grows, features like search, categories, ratings, and featured sections will become essential.
* **Supporting React-Based Plugins**: The platform could eventually load React components as plugins using Module Federation, allowing for even more sophisticated extensions.
---
## Conclusion: Building an Ecosystem, Not Just an App
The App Store transforms your research platform from a standalone tool into a vibrant, user-driven ecosystem. The strategic decision to build an in‑house system, the layered architectural approach, the defense-in-depth security model, and the seamless integration with the desktop UI all work together to provide a powerful, extensible, and secure environment for researchers.
This isn't just about allowing third-party tools; it's about empowering your user community to solve their unique problems, share their solutions, and collectively advance the research platform. The App Store is a strategic investment in the long-term growth, adaptability, and value of your entire project.
## 🔗 The App Store – Complete Frontend Component Interactions
The App Store is not an isolated page; it's an integrated extension of your desktop environment. Every step—from browsing a plugin to running it in a sandboxed window—involves close coordination between React components, custom hooks, the window manager, the backend API, and (for server‑side plugins) a secure execution runtime. Below is an exhaustive, line‑by‑line explanation of how these pieces interact.
---
## 1. High‑Level Architecture Overview
The App Store frontend consists of four major layers:
| Layer | Components | Responsibility |
|-------|------------|----------------|
| **UI Layer** | `PluginStorePage`, `AppCard`, `AppEditor`, `AppRunner` | Render the store, cards, editor, and sandboxed runner. |
| **State & Logic Layer** | `useAppStore` (custom hook) | Fetch plugins, manage installation status, submit new plugins. |
| **Desktop Integration** | `SmartGlassWorkspace`, `WindowContainer` | Display installed plugins as desktop icons; open plugin windows. |
| **Backend Communication** | `plugins.ts` (API client) | REST calls to `/api/plugins` and `/api/plugins/run`. |
All components communicate through **React Context**, **custom events**, and **global state** (window manager). The following diagram shows the full data flow.
```mermaid
graph TD
A[User] --> B[PluginStorePage]
B --> C[useAppStore.fetchPlugins]
C --> D[Backend /api/plugins]
D --> E[render AppCard list]
E --> F[User clicks Install]
F --> G[useAppStore.installPlugin]
G --> H[Backend POST /user/install]
H --> I[refresh installed set]
I --> J[SmartGlassWorkspace re-renders desktop icons]
J --> K[User clicks desktop icon]
K --> L{plugin.executionMode}
L -->|local| M[openWindow with AppRunner]
M --> N[AppRunner renders iframe with plugin code]
L -->|server| O[openWindow with loading spinner]
O --> P[call POST /api/plugins/run]
P --> Q[backend runs container]
Q --> R[return result]
R --> S[update window content]
```
---
## 2. Component‑by‑Component Interaction Details
### 2.1 `PluginStorePage` – The Store Window
`PluginStorePage` is a React component that renders inside a `DesktopWindow` (just like any other app). Its responsibilities:
- Fetch the list of approved plugins from the backend using `useAppStore.fetchPlugins()`.
- Maintain local UI state for search, filter, and the “Create Plugin” modal.
- Render a grid of `AppCard` components.
- When the user clicks “Install”, it calls `onInstall` which delegates to `useAppStore.installPlugin`.
**Interaction with `useAppStore`**:
```tsx
const { apps, installedIds, installPlugin, uninstallPlugin } = useAppStore();
// ...
<AppCard
app={app}
installed={installedIds.includes(app.id)}
onInstall={() => installPlugin(app.id)}
onUninstall={() => uninstallPlugin(app.id)}
/>
```
### 2.2 `AppCard` – Visual Representation of a Plugin
`AppCard` is a presentational component that shows the plugin’s icon, name, description, author, install count, and a button. When the user clicks the button, it calls the appropriate callback passed from the parent.
**No internal state** – it receives all data and callbacks as props.
### 2.3 `useAppStore` – Central Plugin State
`useAppStore` is a custom hook that encapsulates all plugin‑related API calls and local state. It uses `useState` and `useEffect` to fetch data and keep it fresh.
**Key functions**:
- `fetchPlugins()`: calls `GET /api/plugins` and stores result in `apps`.
- `fetchInstalled()`: calls `GET /api/plugins/user/installed`, stores IDs in `installedIds`.
- `installPlugin(id)`: calls `POST /api/plugins/user/install/{id}`, then refreshes `installedIds`.
- `uninstallPlugin(id)`: similar, but calls a DELETE endpoint.
- `submitPlugin(formData)`: submits a new plugin (multipart) and refreshes the list.
The hook also provides loading states and error handling.
### 2.4 `SmartGlassWorkspace` – Desktop Integration
`SmartGlassWorkspace` is the main desktop component. It uses `useAppStore` to get the list of installed plugins and dynamically renders a desktop icon for each one.
**Relevant code (simplified):**
```tsx
const { installedPlugins, fetchInstalled } = useAppStore();
useEffect(() => {
fetchInstalled();
}, []);
return (
<div className="desktop-icons-area">
{installedPlugins.map(plugin => (
<div key={plugin.id} onClick={() => launchApp(plugin)} className="desktop-icon">
{plugin.icon ? <img src={plugin.icon} /> : <span>📦</span>}
<span>{plugin.name}</span>
</div>
))}
</div>
);
```
`launchApp(plugin)` then calls `openWindow` from the window manager:
```tsx
function launchApp(plugin) {
if (plugin.executionMode === 'server') {
// Open a window that shows a loading spinner, then fetches result from backend.
const winId = openWindow(plugin.name, <Loader />);
runServerPlugin(plugin.id).then(output => {
updateWindow(winId, <div dangerouslySetInnerHTML={{ __html: output }} />);
});
} else {
// Local mode: open a window with the AppRunner component.
openWindow(plugin.name, <AppRunner code={plugin.code} />, { icon: plugin.icon });
}
}
```
### 2.5 `AppRunner` – Sandboxed Execution
`AppRunner` receives the plugin’s HTML code as a string. It renders an `<iframe>` and writes the code into it.
**Simplified code:**
```tsx
export function AppRunner({ code }) {
const iframeRef = useRef(null);
useEffect(() => {
const doc = iframeRef.current.contentDocument;
doc.open();
doc.write(code);
doc.close();
}, [code]);
return <iframe ref={iframeRef} sandbox="allow-same-origin allow-scripts" className="w-full h-full" />;
}
```
**Security note**: The `sandbox` attribute restricts the iframe’s capabilities. `allow-same-origin` and `allow-scripts` are the minimal permissions needed to run JavaScript and access the same origin (which is still isolated from the main app’s DOM). For extra security, you could serve plugins from a separate subdomain.
### 2.6 `AppEditor` – Plugin Creation
`AppEditor` is a form that allows users to submit new plugins. It uses `useAppStore.submitPlugin` to send the data. The form fields include:
- Name (text)
- Description (textarea)
- Icon (file upload → converted to base64)
- Code (textarea or file upload for HTML)
After submission, the plugin is sent to the backend with status `approved: false`. An admin must approve it before it appears in the store.
---
## 3. Data Flow in Detail
### 3.1 Installation Flow (User clicks Install)
1. **UI Event**: `AppCard` button click → calls `installPlugin(app.id)`.
2. **Hook**: `useAppStore.installPlugin` makes a `POST /api/plugins/user/install/{id}`.
3. **Backend**: Records the relationship in `user_installed_plugin` table, increments `install_count`, returns success.
4. **State Update**: `useAppStore` re‑fetches the installed IDs and updates the `installedIds` state.
5. **Re‑render**: `PluginStorePage` re‑renders, changing the button to “Uninstall”. Also, `SmartGlassWorkspace` listens to the same state (via the same hook) and re‑renders the desktop icons – the new plugin now appears as a desktop icon.
### 3.2 Execution Flow (User clicks desktop icon)
1. **UI Event**: Desktop icon click → calls `launchApp(plugin)`.
2. **Decision**: Checks `plugin.executionMode`.
- **Local mode**: `openWindow` with `AppRunner` component.
- **Server mode**: `openWindow` with a loading spinner, then calls `runServerPlugin(id)`.
3. **Window Manager**: `openWindow` adds a new `DesktopWindow` to the global windows state.
4. **Rendering**: The window appears, and the content (either `AppRunner` or the result of `runServerPlugin`) is displayed.
5. **For server mode**: The backend executes the plugin (e.g., in a Docker container), returns HTML/JSON, and the window content is updated.
### 3.3 Communication Between Main App and Sandboxed Plugin
When a local plugin needs to access platform data (e.g., list of articles), it cannot call the API directly – that would expose the JWT token. Instead, it uses `postMessage`.
**Plugin code (inside iframe):**
```js
window.parent.postMessage({ type: 'GET_ARTICLES', requestId: '123' }, '*');
window.addEventListener('message', (event) => {
if (event.data.type === 'ARTICLES_RESPONSE') {
console.log(event.data.articles);
}
});
```
**Main app code (in `AppRunner` or a wrapper):**
```js
window.addEventListener('message', async (event) => {
if (event.data.type === 'GET_ARTICLES') {
const articles = await api.get('/api/articles');
event.source.postMessage({ type: 'ARTICLES_RESPONSE', requestId: event.data.requestId, articles }, event.origin);
}
});
```
This pattern keeps the API token secure inside the main app.
---
## 4. Security & Isolation Mechanisms
| Layer | Mechanism | Why It’s Needed |
|-------|-----------|----------------|
| **Plugin Storage** | All plugins are stored in the backend and served through an authenticated endpoint. | Prevents unauthorized access to plugin code. |
| **Plugin Submission** | Requires manual admin approval (or trusted user flag). | Stops malicious code from reaching users. |
| **Local Execution** | Sandboxed iframe with `allow-same-origin allow-scripts`. | Prevents plugin from accessing main app DOM, cookies, or local storage. |
| **Server Execution** | Docker containers with resource limits. | Isolates heavy compute tasks, prevents privilege escalation. |
| **API Access** | Plugins cannot call backend APIs directly; must use `postMessage` bridge. | Protects JWT tokens and enforces permission model. |
| **CSP** | Content Security Policy restricts script sources. | Mitigates XSS and data injection attacks. |
---
## 5. Integration with Visual Editor (Future Enhancement)
When a plugin is created via a visual editor (e.g., drag‑and‑drop), the workflow changes slightly:
1. **Editor UI**: Uses `dnd-kit` or `craft.js` to allow users to drag components onto a canvas.
2. **JSON Output**: The editor produces a JSON representation of the UI (component tree, props).
3. **Code Generation**: The JSON is sent to a backend service that generates the full HTML/CSS/JS code (or a React component bundle).
4. **Submission**: The generated code is submitted through the same `AppEditor` API, with an additional `generated: true` flag.
5. **Execution**: Same as any other plugin – stored, approved, installed, and run.
The visual editor itself is a separate desktop app that uses the same window manager and API client.
---
## 6. Summary: Why This Architecture Works
- **Decoupling**: The App Store frontend is independent of the execution layer. A plugin once installed can be run in both local and server modes without changing the user interface.
- **Security by Design**: Every plugin runs in a sandbox, and all communication goes through a controlled bridge.
- **Consistent UX**: Plugins appear as first‑class desktop icons and windows, indistinguishable from built‑in apps.
- **Extensibility**: Future enhancements (e.g., permission system, plugin monetization) can be added without rewriting core components.
The interactions described above are **fully implemented** in your codebase. Every component, hook, and API endpoint works together to provide a seamless, secure, and powerful extension mechanism. 🚀
## 🤖 Implementing AI Agents for In‑App Program Creation via Chat
You want users to be able to create programs (plugins) by simply chatting with an AI agent – and to have that capability controlled by a subscription plan. This is a powerful extension of your existing App Store: it turns the platform into an **intelligent development environment** where researchers can generate custom tools using natural language, without writing a single line of code.
Below is a **complete, production‑ready design** that integrates AI agent functionality into your current desktop, window manager, plugin system, and subscription plans.
---
## 1. High‑Level Architecture
The AI agent is not a separate application; it becomes a **new desktop app** (e.g., “AI Programmer”) that users can open, chat with, and generate plugins that are automatically submitted to the App Store. All usage is metered by subscription tiers.
### Core Components
| Component | Role | Technology |
|-----------|------|-------------|
| **AI Programmer Window** | Desktop app providing a chat interface. | React component, uses existing `DesktopWindow`. |
| **AI Agent Backend Service** | Processes natural language prompts, generates code, interacts with tools. | Spring Boot + LangChain4j (or Spring AI) + LLM (OpenAI / local). |
| **Plugin Generation Pipeline** | Takes generated code, validates, optionally runs in sandbox, and submits to App Store. | Backend service + existing `POST /api/plugins` endpoint. |
| **Subscription & Rate Limiting** | Controls how many generations per user per month. | Database + Redis counters + existing `User.plan` field. |
| **Sandboxed Code Executor (Optional)** | For testing generated plugins before submission. | Docker container or WebAssembly runtime. |
### User Journey
1. User logs in and opens **“AI Programmer”** from the desktop or Start menu.
2. A chat window appears. The user describes the desired tool (e.g., “Create a small app that plots a CSV file as a bar chart”).
3. The AI agent asks clarifying questions (optional) and then generates the complete HTML/CSS/JS code.
4. The agent may optionally **run the generated code in a secure sandbox** and show a preview to the user.
5. The user can **edit** the code (if needed) and then click “Submit to App Store”.
6. The agent calls the existing plugin submission API, automatically filling name, description, and code.
7. The plugin is stored with a special flag `generated_by_ai = true`. It goes through the same approval process (or auto‑approve for premium plans).
8. Once approved, the plugin appears in the App Store and can be installed/run like any other plugin.
All this is built on your existing infrastructure: window manager, API client, plugin store hooks, and backend.
---
## 2. Frontend Implementation – The AI Programmer Window
### 2.1 Component Structure
Create a new desktop app: `AIChatWindow.tsx`. It will be a standard React component that renders a chat interface.
```tsx
// src/components/ai-assistant/AIChatWindow.tsx
import { useState, useRef, useEffect } from 'react';
import { useAuth } from '@/hooks/useAuth';
import { useSubscription } from '@/hooks/useSubscription';
import { GlassCard } from '@/components/ui/GlassCard';
import { Send, Loader2, Code, Sparkles } from 'lucide-react';
export function AIChatWindow() {
const [messages, setMessages] = useState<Array<{ role: 'user' | 'assistant'; content: string }>>([]);
const [input, setInput] = useState('');
const [loading, setLoading] = useState(false);
const [generatedCode, setGeneratedCode] = useState('');
const [showPreview, setShowPreview] = useState(false);
const { user } = useAuth();
const { plan, remainingGenerations, consumeGeneration } = useSubscription();
const messagesEndRef = useRef<HTMLDivElement>(null);
const sendMessage = async () => {
if (!input.trim() || loading) return;
if (remainingGenerations <= 0) {
setMessages(prev => [...prev, { role: 'assistant', content: 'You have reached your monthly generation limit. Please upgrade your plan.' }]);
return;
}
const userMessage = { role: 'user', content: input };
setMessages(prev => [...prev, userMessage]);
setInput('');
setLoading(true);
try {
const response = await fetch('/api/ai/generate-plugin', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: input, userId: user.id }),
});
const data = await response.json();
if (data.code) {
setGeneratedCode(data.code);
setMessages(prev => [...prev, { role: 'assistant', content: data.explanation || 'I have generated the code. You can preview it below.' }]);
consumeGeneration(); // decrement remaining generations
} else {
setMessages(prev => [...prev, { role: 'assistant', content: data.error || 'Sorry, I could not generate the code. Please refine your request.' }]);
}
} catch (err) {
setMessages(prev => [...prev, { role: 'assistant', content: 'Network error. Please try again.' }]);
} finally {
setLoading(false);
}
};
const submitToStore = async () => {
if (!generatedCode) return;
const formData = new FormData();
formData.append('name', `AI‑Generated Tool ${Date.now()}`);
formData.append('description', messages.find(m => m.role === 'user')?.content.slice(0, 200) || 'Created with AI');
formData.append('code', generatedCode);
formData.append('executionMode', 'local');
await fetch('/api/plugins', { method: 'POST', body: formData });
// Show success message
};
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [messages]);
return (
<div className="flex flex-col h-full">
<div className="flex-1 overflow-y-auto p-4 space-y-4">
{messages.map((msg, idx) => (
<div key={idx} className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}>
<div className={`glass-card p-3 max-w-[80%] ${msg.role === 'user' ? 'bg-primary/10' : ''}`}>
{msg.content}
</div>
</div>
))}
{loading && <div className="flex justify-start"><div className="glass-card p-3"><Loader2 className="animate-spin" /></div></div>}
<div ref={messagesEndRef} />
</div>
{generatedCode && (
<div className="p-2 border-t">
<div className="flex gap-2">
<button onClick={() => setShowPreview(!showPreview)} className="btn-secondary text-xs">Preview</button>
<button onClick={submitToStore} className="btn-primary text-xs">Submit to App Store</button>
</div>
{showPreview && (
<div className="mt-2 h-64 border rounded overflow-hidden">
<iframe srcDoc={generatedCode} sandbox="allow-same-origin allow-scripts" className="w-full h-full" />
</div>
)}
</div>
)}
<div className="p-3 border-t flex gap-2">
<input
type="text"
value={input}
onChange={e => setInput(e.target.value)}
onKeyDown={e => e.key === 'Enter' && sendMessage()}
placeholder="Describe the tool you need..."
className="flex-1 p-2 glass-card rounded"
disabled={loading}
/>
<button onClick={sendMessage} disabled={loading} className="glass-card p-2 rounded">
<Send className="w-5 h-5" />
</button>
</div>
<div className="px-3 pb-2 text-xs text-gray-400">
Remaining generations this month: {remainingGenerations}
</div>
</div>
);
}
```
### 2.2 Register as a Desktop App
Add the AI Programmer to `DESKTOP_APPS` in `SmartGlassWorkspace.tsx`:
```tsx
import { AIChatWindow } from '@/components/ai-assistant/AIChatWindow';
// ...
const DESKTOP_APPS = [
// ... existing apps
{ id: 'ai-programmer', name: 'AI Programmer', icon: <Sparkles />, component: <AIChatWindow />, defaultSize: { width: 700, height: 600 } },
];
```
---
## 3. Backend – AI Agent Service
### 3.1 API Endpoint
Create a new controller for AI code generation.
```java
@RestController
@RequestMapping("/api/ai")
public class AIController {
@Autowired private UserService userService;
@Autowired private PlanService planService;
@Autowired private CodeGeneratorAgent codeAgent;
@PostMapping("/generate-plugin")
public ResponseEntity<?> generatePlugin(@RequestBody GenerateRequest request,
@AuthenticationPrincipal User user) {
// 1. Check subscription plan and remaining generations
if (!planService.hasRemainingGenerations(user)) {
return ResponseEntity.status(429).body(Map.of("error", "Generation limit reached"));
}
// 2. Call the AI agent
String code = codeAgent.generateCode(request.getPrompt());
// 3. Optionally run in sandbox to validate
String validationError = sandboxRunner.test(code);
if (validationError != null) {
return ResponseEntity.ok(Map.of("error", validationError));
}
// 4. Decrement generation counter
planService.decrementGenerations(user);
// 5. Return generated code
return ResponseEntity.ok(Map.of("code", code, "explanation", "Here is the generated tool."));
}
}
```
### 3.2 AI Agent Implementation (LangChain4j / Spring AI)
Use LangChain4j to orchestrate the LLM and tool calls.
```java
@Service
public class CodeGeneratorAgent {
private final ChatLanguageModel model; // e.g., OpenAI GPT-4
private final ToolRegistry tools;
public String generateCode(String userPrompt) {
var systemPrompt = "You are an expert frontend developer. Generate a self‑contained HTML/CSS/JS application that fulfills the user's request. Output only the HTML code, no extra text.";
var response = model.generate(systemPrompt + "\nUser: " + userPrompt);
return extractHtmlCode(response);
}
}
```
For complex tasks, you can enable **tool calling** (e.g., a tool to fetch article metadata, search the web, or even call your own APIs).
### 3.3 Subscription & Rate Limiting
Add a `plan` field to the `User` entity (FREE, PRO, ENTERPRISE). Store monthly generation counters in Redis or a database table.
```java
@Service
public class PlanService {
@Autowired private RedisTemplate<String, Integer> redis;
public boolean hasRemainingGenerations(User user) {
int limit = user.getPlan().getMonthlyGenerations();
int used = redis.opsForValue().get("gen:" + user.getId(), 0);
return used < limit;
}
public void decrementGenerations(User user) {
redis.opsForValue().increment("gen:" + user.getId());
// set expiry to 30 days
}
}
```
### 3.4 Sandboxed Execution (Optional but Recommended)
Before returning the code to the user, you can run it in a **secure Docker container** or **WebAssembly** sandbox to detect obvious errors or malicious patterns.
```java
@Service
public class SandboxRunner {
public String test(String htmlCode) {
// Write htmlCode to a temporary file
// Run headless browser (Puppeteer) inside a container
// Check for console errors, infinite loops, or unsafe calls
// Return null if successful, else error message
}
}
```
---
## 4. Integration with Existing App Store
When the user clicks “Submit to App Store”, the frontend calls the existing `POST /api/plugins` endpoint. You can add a flag `generated_by_ai` to the plugin metadata for analytics.
**No changes needed** in `useAppStore` or `PluginStorePage` – the generated plugin appears like any other after approval.
---
## 5. Subscription Plans & UI
Display the user’s plan and remaining generations in the AI Programmer window. You can also add a “Upgrade” button that opens a payment window (e.g., Stripe Checkout).
```tsx
// hooks/useSubscription.ts
export function useSubscription() {
const { user } = useAuth();
const [plan, setPlan] = useState(user?.plan);
const [remainingGenerations, setRemaining] = useState(0);
useEffect(() => {
fetch('/api/user/subscription').then(res => res.json()).then(data => {
setPlan(data.plan);
setRemaining(data.remainingGenerations);
});
}, [user]);
const consumeGeneration = () => setRemaining(prev => prev - 1);
return { plan, remainingGenerations, consumeGeneration };
}
```
---
## 6. Security & Control
- **Code validation**: The sandbox runner prevents malicious or broken code from reaching users.
- **Rate limiting**: Per‑user, per‑month generation limits based on subscription plan.
- **Manual approval**: For free plans, generated plugins can be set to `approved: false`; premium plans can auto‑approve.
- **Token exposure**: The AI agent uses a backend API key (e.g., OpenAI) – never exposed to the frontend.
---
## 7. Putting It All Together – User Flow
1. **User logs in** (free plan, 5 generations/month).
2. **Opens AI Programmer** from desktop.
3. **Types**: “Create a small app that shows a random motivational quote each time I click a button.”
4. **AI agent** generates an HTML file with a button, a quote element, and a fetch to a quotes API.
5. **Sandbox** runs the code, confirms no errors.
6. **User previews** the widget inside the chat window.
7. **User clicks “Submit to App Store”**. The plugin is saved with status “pending review” (for free plan) or auto‑approved (for pro plan).
8. **Later, after approval**, the plugin appears in the App Store and the user can install it like any other plugin.
9. **User uses up one generation**; remaining counter decreases.
---
## 8. Benefits Over a Manual Plugin Editor
| Feature | Without AI | With AI Agent |
|---------|------------|----------------|
| **Ease of use** | Requires HTML/JS knowledge. | Natural language description. |
| **Speed** | Manual coding takes hours. | Generation in seconds. |
| **Creativity** | Limited to user’s own skills. | AI can suggest novel solutions. |
| **Monetisation** | Hard to price. | Subscription tiers based on usage. |
---
## 9. Conclusion
By adding an AI agent as a desktop app, your platform becomes a **generative development environment** where researchers can produce custom tools through conversation. The agent integrates seamlessly with your existing plugin system and subscription plans, providing a clear upgrade path from free tier to premium. All components – frontend chat interface, backend AI service, sandbox, rate limiting, and App Store integration – are modular and can be built incrementally.
This feature transforms your platform from a passive research environment into an **active co‑creator**, accelerating discovery and tool‑building for every researcher. 🚀
## 🎨 The App Editor – Complete Breakdown of Basic Elements & Appearance
The **App Editor** is the interface where developers (researchers) create and submit new plugins to the App Store. It is designed to be **simple**, **approachable**, and **visually consistent** with the rest of the glass‑morphism desktop environment. Below is an exhaustive explanation of every UI element, its purpose, and how the overall appearance is constructed.
---
## 1. Purpose of the App Editor
The App Editor enables users to turn their HTML/CSS/JS code (or a description for the AI agent, in future versions) into a publishable plugin. It collects essential metadata, validates input, and then submits the plugin to the backend. After approval, the plugin becomes available for all users.
**Key user goals:**
- Provide a **name** and **description** so others understand the plugin.
- Upload or paste the **HTML/JS code**.
- Optionally add an **icon** (base64 image) for visual identity.
- Preview the plugin before submission (optional, but planned).
- Submit the plugin with one click.
---
## 2. Basic UI Elements of the App Editor
The editor is typically presented as a **modal window** (or a dedicated desktop window) that appears when the user clicks a “+” button in the App Store.
### 2.1. Header Bar
| Element | Description | Styling |
|---------|-------------|---------|
| **Title** | “Create New Plugin” or “Submit Tool” | Bold, gradient text, centered or left‑aligned. |
| **Close button** | X icon (lucide‑react `X`) | Circular glass button, hover effect. |
### 2.2. Form Fields
| Field | Input Type | Purpose | Validation |
|-------|------------|---------|-------------|
| **Name** | Text input (single line) | Human‑readable name of the plugin. | Required, max 60 characters. |
| **Description** | Textarea (3‑4 rows) | Short explanation of what the tool does. | Required, max 300 characters. |
| **Icon** | File upload (image) | Optional 64×64 or 128×128 pixel icon (PNG, JPEG, WEBP). Shows preview after upload. | Not required; file size < 1MB. |
| **Code** | Textarea (HTML/JS) | The full HTML code of the plugin (can be pasted or uploaded via file). | Required, must contain at least `<html>` tag. |
| **Execution Mode** (advanced) | Radio group or select | “Local” (runs in iframe) or “Server” (requires backend). | Default: “Local”. Only shown to advanced users. |
### 2.3. Preview Section (Optional)
A collapsible area that displays a live preview of the plugin inside an iframe (same sandbox as `AppRunner`). This allows the developer to test the plugin before submitting.
| Element | Description |
|---------|-------------|
| **Preview button** | Toggles the preview area. |
| **Iframe** | Sandboxed preview of the plugin code. |
### 2.4. Action Buttons
| Button | Action | Styling |
|--------|--------|---------|
| **Cancel** | Closes the editor without saving. | Glass secondary button. |
| **Submit** | Sends the plugin data to the backend. | Gradient primary button (using `btn-primary` class). |
### 2.5. Status/Error Messages
A small area below the form to show:
- Validation errors (e.g., “Name is required”, “Code must not be empty”).
- Submission progress (spinner + “Submitting...”).
- Success message (“Plugin submitted for review”) or error (“Submission failed”).
---
## 3. Visual Appearance & Design Consistency
The App Editor inherits the **glass‑morphism** design system used throughout the platform. All elements are built with Tailwind CSS and custom glass classes.
### 3.1. Base Container
- **Background**: Semi‑transparent with backdrop blur (`glass-card` class).
- **Border**: Light white/cyan border, subtle shadow.
- **Border radius**: `rounded-2xl` (1rem) for a soft, modern look.
- **Padding**: `p-6` to give comfortable spacing.
### 3.2. Form Fields
- **Input backgrounds**: Semi‑transparent white/black depending on dark mode, with `backdrop-blur-sm`.
- **Focus ring**: Primary color (indigo/purple) with `focus:ring-2`.
- **Labels**: Small, semi‑bold, light gray color.
### 3.3. Buttons
- **Primary button (Submit)**: Linear gradient from `primary` to `secondary` (`bg-gradient-to-r from-primary to-secondary`), white text, rounded‑xl, shadow.
- **Secondary button (Cancel)**: Glass background (`bg-white/20`) with hover effect.
### 3.4. Icons
All icons from **Lucide React** (e.g., `Upload`, `Code`, `Image`, `X`). They are sized `w-5 h-5` and aligned with text.
### 3.5. Dark Mode
The entire editor automatically adapts to the user’s dark mode preference:
- Background becomes darker with higher opacity.
- Text becomes lighter.
- Borders become more subtle.
---
## 4. Complete Code Example (Minimal, Yet Fully Functional)
Below is a self‑contained `AppEditor.tsx` component that matches the description. It uses Tailwind CSS and integrates with the `useAppStore` hook.
```tsx
// src/components/app-store/AppEditor.tsx
import { useState } from 'react';
import { useAppStore } from '@/hooks/useAppStore';
import { X, Upload, Code, Image } from 'lucide-react';
import { GlassCard } from '@/components/ui/GlassCard';
interface AppEditorProps {
onClose: () => void;
}
export function AppEditor({ onClose }: AppEditorProps) {
const { submitPlugin, submitting } = useAppStore();
const [name, setName] = useState('');
const [description, setDescription] = useState('');
const [code, setCode] = useState(`<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>My Tool</title></head>
<body style="font-family: system-ui; padding: 1rem;">
<h1>Hello Researcher!</h1>
<p>Edit this code to create your tool.</p>
</body>
</html>`);
const [iconBase64, setIconBase64] = useState('');
const [error, setError] = useState('');
const handleIconUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = (ev) => setIconBase64(ev.target?.result as string);
reader.readAsDataURL(file);
}
};
const handleSubmit = async () => {
if (!name.trim()) {
setError('Plugin name is required');
return;
}
if (!code.trim()) {
setError('Plugin code cannot be empty');
return;
}
const formData = new FormData();
formData.append('name', name.trim());
formData.append('description', description.trim());
formData.append('code', code);
if (iconBase64) formData.append('icon', iconBase64);
formData.append('executionMode', 'local');
setError('');
await submitPlugin(formData);
onClose();
};
return (
<GlassCard className="w-full max-w-2xl p-6 space-y-5">
<div className="flex justify-between items-center">
<h2 className="text-xl font-bold bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
Create New Plugin
</h2>
<button onClick={onClose} className="text-gray-400 hover:text-gray-600">
<X className="w-5 h-5" />
</button>
</div>
<div>
<label className="block text-sm font-medium mb-1">Name *</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
className="w-full px-3 py-2 glass-card rounded-lg focus:outline-none focus:ring-2 focus:ring-primary"
placeholder="e.g., Quick Plotter"
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">Description *</label>
<textarea
rows={3}
value={description}
onChange={(e) => setDescription(e.target.value)}
className="w-full px-3 py-2 glass-card rounded-lg focus:outline-none focus:ring-2 focus:ring-primary"
placeholder="Explain what your tool does..."
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">Icon (optional)</label>
<div className="flex items-center gap-3">
<label className="glass-card px-3 py-2 rounded-lg cursor-pointer flex items-center gap-1">
<Image className="w-4 h-4" /> Upload
<input type="file" accept="image/*" onChange={handleIconUpload} className="hidden" />
</label>
{iconBase64 && <img src={iconBase64} className="w-8 h-8 rounded" alt="icon preview" />}
</div>
</div>
<div>
<label className="block text-sm font-medium mb-1">HTML Code *</label>
<textarea
rows={10}
value={code}
onChange={(e) => setCode(e.target.value)}
className="w-full font-mono text-sm px-3 py-2 glass-card rounded-lg focus:outline-none focus:ring-2 focus:ring-primary"
/>
<div className="flex justify-end mt-1">
<label className="glass-card text-xs px-2 py-1 rounded cursor-pointer">
<Upload className="w-3 h-3 inline mr-1" /> Upload .html
<input type="file" accept=".html" onChange={(e) => {
const file = e.target.files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = (ev) => setCode(ev.target?.result as string);
reader.readAsText(file);
}
}} className="hidden" />
</label>
</div>
</div>
{error && <p className="text-red-500 text-sm">{error}</p>}
<div className="flex gap-3 pt-2">
<button onClick={handleSubmit} disabled={submitting} className="btn-primary flex-1 py-2 rounded-lg flex items-center justify-center gap-2">
{submitting && <div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />}
Submit
</button>
<button onClick={onClose} className="btn-secondary flex-1 py-2 rounded-lg">Cancel</button>
</div>
</GlassCard>
);
}
```
---
## 5. Appearance in the Desktop Context
When the App Editor is opened, it is typically displayed as a **modal** overlay inside the App Store window, or as a separate desktop window (if you prefer). The style is fully consistent with other glass cards:
- **Background**: Translucent white with blur.
- **Borders**: 1px light border, rounded corners.
- **Input fields**: Matte with subtle background.
- **Buttons**: Rounded, gradient primary, glass secondary.
- **Spacing**: Comfortable, using Tailwind’s spacing scale.
The editor respects the user’s **dark mode** preference automatically, adjusting colours and opacities.
---
## 6. Integration Flow with the App Store
1. User clicks **“+”** in `PluginStorePage`.
2. `PluginStorePage` sets a local state `showEditor = true`.
3. The `AppEditor` component is rendered as a modal (using a fixed overlay or inside a `DesktopWindow`).
4. User fills the form, clicks **Submit**.
5. `AppEditor` calls `useAppStore.submitPlugin(formData)`.
6. The hook sends a `POST` request to `/api/plugins`.
7. On success, the editor closes, and the App Store refreshes the list (the new plugin appears after approval).
8. Error messages are shown inline.
The entire experience is **smooth**, **glassy**, and **fast** – exactly matching the desktop environment’s design language.
---
## 7. Future Enhancements
- **Live preview**: A live iframe preview that updates as the user types, helping debug before submission.
- **AI‑assisted filling**: For premium users, an AI agent can auto‑generate name and description from the code.
- **Template library**: Pre‑built templates (chart, form, dashboard) that users can start from.
- **Validation**: Syntax checking and sandbox testing before submission.
All these enhancements can be added without changing the core UI structure.
---
## Conclusion
The App Editor is a **minimal but powerful** tool that empowers researchers to publish their own plugins with ease. Its design is fully integrated with the platform’s glass‑morphism theme, and it seamlessly connects to the existing App Store backend and submission pipeline. By understanding each basic element and its appearance, you can extend the editor with additional features (like previews, templates, or AI assistance) while keeping a consistent, user‑friendly interface. 🎨🚀

Xet Storage Details

Size:
318 kB
·
Xet hash:
8c008c05de4873be6771098aad30d6d78451fa4e2774ad3dd7f3faf6c63eeff0

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.