202 pdf annotations#323
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
corates | 258ef54 | Commit Preview URL | Jan 26 2026, 05:52 AM |
📝 WalkthroughWalkthroughAdds end-to-end PDF annotation support and syncing: viewer-side hook and sync manager, Yjs-backed per-project annotation operations, wiring into checklist components, and landing page UI/content updates removing "coming soon" labels and adding workflow copy and cards. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Viewer as EmbedPDF Viewer (Preact)
participant Hook as useAnnotationSync
participant Manager as AnnotationSyncManager
participant Checklist as ChecklistYjsWrapper
participant Ops as AnnotationOps (Yjs)
User->>Viewer: create/update/delete annotation
Viewer->>Hook: emit annotation event
Hook->>Manager: filter & translate event
Manager->>Checklist: invoke onAnnotationAdd/update/delete
Checklist->>Ops: call add/update/deleteAnnotation
Ops->>Ops: persist to Yjs (Y.Map)
Ops-->>Checklist: return status
Checklist-->>User: reflect change in UI
sequenceDiagram
participant Yjs as Yjs Document
participant Sync as buildAnnotationsFromYMap
participant Study as In-memory Study Object
participant Consumer as useProject Consumer
Yjs->>Sync: provide annotations Y.Map
Sync->>Sync: iterate checklists, parse embedPdfData
Sync->>Study: attach parsed annotations per checklist
Study-->>Consumer: return hydrated study.annotations
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧹 Recent nitpick comments
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used📓 Path-based instructions (16)packages/web/src/**/*.{js,jsx,ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)
Files:
packages/web/src/**/*.{jsx,tsx}📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)
Files:
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)
Files:
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)
Files:
**/*.{js,jsx,ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/yjs-sync.mdc)
Files:
packages/web/src/**📄 CodeRabbit inference engine (.cursor/rules/organizations.mdc)
Files:
packages/web/**/*.{js,ts,jsx,tsx}📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Files:
packages/web/**/*.{jsx,tsx}📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Files:
packages/{web,workers}/**/*.{js,ts,jsx,tsx}📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Files:
{packages/web/src/stores/**/*.{js,jsx,ts,tsx},packages/web/src/**/*.{js,jsx,ts,tsx}}📄 CodeRabbit inference engine (.github/instructions/solidjs.instructions.md)
Files:
packages/web/src/**/*.{ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
Files:
**/*.{js,ts,jsx,tsx}📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
Files:
packages/web/src/components/**/*.{ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
Files:
**/*📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
packages/{web,landing}/src/**/*.{ts,tsx}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
packages/**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
🧠 Learnings (7)📓 Common learnings📚 Learning: 2025-12-27T03:02:05.951ZApplied to files:
📚 Learning: 2025-12-27T03:02:05.951ZApplied to files:
📚 Learning: 2025-12-27T03:02:05.951ZApplied to files:
📚 Learning: 2026-01-17T16:10:07.531ZApplied to files:
📚 Learning: 2026-01-17T00:25:35.716ZApplied to files:
📚 Learning: 2025-12-27T03:02:05.951ZApplied to files:
🧬 Code graph analysis (1)packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx (3)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
🔇 Additional comments (5)
✏️ Tip: You can disable this entire section by setting Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx`:
- Around line 154-163: importAnnotations is being called synchronously and
isApplyingRef.current is reset immediately, causing a race with async annotation
events; wrap the call in an async function, await
annotationScope.importAnnotations(...) (or wrap its callback into a Promise if
it doesn't return one), and move isApplyingRef.current = false into a finally
block so it's only cleared after import completes; also add a local
cancelled/isMounted flag and cleanup on unmount to ignore late events (or abort)
so import won't flip the guard after the component unmounts—update the block
around annotationScope.importAnnotations, isApplyingRef, and any surrounding
effect to use async/await with try/finally and cleanup.
In `@packages/web/src/primitives/useProject/annotations.js`:
- Around line 69-79: The function addAnnotation currently documents userId as
required but silently defaults it to 'unknown' when missing; either make userId
truly required by adding it to the existing required-parameter check (alongside
studyId, pdfId, checklistId, annotationData) and return/null-warn when absent,
or update the JSDoc for addAnnotation to mark userId as optional and keep the
fallback behavior—pick one approach and make the validation and JSDoc consistent
for addAnnotation and its callers.
- Around line 287-302: Merged annotations copy embedPdfData from the source but
do not update its internal id to the newly generated newAnnotationId, causing
annotation.id !== annotation.embedPdfData.id; fix this in the merge code that
builds newAnnotationYMap by, when data.embedPdfData exists, creating/using a
copy of embedPdfData and setting its id to newAnnotationId (mirroring the
behavior in addAnnotation) before calling newAnnotationYMap.set('embedPdfData',
...), so newAnnotationId and embedPdfData.id stay in sync.
🧹 Nitpick comments (9)
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx (2)
107-161: Remove debug logging before merging.The extensive
console.logstatements throughoutAnnotationSyncManager(lines 107-111, 120-121, 125, 129, 144, 156-158, 170, 174, 178, 189, 194, 208, 222, 231) are useful for development but should be removed or guarded behind a debug flag before production release.Example cleanup for the load effect
useEffect(() => { - console.log('[AnnotationSync] Load effect triggered:', { - hasAnnotationScope: !!annotationScope, - initialAnnotationsCount: initialAnnotations?.length || 0, - initialAnnotations, - }); if (!annotationScope || !initialAnnotations?.length) { return; } // Filter to only annotations we haven't loaded yet const annotationsToLoad = initialAnnotations.filter(annotation => { if (!annotation.embedPdfData) { - console.log('[AnnotationSync] Skipping annotation without embedPdfData:', annotation); return false; } const annotationId = annotation.id || annotation.embedPdfData.id; const alreadyLoaded = loadedAnnotationIdsRef.current.has(annotationId); - console.log('[AnnotationSync] Annotation:', annotationId, 'alreadyLoaded:', alreadyLoaded); return annotationId && !alreadyLoaded; }); - - console.log('[AnnotationSync] Annotations to load:', annotationsToLoad.length); // ... rest of the function
252-260: Consider exportingAnnotationDatatype for reuse.The
AnnotationDatatype is declared internally but is also used inViewerPageProps.initialAnnotations. If external callers need to construct this type, consider exporting it for better type safety across the annotation system.packages/web/src/primitives/useProject/sync.js (1)
214-224: Consider validating required annotation fields.If
pdfId,type, orpageIndexare missing, the annotation may be unusable downstream. Consider skipping invalid annotations or logging a warning.Optional validation
+ // Skip annotations missing required fields + if (!annotationData.pdfId || annotationData.pageIndex === undefined) { + console.warn('Skipping annotation with missing required fields:', annotationId); + continue; + } + checklistAnnotations.push({ id: annotationData.id || annotationId, pdfId: annotationData.pdfId,packages/web/src/components/checklist/ChecklistYjsWrapper.jsx (1)
415-420: Remove debug logging before merging.Multiple
console.logstatements in the annotation handlers and memo should be removed for production.Lines to remove
const initialAnnotations = createMemo(() => { const study = currentStudy(); const pdfId = selectedPdfId(); const checklistId = params.checklistId; - console.log('[ChecklistYjsWrapper] initialAnnotations memo:', { - hasStudy: !!study, - studyAnnotations: study?.annotations, - pdfId, - checklistId, - }); if (!study?.annotations || !pdfId || !checklistId) return []; // ... - console.log('[ChecklistYjsWrapper] Filtered annotations:', filtered); return filtered; }); const handleAnnotationAdd = annotation => { - console.log('[ChecklistYjsWrapper] handleAnnotationAdd called:', annotation); if (isReadOnly()) { - console.log('[ChecklistYjsWrapper] Read-only mode, skipping'); return; } const pdfId = selectedPdfId(); if (!pdfId) { - console.log('[ChecklistYjsWrapper] No pdfId, skipping'); return; } - - console.log('[ChecklistYjsWrapper] Calling addAnnotation with:', { - studyId: params.studyId, - pdfId, - checklistId: params.checklistId, - annotation, - userId: user()?.id, - }); const result = addAnnotation(params.studyId, pdfId, params.checklistId, annotation, user()?.id); - console.log('[ChecklistYjsWrapper] addAnnotation result:', result); };Also applies to: 433-436, 440-441, 444-452
packages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.js (2)
178-181:isLoadedwill not trigger re-renders.The
isLoadedproperty returnsloadedRef.currentdirectly, which is a plain value at call time. Changes to the ref won't cause consuming components to re-render. If consumers need reactive loaded state, consider usinguseStateinstead:- const loadedRef = useRef(false); + const [isLoaded, setIsLoaded] = useState(false); // Then in loadAnnotations: - loadedRef.current = true; + setIsLoaded(true); // And in reset effect: - loadedRef.current = false; + setIsLoaded(false); // Return: return { loadAnnotations, - isLoaded: loadedRef.current, + isLoaded, };
32-89: Consider consolidating withAnnotationSyncManagerin viewer.tsx.This hook and
AnnotationSyncManager(viewer.tsx lines 69-244) implement very similar logic for:
- Tracking loaded annotations via refs/maps
- Loading initial annotations
- Subscribing to annotation events
- Skipping events during loading
The key difference is that
AnnotationSyncManagerusesimportAnnotations()while this hook usescreateAnnotation(). Consider whether one implementation can serve both purposes to reduce maintenance burden.packages/web/src/primitives/useProject/annotations.js (3)
70-76: Remove debug console.log statements before merging.These verbose debug logs will clutter production console output. Consider removing them or gating behind a debug flag.
Proposed fix
function addAnnotation(studyId, pdfId, checklistId, annotationData, userId) { - console.log('[annotations.js] addAnnotation called:', { - studyId, - pdfId, - checklistId, - annotationData, - userId, - }); if (!studyId || !pdfId || !checklistId || !annotationData) { console.warn('addAnnotation: missing required parameters'); return null; } const checklistAnnotationsMap = getChecklistAnnotationsMap(studyId, checklistId, true); - console.log('[annotations.js] checklistAnnotationsMap:', checklistAnnotationsMap); if (!checklistAnnotationsMap) return null; // ... rest of function ... checklistAnnotationsMap.set(annotationId, annotationYMap); - console.log('[annotations.js] Annotation stored successfully:', annotationId); return annotationId; }Also applies to: 83-83, 103-103
23-23: UnusedprojectIdparameter.The
projectIdparameter is passed but never used within the factory. If intentionally unused, prefix it with_like_isSyncedfor consistency and to signal intent.Proposed fix
-export function createAnnotationOperations(projectId, getYDoc, _isSynced) { +export function createAnnotationOperations(_projectId, getYDoc, _isSynced) {
181-200: Consider extracting annotation parsing logic to reduce duplication.The annotation parsing logic (toJSON conversion, pdfId filtering, embedPdfData parsing) is duplicated between
getAnnotationsandgetAllAnnotationsForPdf. A small helper would improve maintainability.Example helper extraction
/** * Parse a single annotation Y.Map into a plain object * `@private` */ function parseAnnotationYMap(annotationYMap) { const data = annotationYMap.toJSON ? annotationYMap.toJSON() : annotationYMap; let embedPdfData = {}; try { embedPdfData = JSON.parse(data.embedPdfData || '{}'); } catch (err) { console.warn('Failed to parse annotation embedPdfData:', data.id, err); } return { ...data, embedPdfData }; }Then use in both
getAnnotationsandgetAllAnnotationsForPdf:const annotation = parseAnnotationYMap(annotationYMap); if (pdfId && annotation.pdfId !== pdfId) continue; annotations.push(annotation);Also applies to: 218-236
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
packages/landing/src/components/FeatureShowcase.jsxpackages/landing/src/components/HowItWorks.jsxpackages/landing/src/components/SupportedTools.jsxpackages/landing/src/components/resources/ToolResourcePage.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsxpackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/sync.js
🧰 Additional context used
📓 Path-based instructions (17)
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}: NEVER destructure props in SolidJS components - access props directly or wrap in functions to maintain reactivity
Use external stores in packages/web/src/stores/ for shared/cross-feature state instead of prop-drilling
Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components
Use Solid's Show component for conditional rendering instead of ternary operators
Use Solid's For component for rendering lists instead of Array.map()
Use the children helper when manipulating props.children in SolidJS componentsUse Show and For components for conditional and list rendering in SolidJS
Files:
packages/landing/src/components/resources/ToolResourcePage.jsxpackages/landing/src/components/SupportedTools.jsxpackages/landing/src/components/FeatureShowcase.jsxpackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/landing/src/components/HowItWorks.jsxpackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}: Use createSignal for simple reactive values in SolidJS components
Use createStore for complex objects and arrays that need granular reactivity in SolidJS
Use createMemo for computed/derived values that depend on reactive state in SolidJS
Always clean up SolidJS effects that create subscriptions or timers using onCleanup
Import stores directly in components and use store read/write action pattern - read from store, write via actions store
Prefer derived state with createMemo or signals over effects whenever possible
Use local createSignal or createStore for local component state; use external stores for shared/cross-feature state
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}: NEVER destructure props in SolidJS components - it breaks reactivity. Access props directly (e.g., props.name) or wrap in a function (e.g., () => props.name)
Store imports should access store data directly from external stores (packages/web/src/stores/) rather than receiving store data via props
Use createSignal for simple, reactive values in SolidJS
Use createStore for complex objects and nested state in SolidJS, with nested updates using setState pattern (e.g., setState('items', items => [...items, newItem]))
Use createMemo for derived/computed values in SolidJS to maintain reactivity
Use local createSignal or createStore for local component state
Components should receive at most 1-5 props for local configuration only
Move business logic to stores, utilities, or SolidJS primitives rather than keeping it in component code
Files:
packages/landing/src/components/resources/ToolResourcePage.jsxpackages/landing/src/components/SupportedTools.jsxpackages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/landing/src/components/FeatureShowcase.jsxpackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/landing/src/components/HowItWorks.jsxpackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/yjs-sync.mdc)
**/*.{js,jsx,ts,tsx}: Use theuseProjecthook for managing Yjs connections with reference counting instead of creating Y.Doc instances directly
Never create Y.Doc instances directly; always use the connection registry managed by useProject
Access Y.Doc connection state via projectStore.getConnectionState(projectId) instead of checking connection state directly
Read Yjs-synced data from projectStore (using getStudies, getChecklist, etc.) rather than accessing Y.Doc maps/arrays directly
Use operation functions from useProject or projectActionsStore for writing data instead of directly modifying Y.Doc
Don't store Y.Doc references in component state; always retrieve the connection through useProject
Handle connection cleanup via onCleanup() in Solid.js components or equivalent cleanup patterns, calling disconnect() when the component unmounts
Files:
packages/landing/src/components/resources/ToolResourcePage.jsxpackages/landing/src/components/SupportedTools.jsxpackages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/landing/src/components/FeatureShowcase.jsxpackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/landing/src/components/HowItWorks.jsxpackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
**/*.{js,ts,jsx,tsx}: Prefer modern ES6+ syntax and features
Comments should explain why something is being done, not what the code is doing
Reserve comments for explaining intent, context, workarounds, assumptions, edge cases, or limitations
Use TODO(agent): prefix for incomplete work or flagged items with brief description and relevant doc references
Files:
packages/landing/src/components/resources/ToolResourcePage.jsxpackages/landing/src/components/SupportedTools.jsxpackages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/landing/src/components/FeatureShowcase.jsxpackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/landing/src/components/HowItWorks.jsxpackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
**/*
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Never use emojis or unicode symbols anywhere in code, comments, documentation, plan files, commit messages, or examples
Files:
packages/landing/src/components/resources/ToolResourcePage.jsxpackages/landing/src/components/SupportedTools.jsxpackages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/landing/src/components/FeatureShowcase.jsxpackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/landing/src/components/HowItWorks.jsxpackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
packages/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/**/*.{ts,tsx,js,jsx}: Prefer modern ES6+ syntax and features
Prefer config files over hardcoding values
Keep files small, focused, and modular - extract large files into sub-modules or separate utilities
Each file should handle one coherent responsibility
Comments should explain WHY something is being done or provide context, not repeat what the code is saying
Do NOT narrate what code is doing, don't duplicate function/variable names in comments, and don't leave stale comments that contradict the code
Use the Agent TODO convention// TODO(agent): Brief descriptionfor incomplete work, flagging items for future attention, known limitations, and documentation section referencesUse TODO(agent) convention with brief description and relevant doc section references for incomplete work or flagged issues
Files:
packages/landing/src/components/resources/ToolResourcePage.jsxpackages/landing/src/components/SupportedTools.jsxpackages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/landing/src/components/FeatureShowcase.jsxpackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/landing/src/components/HowItWorks.jsxpackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
packages/web/src/**/*.{js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/form-state.mdc)
packages/web/src/**/*.{js,jsx}: Save form state to IndexedDB before initiating OAuth redirects (Google Drive, ORCID) using saveFormState() with form type ('createProject' or 'addStudies') and serializable state only
Only save serializable data to IndexedDB—exclude File objects, ArrayBuffers, functions, and other non-serializable objects from form state persistence
Restore form state after OAuth redirects by checking URL restore params with getRestoreParamsFromUrl(), retrieving saved state with getFormState(), restoring to form, clearing saved state with clearFormState(), and clearing URL params with clearRestoreParamsFromUrl()
For temporary File object storage during OAuth flows (e.g., pending PDFs), use projectStore.setPendingProjectData() instead of IndexedDB, as File objects cannot be serialized
Add restore parameters to the URL after OAuth redirects in the format '?restore=&projectId=' to signal form state restoration on mount
Clear URL restore parameters after form state restoration by calling clearRestoreParamsFromUrl() to prevent stale restoration attempts on subsequent navigation
Form state persistence library functions (saveFormState, getFormState, clearFormState, getRestoreParamsFromUrl, clearRestoreParamsFromUrl) are implemented in packages/web/src/lib/formStatePersistence.js and should be imported from@/lib/formStatePersistence.js
Files:
packages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
packages/web/src/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)
packages/web/src/**/*.{js,jsx,ts,tsx}: Always useuploadPdffrom@api/pdf-api.jsfor uploading PDF files. Pass object with projectId, studyId, tag ('primary' or 'supplementary'), and fileName
Validate PDF files on frontend by checking file.type includes 'pdf' and file.size is within MAX_PDF_SIZE limit (full validation is done on backend)
UsecachePdfandgetCachedPdffrom@primitives/pdfCache.jsfor caching PDF data in IndexedDB
Implement PDF caching strategy: check cache first, download from server if not cached, then cache the downloaded PDF
Store only PDF metadata in Yjs (id, name, size, tag, uploadedAt, uploadedBy), never store PDF binary data in Yjs as it is too large
UseimportFromGoogleDrivefrom@api/google-drive.jsfor importing PDFs from Google Drive. Pass fileId, projectId, studyId, and tag
Save form state usingsaveFormStatefrom@/lib/formStatePersistence.jsbefore triggering OAuth redirects for Google Drive
UseaddPdfToStudyoperation fromuseProjecthook to add PDFs to a study, passing id, name, size, tag, uploadedAt, and uploadedBy
UseremovePdfFromStudyoperation fromuseProjecthook to remove PDFs from a study
UsepdfPreviewStorefrom@/stores/pdfPreviewStore.jsfor managing PDF preview state (openPreview, closePreview, getPreview methods)
UsedownloadPdffrom@api/pdf-api.jsto download PDFs from server, then cache the result usingcachePdf
Always cache PDFs after download and check cache before downloading to avoid redundant downloads
Use PDF operations fromuseProjecthook instead of bypassing through direct API calls
Files:
packages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
packages/web/src/**
📄 CodeRabbit inference engine (.cursor/rules/organizations.mdc)
packages/web/src/**: Use human-readable slug in frontend URLs: /orgs/:orgSlug/...
Use orgId (UUID) for API calls, not orgSlug, when making fetch requests to backend endpoints
Files:
packages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
packages/web/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
packages/web/**/*.{js,ts,jsx,tsx}: UseapiFetchfor all frontend API calls instead of raw fetch to automatically handle JSON parsing, errors, and toast notifications
UsehandleFetchErrorfor wrapping legacy raw fetch calls in frontend code (legacy pattern, prefer apiFetch)
Use error utility functions likeisErrorCodefrom error-utils to check specific error types instead of direct string comparisons
Files:
packages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
packages/{web,workers}/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Never throw string literals; always throw Error objects or return domain errors from API routes
Files:
packages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
{packages/web/src/stores/**/*.{js,jsx,ts,tsx},packages/web/src/**/*.{js,jsx,ts,tsx}}
📄 CodeRabbit inference engine (.github/instructions/solidjs.instructions.md)
Shared or cross-feature state should use external stores located in packages/web/src/stores/
Files:
packages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
packages/web/src/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)
Use
PdfViewercomponent from@/components/checklist-ui/pdf/PdfViewer.jsxfor displaying PDFs, passing pdfData as ArrayBuffer, fileName, readOnly, and onPageChange
Files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
packages/web/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Use
createFormErrorSignalsfor form error handling in frontend forms to manage field-level and global error states
Files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
packages/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
packages/web/src/**/*.{ts,tsx}: For UI icons, usesolid-iconslibrary or SVGs only (never emojis)
Use import aliases from jsconfig.json as defined for the project
Use Ark UI component library (@ark-ui/solid) for UI components
Usesolid-iconslibrary for icons (e.g.,solid-icons/bi,solid-icons/fi)
Do not prop-drill application state in SolidJS components; import stores directly where needed
Do not destructure props in SolidJS; accessprops.fielddirectly or wrap in a function:() => props.field
Components should receive at most 1-5 props (local config only, not shared state)
UsecreateMemofor derived values in SolidJS
Frontend uses orgSlug in URLs (/orgs/:orgSlug/...) for readability
Never destructure SolidJS props as it breaks reactivity
Never prop-drill shared state; import stores directlyUse import aliases from jsconfig.json as defined in the project configuration
packages/web/src/**/*.{ts,tsx}: Import stores directly and never prop-drill application state in SolidJS components
Never destructure SolidJS props - useprops.fieldor() => props.fieldto preserve reactivity
Files:
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
packages/web/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
Group related components in subdirectories with barrel exports
Files:
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
packages/{web,landing}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/{web,landing}/src/**/*.{ts,tsx}: For UI icons, usesolid-iconslibrary (e.g.,solid-icons/bi,solid-icons/fi) or SVGs only, never emojis
Ensure browser compatibility, with particular attention to Safari
Group related components in subdirectories with barrel exports
Use Ark UI components from@ark-ui/solidfor UI components
Usesolid-iconsicon library for all icon needs
Do NOT prop-drill application state in SolidJS - import stores directly where needed
Do NOT destructure SolidJS props - accessprops.fielddirectly or wrap in function:() => props.field
SolidJS components should receive at most 1-5 props (local config only, not shared state)
UsecreateStorefor complex state objects in SolidJS
UsecreateMemofor derived values in SolidJS
Move business logic to stores, utilities, or primitives - not components
Never destructure SolidJS props as it breaks reactivity
Never prop-drill shared state - import stores directly
Files:
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
🧠 Learnings (45)
📓 Common learnings
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/primitives/useProject/checklists.js : Store question notes as Y.Text objects obtained from useProject hook via getQuestionNote operation to enable collaborative editing
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{jsx,tsx} : Use `PdfViewer` component from `@/components/checklist-ui/pdf/PdfViewer.jsx` for displaying PDFs, passing pdfData as ArrayBuffer, fileName, readOnly, and onPageChange
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Use `addPdfToStudy` operation from `useProject` hook to add PDFs to a study, passing id, name, size, tag, uploadedAt, and uploadedBy
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/** : Use scoreChecklist utility from `@/AMSTAR2/checklist.js` to determine quality assessment rating: 'High' | 'Moderate' | 'Low' | 'Critically Low'
Applied to files:
packages/landing/src/components/resources/ToolResourcePage.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/ROBINS-I/** : Use scoreChecklist utility from `@/ROBINS-I/checklist.js` to determine risk of bias rating: 'Low' | 'Moderate' | 'Serious' | 'Critical'
Applied to files:
packages/landing/src/components/resources/ToolResourcePage.jsx
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Use PDF operations from `useProject` hook instead of bypassing through direct API calls
Applied to files:
packages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Use `pdfPreviewStore` from `@/stores/pdfPreviewStore.js` for managing PDF preview state (openPreview, closePreview, getPreview methods)
Applied to files:
packages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{jsx,tsx} : Use `PdfViewer` component from `@/components/checklist-ui/pdf/PdfViewer.jsx` for displaying PDFs, passing pdfData as ArrayBuffer, fileName, readOnly, and onPageChange
Applied to files:
packages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/landing/src/components/HowItWorks.jsxpackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Use `addPdfToStudy` operation from `useProject` hook to add PDFs to a study, passing id, name, size, tag, uploadedAt, and uploadedBy
Applied to files:
packages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.jspackages/landing/src/components/FeatureShowcase.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to packages/web/src/components/checklist-ui/compare/** : Use Y.Text objects for collaborative editing of question notes in reconciliation
Applied to files:
packages/landing/src/components/FeatureShowcase.jsxpackages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/sync.jspackages/landing/src/components/HowItWorks.jsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : NEVER destructure props in SolidJS components - access props directly or wrap in functions to maintain reactivity
Applied to files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsx
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Use `cachePdf` and `getCachedPdf` from `primitives/pdfCache.js` for caching PDF data in IndexedDB
Applied to files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsxpackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
📚 Learning: 2026-01-17T16:09:36.920Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.920Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Do NOT destructure SolidJS props - access `props.field` directly or wrap in function: `() => props.field`
Applied to files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsx
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Store only PDF metadata in Yjs (id, name, size, tag, uploadedAt, uploadedBy), never store PDF binary data in Yjs as it is too large
Applied to files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsx
📚 Learning: 2026-01-17T16:09:36.920Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.920Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Never destructure SolidJS props as it breaks reactivity
Applied to files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsx
📚 Learning: 2026-01-17T16:10:07.531Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-17T16:10:07.531Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Never destructure SolidJS props - use `props.field` or `() => props.field` to preserve reactivity
Applied to files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
Applied to files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Always clean up SolidJS effects that create subscriptions or timers using onCleanup
Applied to files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsx
📚 Learning: 2025-12-27T03:02:50.087Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/yjs-sync.mdc:0-0
Timestamp: 2025-12-27T03:02:50.087Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Handle connection cleanup via onCleanup() in Solid.js components or equivalent cleanup patterns, calling disconnect() when the component unmounts
Applied to files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsx
📚 Learning: 2026-01-17T00:25:12.518Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.518Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createMemo for derived/computed values in SolidJS to maintain reactivity
Applied to files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createMemo for computed/derived values that depend on reactive state in SolidJS
Applied to files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsx
📚 Learning: 2026-01-17T16:09:36.920Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.920Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use `createMemo` for derived values in SolidJS
Applied to files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsx
📚 Learning: 2026-01-17T00:25:12.518Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.518Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : NEVER destructure props in SolidJS components - it breaks reactivity. Access props directly (e.g., props.name) or wrap in a function (e.g., () => props.name)
Applied to files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createStore for complex objects and arrays that need granular reactivity in SolidJS
Applied to files:
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/primitives/useProject/checklists.js : Store question notes as Y.Text objects obtained from useProject hook via getQuestionNote operation to enable collaborative editing
Applied to files:
packages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js,packages/web/src/primitives/useProject/checklists.js : Use checklist operations from useProject hook (createChecklist, updateChecklistAnswer, getChecklistData) instead of manually updating checklist structure
Applied to files:
packages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/landing/src/components/HowItWorks.jsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/AMSTAR2/checklist-compare.js} : Use compareChecklists utility from checklist-compare.js for comparing reviewer checklists
Applied to files:
packages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/primitives/useProject/index.jspackages/landing/src/components/HowItWorks.jsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/** : Use NoteEditor component from `@/components/checklist-ui/common/NoteEditor.jsx` for question note editing with max 2000 character limit
Applied to files:
packages/web/src/components/checklist/ChecklistWithPdf.jsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
📚 Learning: 2025-12-27T03:02:50.087Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/yjs-sync.mdc:0-0
Timestamp: 2025-12-27T03:02:50.087Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use operation functions from useProject or projectActionsStore for writing data instead of directly modifying Y.Doc
Applied to files:
packages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Use `removePdfFromStudy` operation from `useProject` hook to remove PDFs from a study
Applied to files:
packages/web/src/primitives/useProject/index.jspackages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
📚 Learning: 2025-12-27T03:02:50.087Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/yjs-sync.mdc:0-0
Timestamp: 2025-12-27T03:02:50.087Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use the `useProject` hook for managing Yjs connections with reference counting instead of creating Y.Doc instances directly
Applied to files:
packages/web/src/primitives/useProject/index.js
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Use getChecklistStatus utility from `@/lib/checklist-domain.js` to determine current checklist status before performing operations
Applied to files:
packages/web/src/primitives/useProject/index.jspackages/web/src/components/checklist/ChecklistYjsWrapper.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/lib/checklist-domain.js : Register and retrieve checklists using checklist-registry: getChecklistType and getChecklistComponent functions
Applied to files:
packages/web/src/primitives/useProject/index.js
📚 Learning: 2025-12-27T03:02:50.087Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/yjs-sync.mdc:0-0
Timestamp: 2025-12-27T03:02:50.087Z
Learning: Applies to packages/workers/src/durable-objects/ProjectDoc.js, packages/web/src/primitives/useProject/** : Y.Doc structure in ProjectDoc follows a specific hierarchy: meta (Map), members (Map), reviews (Map containing studies with checklists, pdfs, and reconciliation)
Applied to files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.js
📚 Learning: 2025-12-27T03:01:35.601Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/durable-objects.mdc:0-0
Timestamp: 2025-12-27T03:01:35.601Z
Learning: Applies to packages/workers/src/durable-objects/**/ProjectDoc.{js,ts} : Structure ProjectDoc Y.Doc with meta (Map), members (Map), and reviews (Map) containing checklists (Map), pdfs (Array), and reconciliation (Map)
Applied to files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.js
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Always use `uploadPdf` from `api/pdf-api.js` for uploading PDF files. Pass object with projectId, studyId, tag ('primary' or 'supplementary'), and fileName
Applied to files:
packages/web/src/primitives/useProject/annotations.js
📚 Learning: 2025-12-27T03:02:50.087Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/yjs-sync.mdc:0-0
Timestamp: 2025-12-27T03:02:50.087Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Read Yjs-synced data from projectStore (using getStudies, getChecklist, etc.) rather than accessing Y.Doc maps/arrays directly
Applied to files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/primitives/useProject/sync.js
📚 Learning: 2025-12-27T03:02:50.087Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/yjs-sync.mdc:0-0
Timestamp: 2025-12-27T03:02:50.087Z
Learning: Applies to packages/web/src/primitives/useProject/**, packages/web/src/stores/projectStore.js : Never manually call syncFromYDoc() - sync from Y.Doc to store is handled automatically via ydoc.on('update')
Applied to files:
packages/web/src/primitives/useProject/sync.js
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/lib/checklist-domain.js} : Store reconciliation progress metadata (IDs and optional currentPage) in the study's Y.Map reconciliation property
Applied to files:
packages/web/src/primitives/useProject/sync.js
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Checklist status transitions follow sequence: in_progress → completed (when all questions answered) → reconciled (after reconciliation complete)
Applied to files:
packages/landing/src/components/HowItWorks.jsx
📚 Learning: 2026-01-17T16:09:36.920Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.920Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use `solid-icons` icon library for all icon needs
Applied to files:
packages/landing/src/components/HowItWorks.jsx
📚 Learning: 2026-01-17T00:25:12.518Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.518Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use Show and For components for conditional and list rendering in SolidJS
Applied to files:
packages/landing/src/components/HowItWorks.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use Solid's For component for rendering lists instead of Array.map()
Applied to files:
packages/landing/src/components/HowItWorks.jsx
📚 Learning: 2026-01-17T00:25:35.716Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.716Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Use `solid-icons` library for icons (e.g., `solid-icons/bi`, `solid-icons/fi`)
Applied to files:
packages/landing/src/components/HowItWorks.jsx
📚 Learning: 2026-01-17T16:09:36.920Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.920Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : For UI icons, use `solid-icons` library (e.g., `solid-icons/bi`, `solid-icons/fi`) or SVGs only, never emojis
Applied to files:
packages/landing/src/components/HowItWorks.jsx
📚 Learning: 2026-01-17T16:09:36.920Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.920Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use Ark UI components from `ark-ui/solid` for UI components
Applied to files:
packages/landing/src/components/HowItWorks.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/lib/checklist-domain.js,packages/web/src/AMSTAR2/checklist-compare.js} : Store final answers in the reconciled checklist itself, not in reconciliation progress metadata
Applied to files:
packages/web/src/components/checklist/ChecklistYjsWrapper.jsx
🧬 Code graph analysis (4)
packages/web/src/components/pdf/embedpdf/EmbedPdfViewer.jsx (2)
packages/web/src/components/checklist/ChecklistYjsWrapper.jsx (2)
pdfData(51-51)selectedPdfId(54-54)packages/web/src/primitives/useProject/sync.js (1)
pdfData(141-141)
packages/web/src/primitives/useProject/index.js (1)
packages/web/src/primitives/useProject/annotations.js (1)
createAnnotationOperations(23-321)
packages/web/src/primitives/useProject/annotations.js (3)
packages/web/src/primitives/useProject/index.js (1)
getYDoc(159-159)packages/workers/src/durable-objects/__tests__/ProjectDoc.test.js (2)
studiesMap(25-25)studyYMap(35-35)packages/web/src/primitives/useProject/sync.js (3)
annotationsMap(178-178)annotationData(204-204)annotations(193-193)
packages/web/src/primitives/useProject/sync.js (1)
packages/workers/src/durable-objects/__tests__/ProjectDoc.test.js (1)
studyYMap(35-35)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Workers Builds: corates
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx`:
- Around line 192-207: The event handler in viewer.tsx uses event.annotation.id
(annotationId) without checking for existence, which can write undefined into
annotationMapRef.current and call callbacks with an invalid ID; update the
'create' case to guard early: verify annotation and annotationId are present (if
not, log a warning and return), only then call
annotationMapRef.current.set(annotationId, annotation) and invoke
onAnnotationAdd/onAnnotationChange/onAnnotationDelete using the validated
annotationId so no undefined keys or callback payloads are produced.
In `@packages/web/src/primitives/useProject/annotations.js`:
- Around line 296-304: The merge logic for updating embedPdfData can throw when
JSON.parse fails, which would abort the Yjs merge; wrap the parse in a try/catch
inside the block that checks data.embedPdfData (the code that currently computes
parsed and updatedEmbed) and on parse error fall back to using data.embedPdfData
as-is or skip setting embedPdfData on newAnnotationYMap (i.e., avoid calling
newAnnotationYMap.set with a malformed JSON string), and optionally record the
parse error via your existing logging mechanism; ensure this change touches the
block referencing embedPdfData, parsed, updatedEmbed, newAnnotationId and
newAnnotationYMap.set so bad JSON no longer aborts the merge.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsxpackages/web/src/primitives/useProject/annotations.js
🧰 Additional context used
📓 Path-based instructions (17)
packages/web/src/**/*.{js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/form-state.mdc)
packages/web/src/**/*.{js,jsx}: Save form state to IndexedDB before initiating OAuth redirects (Google Drive, ORCID) using saveFormState() with form type ('createProject' or 'addStudies') and serializable state only
Only save serializable data to IndexedDB—exclude File objects, ArrayBuffers, functions, and other non-serializable objects from form state persistence
Restore form state after OAuth redirects by checking URL restore params with getRestoreParamsFromUrl(), retrieving saved state with getFormState(), restoring to form, clearing saved state with clearFormState(), and clearing URL params with clearRestoreParamsFromUrl()
For temporary File object storage during OAuth flows (e.g., pending PDFs), use projectStore.setPendingProjectData() instead of IndexedDB, as File objects cannot be serialized
Add restore parameters to the URL after OAuth redirects in the format '?restore=&projectId=' to signal form state restoration on mount
Clear URL restore parameters after form state restoration by calling clearRestoreParamsFromUrl() to prevent stale restoration attempts on subsequent navigation
Form state persistence library functions (saveFormState, getFormState, clearFormState, getRestoreParamsFromUrl, clearRestoreParamsFromUrl) are implemented in packages/web/src/lib/formStatePersistence.js and should be imported from@/lib/formStatePersistence.js
Files:
packages/web/src/primitives/useProject/annotations.js
packages/web/src/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)
packages/web/src/**/*.{js,jsx,ts,tsx}: Always useuploadPdffrom@api/pdf-api.jsfor uploading PDF files. Pass object with projectId, studyId, tag ('primary' or 'supplementary'), and fileName
Validate PDF files on frontend by checking file.type includes 'pdf' and file.size is within MAX_PDF_SIZE limit (full validation is done on backend)
UsecachePdfandgetCachedPdffrom@primitives/pdfCache.jsfor caching PDF data in IndexedDB
Implement PDF caching strategy: check cache first, download from server if not cached, then cache the downloaded PDF
Store only PDF metadata in Yjs (id, name, size, tag, uploadedAt, uploadedBy), never store PDF binary data in Yjs as it is too large
UseimportFromGoogleDrivefrom@api/google-drive.jsfor importing PDFs from Google Drive. Pass fileId, projectId, studyId, and tag
Save form state usingsaveFormStatefrom@/lib/formStatePersistence.jsbefore triggering OAuth redirects for Google Drive
UseaddPdfToStudyoperation fromuseProjecthook to add PDFs to a study, passing id, name, size, tag, uploadedAt, and uploadedBy
UseremovePdfFromStudyoperation fromuseProjecthook to remove PDFs from a study
UsepdfPreviewStorefrom@/stores/pdfPreviewStore.jsfor managing PDF preview state (openPreview, closePreview, getPreview methods)
UsedownloadPdffrom@api/pdf-api.jsto download PDFs from server, then cache the result usingcachePdf
Always cache PDFs after download and check cache before downloading to avoid redundant downloads
Use PDF operations fromuseProjecthook instead of bypassing through direct API calls
Files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}: Use createSignal for simple reactive values in SolidJS components
Use createStore for complex objects and arrays that need granular reactivity in SolidJS
Use createMemo for computed/derived values that depend on reactive state in SolidJS
Always clean up SolidJS effects that create subscriptions or timers using onCleanup
Import stores directly in components and use store read/write action pattern - read from store, write via actions store
Prefer derived state with createMemo or signals over effects whenever possible
Use local createSignal or createStore for local component state; use external stores for shared/cross-feature state
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}: NEVER destructure props in SolidJS components - it breaks reactivity. Access props directly (e.g., props.name) or wrap in a function (e.g., () => props.name)
Store imports should access store data directly from external stores (packages/web/src/stores/) rather than receiving store data via props
Use createSignal for simple, reactive values in SolidJS
Use createStore for complex objects and nested state in SolidJS, with nested updates using setState pattern (e.g., setState('items', items => [...items, newItem]))
Use createMemo for derived/computed values in SolidJS to maintain reactivity
Use local createSignal or createStore for local component state
Components should receive at most 1-5 props for local configuration only
Move business logic to stores, utilities, or SolidJS primitives rather than keeping it in component code
Files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/yjs-sync.mdc)
**/*.{js,jsx,ts,tsx}: Use theuseProjecthook for managing Yjs connections with reference counting instead of creating Y.Doc instances directly
Never create Y.Doc instances directly; always use the connection registry managed by useProject
Access Y.Doc connection state via projectStore.getConnectionState(projectId) instead of checking connection state directly
Read Yjs-synced data from projectStore (using getStudies, getChecklist, etc.) rather than accessing Y.Doc maps/arrays directly
Use operation functions from useProject or projectActionsStore for writing data instead of directly modifying Y.Doc
Don't store Y.Doc references in component state; always retrieve the connection through useProject
Handle connection cleanup via onCleanup() in Solid.js components or equivalent cleanup patterns, calling disconnect() when the component unmounts
Files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
packages/web/src/**
📄 CodeRabbit inference engine (.cursor/rules/organizations.mdc)
packages/web/src/**: Use human-readable slug in frontend URLs: /orgs/:orgSlug/...
Use orgId (UUID) for API calls, not orgSlug, when making fetch requests to backend endpoints
Files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
packages/web/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
packages/web/**/*.{js,ts,jsx,tsx}: UseapiFetchfor all frontend API calls instead of raw fetch to automatically handle JSON parsing, errors, and toast notifications
UsehandleFetchErrorfor wrapping legacy raw fetch calls in frontend code (legacy pattern, prefer apiFetch)
Use error utility functions likeisErrorCodefrom error-utils to check specific error types instead of direct string comparisons
Files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
packages/{web,workers}/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Never throw string literals; always throw Error objects or return domain errors from API routes
Files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
{packages/web/src/stores/**/*.{js,jsx,ts,tsx},packages/web/src/**/*.{js,jsx,ts,tsx}}
📄 CodeRabbit inference engine (.github/instructions/solidjs.instructions.md)
Shared or cross-feature state should use external stores located in packages/web/src/stores/
Files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
**/*.{js,ts,jsx,tsx}: Prefer modern ES6+ syntax and features
Comments should explain why something is being done, not what the code is doing
Reserve comments for explaining intent, context, workarounds, assumptions, edge cases, or limitations
Use TODO(agent): prefix for incomplete work or flagged items with brief description and relevant doc references
Files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
**/*
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Never use emojis or unicode symbols anywhere in code, comments, documentation, plan files, commit messages, or examples
Files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
packages/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/**/*.{ts,tsx,js,jsx}: Prefer modern ES6+ syntax and features
Prefer config files over hardcoding values
Keep files small, focused, and modular - extract large files into sub-modules or separate utilities
Each file should handle one coherent responsibility
Comments should explain WHY something is being done or provide context, not repeat what the code is saying
Do NOT narrate what code is doing, don't duplicate function/variable names in comments, and don't leave stale comments that contradict the code
Use the Agent TODO convention// TODO(agent): Brief descriptionfor incomplete work, flagging items for future attention, known limitations, and documentation section referencesUse TODO(agent) convention with brief description and relevant doc section references for incomplete work or flagged issues
Files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
packages/web/src/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)
Use
PdfViewercomponent from@/components/checklist-ui/pdf/PdfViewer.jsxfor displaying PDFs, passing pdfData as ArrayBuffer, fileName, readOnly, and onPageChange
Files:
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}: NEVER destructure props in SolidJS components - access props directly or wrap in functions to maintain reactivity
Use external stores in packages/web/src/stores/ for shared/cross-feature state instead of prop-drilling
Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components
Use Solid's Show component for conditional rendering instead of ternary operators
Use Solid's For component for rendering lists instead of Array.map()
Use the children helper when manipulating props.children in SolidJS componentsUse Show and For components for conditional and list rendering in SolidJS
Files:
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
packages/web/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Use
createFormErrorSignalsfor form error handling in frontend forms to manage field-level and global error states
Files:
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
packages/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
packages/web/src/**/*.{ts,tsx}: For UI icons, usesolid-iconslibrary or SVGs only (never emojis)
Use import aliases from jsconfig.json as defined for the project
Use Ark UI component library (@ark-ui/solid) for UI components
Usesolid-iconslibrary for icons (e.g.,solid-icons/bi,solid-icons/fi)
Do not prop-drill application state in SolidJS components; import stores directly where needed
Do not destructure props in SolidJS; accessprops.fielddirectly or wrap in a function:() => props.field
Components should receive at most 1-5 props (local config only, not shared state)
UsecreateMemofor derived values in SolidJS
Frontend uses orgSlug in URLs (/orgs/:orgSlug/...) for readability
Never destructure SolidJS props as it breaks reactivity
Never prop-drill shared state; import stores directlyUse import aliases from jsconfig.json as defined in the project configuration
packages/web/src/**/*.{ts,tsx}: Import stores directly and never prop-drill application state in SolidJS components
Never destructure SolidJS props - useprops.fieldor() => props.fieldto preserve reactivity
Files:
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
packages/web/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
Group related components in subdirectories with barrel exports
Files:
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
packages/{web,landing}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/{web,landing}/src/**/*.{ts,tsx}: For UI icons, usesolid-iconslibrary (e.g.,solid-icons/bi,solid-icons/fi) or SVGs only, never emojis
Ensure browser compatibility, with particular attention to Safari
Group related components in subdirectories with barrel exports
Use Ark UI components from@ark-ui/solidfor UI components
Usesolid-iconsicon library for all icon needs
Do NOT prop-drill application state in SolidJS - import stores directly where needed
Do NOT destructure SolidJS props - accessprops.fielddirectly or wrap in function:() => props.field
SolidJS components should receive at most 1-5 props (local config only, not shared state)
UsecreateStorefor complex state objects in SolidJS
UsecreateMemofor derived values in SolidJS
Move business logic to stores, utilities, or primitives - not components
Never destructure SolidJS props as it breaks reactivity
Never prop-drill shared state - import stores directly
Files:
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
🧠 Learnings (19)
📓 Common learnings
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{jsx,tsx} : Use `PdfViewer` component from `@/components/checklist-ui/pdf/PdfViewer.jsx` for displaying PDFs, passing pdfData as ArrayBuffer, fileName, readOnly, and onPageChange
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/primitives/useProject/checklists.js : Store question notes as Y.Text objects obtained from useProject hook via getQuestionNote operation to enable collaborative editing
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to packages/web/src/components/checklist-ui/compare/** : Use Y.Text objects for collaborative editing of question notes in reconciliation
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Use `addPdfToStudy` operation from `useProject` hook to add PDFs to a study, passing id, name, size, tag, uploadedAt, and uploadedBy
Applied to files:
packages/web/src/primitives/useProject/annotations.js
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Use `removePdfFromStudy` operation from `useProject` hook to remove PDFs from a study
Applied to files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/primitives/useProject/checklists.js : Store question notes as Y.Text objects obtained from useProject hook via getQuestionNote operation to enable collaborative editing
Applied to files:
packages/web/src/primitives/useProject/annotations.js
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Use PDF operations from `useProject` hook instead of bypassing through direct API calls
Applied to files:
packages/web/src/primitives/useProject/annotations.jspackages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
📚 Learning: 2025-12-27T03:02:50.087Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/yjs-sync.mdc:0-0
Timestamp: 2025-12-27T03:02:50.087Z
Learning: Applies to packages/workers/src/durable-objects/ProjectDoc.js, packages/web/src/primitives/useProject/** : Y.Doc structure in ProjectDoc follows a specific hierarchy: meta (Map), members (Map), reviews (Map containing studies with checklists, pdfs, and reconciliation)
Applied to files:
packages/web/src/primitives/useProject/annotations.js
📚 Learning: 2025-12-27T03:01:35.601Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/durable-objects.mdc:0-0
Timestamp: 2025-12-27T03:01:35.601Z
Learning: Applies to packages/workers/src/durable-objects/**/ProjectDoc.{js,ts} : Structure ProjectDoc Y.Doc with meta (Map), members (Map), and reviews (Map) containing checklists (Map), pdfs (Array), and reconciliation (Map)
Applied to files:
packages/web/src/primitives/useProject/annotations.js
📚 Learning: 2025-12-27T03:02:50.087Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/yjs-sync.mdc:0-0
Timestamp: 2025-12-27T03:02:50.087Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use operation functions from useProject or projectActionsStore for writing data instead of directly modifying Y.Doc
Applied to files:
packages/web/src/primitives/useProject/annotations.js
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js,packages/web/src/primitives/useProject/checklists.js : Use checklist operations from useProject hook (createChecklist, updateChecklistAnswer, getChecklistData) instead of manually updating checklist structure
Applied to files:
packages/web/src/primitives/useProject/annotations.js
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Always use `uploadPdf` from `api/pdf-api.js` for uploading PDF files. Pass object with projectId, studyId, tag ('primary' or 'supplementary'), and fileName
Applied to files:
packages/web/src/primitives/useProject/annotations.js
📚 Learning: 2025-12-27T03:02:50.087Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/yjs-sync.mdc:0-0
Timestamp: 2025-12-27T03:02:50.087Z
Learning: Applies to packages/web/src/primitives/useProject/**, packages/web/src/stores/projectStore.js : Never manually call syncFromYDoc() - sync from Y.Doc to store is handled automatically via ydoc.on('update')
Applied to files:
packages/web/src/primitives/useProject/annotations.js
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/lib/checklist-domain.js,packages/web/src/AMSTAR2/checklist-compare.js} : Reconciliation structure should contain checklist1Id, checklist2Id, and reconciledChecklistId
Applied to files:
packages/web/src/primitives/useProject/annotations.js
📚 Learning: 2025-12-27T03:02:50.087Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/yjs-sync.mdc:0-0
Timestamp: 2025-12-27T03:02:50.087Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Read Yjs-synced data from projectStore (using getStudies, getChecklist, etc.) rather than accessing Y.Doc maps/arrays directly
Applied to files:
packages/web/src/primitives/useProject/annotations.js
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/lib/checklist-domain.js} : Store reconciliation progress metadata (IDs and optional currentPage) in the study's Y.Map reconciliation property
Applied to files:
packages/web/src/primitives/useProject/annotations.js
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{jsx,tsx} : Use `PdfViewer` component from `@/components/checklist-ui/pdf/PdfViewer.jsx` for displaying PDFs, passing pdfData as ArrayBuffer, fileName, readOnly, and onPageChange
Applied to files:
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Use `pdfPreviewStore` from `@/stores/pdfPreviewStore.js` for managing PDF preview state (openPreview, closePreview, getPreview methods)
Applied to files:
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Use `cachePdf` and `getCachedPdf` from `primitives/pdfCache.js` for caching PDF data in IndexedDB
Applied to files:
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
📚 Learning: 2026-01-17T16:10:07.531Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-17T16:10:07.531Z
Learning: Applies to packages/**/*.{ts,tsx,js,jsx} : Use TODO(agent) convention with brief description and relevant doc section references for incomplete work or flagged issues
Applied to files:
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
📚 Learning: 2026-01-17T00:25:35.716Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.716Z
Learning: Applies to **/*.{js,ts,jsx,tsx} : Use TODO(agent): prefix for incomplete work or flagged items with brief description and relevant doc references
Applied to files:
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx
🧬 Code graph analysis (1)
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx (2)
packages/web/src/components/pdf/embedpdf/preact/src/hooks/useAnnotationSync.js (4)
annotationCapability(41-41)isApplyingRef(43-43)annotationMapRef(44-44)annotationScope(47-47)packages/web/src/components/pdf/embedpdf/preact/src/config/types.ts (1)
SidebarState(38-41)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Workers Builds: corates
🔇 Additional comments (3)
packages/web/src/components/pdf/embedpdf/preact/src/viewer.tsx (2)
349-352: Annotation plugin registration aligns with external persistence.Disabling auto-commit is consistent with persisting annotations to Y.js rather than mutating the PDF file.
538-552: Good gating for AnnotationSyncManager.Conditionally mounting only when a document is active and annotation hooks are present avoids unnecessary subscriptions.
packages/web/src/primitives/useProject/annotations.js (1)
93-97: Embed data id normalization on creation is solid.This keeps stored
embedPdfDataaligned with the generated annotation ID.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
Summary by CodeRabbit
New Features
Improvements
Content
✏️ Tip: You can customize this high-level summary in your review settings.