Skip to content

feat: notion-like document management with novel.sh editor#1

Open
Utkarshbhimte wants to merge 4 commits intostagingfrom
feat/documents
Open

feat: notion-like document management with novel.sh editor#1
Utkarshbhimte wants to merge 4 commits intostagingfrom
feat/documents

Conversation

@Utkarshbhimte
Copy link
Collaborator

What

Adds a full document management system to Paperclip — notion-style docs that link to projects, goals, and issues. Agents and users can collaborate on docs.

Changes (27 files, +2120 lines)

Database (drizzle)

  • documents table — title, content (jsonb/tiptap format), projectId, created by agent/user
  • document_goals — many-to-many linking docs to goals
  • document_issues — many-to-many linking docs to issues
  • Migration: 0028_documents.sql

API (server/src/routes/documents.ts)

  • GET /api/companies/:id/documents — list with filters (?projectId, ?goalId, ?issueId)
  • POST /api/companies/:id/documents — create
  • GET /api/documents/:id — read with linked goals/issues
  • PATCH /api/documents/:id — update (auto-save from UI)
  • DELETE /api/documents/:id — delete
  • POST/DELETE /api/documents/:id/goals/:goalId — link/unlink goals
  • POST/DELETE /api/documents/:id/issues/:issueId — link/unlink issues

UI

  • Document list page — grouped by project, shows linked counts
  • Document editor — novel.sh (tiptap) rich text editor with auto-save
  • Project selector + goal/issue linkers on doc detail page
  • LinkedDocuments component — shown on issue detail + goal detail pages
  • Sidebar — "Documents" nav item added

Shared types & validators

  • Document types + zod validators in shared package

How to test

  1. Create a document from the sidebar
  2. Edit with the rich text editor — auto-saves
  3. Link it to a project, goals, and issues
  4. Check issue/goal detail pages for linked documents section

- New documents table with project association (drizzle migration 0028)
- Many-to-many linking: documents <> goals, documents <> issues
- Full CRUD API for documents with link management
- Novel.sh rich text editor in UI
- Document list page grouped by project
- Document detail page with editor, project selector, goal/issue linkers
- Linked documents shown on issue and goal detail pages
- Sidebar navigation for documents
- Auto-save with debounced PATCH

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0077160575

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +134 to +135
assertCompanyAccess(req, existing.companyId);
const link = await svc.linkGoal(id, req.body.goalId);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Verify goal and issue links stay inside the document company

This only authorizes against the document's companyId before inserting the relationship. If a scoped board user or agent submits a goalId from another company, the FK insert succeeds and GET /documents/:id will start returning that foreign ID back to readers of this document; the /documents/:id/issues handler below has the same gap. AGENTS.md explicitly says company boundaries must be enforced in routes/services, so these link endpoints need a same-company check on the target row, not just document access.

Useful? React with 👍 / 👎.

Comment on lines +135 to +136
const link = await svc.linkGoal(id, req.body.goalId);
res.status(201).json(link);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Record activity for document link and unlink mutations

All four goal/issue link handlers mutate join tables and return immediately, but unlike create/update/delete they never call logActivity. AGENTS.md says new endpoints should "write activity log entries for mutations", so attaching or detaching a document from a goal/issue currently leaves no audit trail for operators.

Useful? React with 👍 / 👎.

Comment on lines +81 to +83
const linkIssue = useMutation({
mutationFn: (issueId: string) => documentsApi.linkIssue(documentId!, issueId),
onSuccess: () =>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Wire the issue-link mutation into the document detail UI

This mutation is defined but never invoked anywhere in the component. The linked-issues section only renders existing links and unlink buttons, so board users have no UI path to create a document→issue association; as shipped, the new LinkedDocuments block on issue detail can only surface links inserted through manual API calls.

Useful? React with 👍 / 👎.

Utkarshbhimte and others added 3 commits March 22, 2026 21:06
- Documents now require an issueId (not null) — every doc is created from a task
- Document creation auto-links the source issue via document_issues
- Doc detail page has issue sidebar showing:
  - Issue title, identifier, status, priority, assignee
  - Issue description (truncated)
  - Live comments feed (polls every 15s)
- Documents list page shows issue picker modal when creating new doc
- Agents can edit docs by commenting on the source issue
- Updated migration, schema, types, validators, service, and UI

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Covers data model, API endpoints, UI pages, agent workflow,
and editor details.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
- New endpoint: GET /api/issues/:issueId/document — agents can find
  their doc from their assigned task without knowing the doc ID
- Updated docs with agent direct editing workflow (read → edit → save)
- Agents can PATCH /api/documents/:id with content directly
- Comment-based collaboration remains as secondary workflow

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Utkarshbhimte pushed a commit that referenced this pull request Mar 23, 2026
**#1 — Missing `description` field in fields table**
The create body example included `description` and the schema confirms
`description: z.string().optional().nullable()`, but the reference table
omitted it. Added as an optional field.

**#2 — Concurrency policy descriptions were inaccurate**
Original docs described both `coalesce_if_active` and `skip_if_active` as
variants of "skip", which was wrong. Source-verified against
`server/src/services/routines.ts` (dispatchRoutineRun, line 568):

  const status = concurrencyPolicy === "skip_if_active" ? "skipped" : "coalesced";

Both policies write identical DB state (same linkedIssueId and
coalescedIntoRunId); the only difference is the run status value.
Descriptions now reflect this: both finalise the incoming run immediately
and link it to the active run — no new issue is created in either case.

Note: the reviewer's suggestion that `coalesce_if_active` "extends or
notifies" the active run was also not supported by the code; corrected
accordingly.

**paperclipai#3 — `triggerId` undocumented in Manual Run**
`runRoutineSchema` accepts `triggerId` and the service genuinely uses it
(routines.ts:1029–1034): fetches the trigger, enforces that it belongs to
the routine (403) and is enabled (409), then passes it to dispatchRoutineRun
which records the run against the trigger and updates its `lastFiredAt`.
Added `triggerId` to the example body and documented all three behaviours.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant