# Copilot Instructions — Researcher Endorsement & Collaboration Platform (Frontend-Only) Purpose This file is the authoritative project instruction for the frontend-only Researcher Endorsement & Collaboration Platform. It describes the stack, architecture, data model, Zustand store design, component responsibilities, routing, PDF handling, seeding strategy, dev commands, and React 19 considerations so Copilot agents and contributors can scaffold, modify, test, and demo the app without a backend. Overview - Frontend-only React application (React 19) built with Vite and TypeScript (strict mode). - Global state management with Zustand (persist optional). No Redux. No backend or server-side rendering. - Mock data loaded at start from `src/mock/seedData.ts` and used by services and the store. - PDF attachments are stored as in-memory object URLs (URL.createObjectURL) or placeholder URLs in seed data; do not attempt server uploads. Tech Stack - React 19 (functional components only) - Vite (latest) - TypeScript (strict) - Zustand (+ optional middleware: persist, devtools) - React Router v6+ - Tailwind CSS (preferred) or lightweight CSS modules - uuid or crypto.randomUUID for IDs (fallback to Date.now()) Project goals - Let researchers create profiles (specialties) and post updates including attached PDFs. - Allow endorsing users (per-specialty) and endorsing posts. - Entire app runs client-side with realistic mock data, enabling demos and CLI-driven scaffolding. Folder structure (recommended) src/ main.tsx App.tsx routes/ Home.tsx Profile.tsx CreateUser.tsx PostDetail.tsx components/ Navbar.tsx Feed.tsx PostCard.tsx UserCard.tsx EndorseButton.tsx PDFPreview.tsx CreatePostModal.tsx store/ useAppStore.ts types/ User.ts Post.ts mock/ seedData.ts hooks/ useCurrentUser.ts services/ mockApi.ts utils/ fileHelpers.ts Type definitions (examples) // src/types/User.ts export interface User { id: string name: string email: string bio: string specialties: string[] endorsements: Record createdAt: number // Date.now() } // src/types/Post.ts export interface Post { id: string authorId: string content: string attachedPDF?: { name: string url: string } endorsements: number createdAt: number // Date.now() } Zustand store design (src/store/useAppStore.ts) - Use TypeScript generics for the store interface and actions. - State shape: - users: User[] - posts: Post[] - currentUserId: string | null - selectedPostId: string | null - ui: { isCreatePostOpen: boolean } - Actions (signatures): - seedData(): void - createUser(data: Omit): string - setCurrentUser(id: string | null): void - createPost(data: { authorId: string; content: string; file?: File | null }): string - endorseUser(userId: string, specialty: string): void - endorsePost(postId: string): void - attachPDFToPost(postId: string, file: File): void - toggleCreatePost(): void - reset(): void Implementation notes - Always use functional updates to maintain immutability: set((state) => ({ posts: [newPost, ...state.posts] })) - For IDs: use `crypto.randomUUID()` when available, else fallback to `String(Date.now())`. - Use timestamps (numbers) for createdAt to simplify serialization: `Date.now()`. - If using `persist`, be aware object URLs cannot be serialized; persist only primitive fields or placeholder URLs and avoid persisting File or object URL references. PDF handling - When a user attaches a PDF in the CreatePostModal: 1. Validate file type is `application/pdf`; reject others. 2. Create an object URL: `const url = URL.createObjectURL(file)`. 3. Store `{ name: file.name, url }` on the post object in the store. 4. In PDFPreview component, render `