Skip to content

hw725/pdf_annotator

Repository files navigation

RefManager PDF Annotator

๋ณ„๋„ ํ˜ธ์ŠคํŒ…๋˜๋Š” PDF ์ฃผ์„ ํŽธ์ง‘๊ธฐ - Base44 RefManager์™€ API๋กœ ์—ฐ๋™

๐Ÿ“‹ ๊ฐœ์š”

์ด ์•ฑ์€ Base44 RefManager์™€ ๋ถ„๋ฆฌ๋˜์–ด ๋…๋ฆฝ์ ์œผ๋กœ ํ˜ธ์ŠคํŒ…๋˜๋Š” PDF ์ฃผ์„ ํŽธ์ง‘๊ธฐ์ž…๋‹ˆ๋‹ค. RefManager์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ œ์•ฝ์‚ฌํ•ญ์„ ์šฐํšŒํ•˜๋ฉด์„œ ์™„์ „ํ•œ PDF ์ฃผ์„ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ ์˜์†ํ™”๋Š” ์„ ํƒ์ ์œผ๋กœ Supabase๋ฅผ ๋ฐฑ์—”๋“œ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ŸฐํŠธ์—”๋“œ ํ˜ธ์ŠคํŒ…์€ Vercel/Netlify ๋“ฑ์—์„œ ์ˆ˜ํ–‰ํ•˜์„ธ์š”.

์ฃผ์š” ๊ธฐ๋Šฅ

  • ๐Ÿ“„ PDF ๋ทฐ์–ด (react-pdf ๊ธฐ๋ฐ˜)
  • โœ๏ธ ํ…์ŠคํŠธ ํ•˜์ด๋ผ์ดํŠธ
  • ๐Ÿ–ผ๏ธ ์˜์—ญ ์„ ํƒ ์ฃผ์„
  • ๐Ÿ’พ RefManager API์™€ ๋™๊ธฐํ™” (์„ ํƒ)
  • โ˜๏ธ Supabase๋กœ ์ฃผ์„ Save/Load (์„ ํƒ)
  • ๐ŸŽจ ๋‹ค์–‘ํ•œ ์ƒ‰์ƒ ์„ ํƒ
  • ๐Ÿ“ฑ ๋ฐ˜์‘ํ˜• UI

๐Ÿ—๏ธ ์•„ํ‚คํ…์ฒ˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   RefManager (Base44)           โ”‚
โ”‚   - ์„œ์ง€์‚ฌํ•ญ ๊ด€๋ฆฌ               โ”‚
โ”‚   - ์ธ์šฉ ์ƒ์„ฑ                   โ”‚
โ”‚   - Base44 Functions API        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
             โ”‚ REST API
             โ”‚ (์ฃผ์„ ๋ฐ์ดํ„ฐ ๊ตํ™˜)
             โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   PDF Annotator (๋ณ„๋„ ํ˜ธ์ŠคํŒ…)   โ”‚
โ”‚   - react-pdf ๋ทฐ์–ด              โ”‚
โ”‚   - pdf-lib ์ฃผ์„ ์ฒ˜๋ฆฌ           โ”‚
โ”‚   - IndexedDB ์บ์‹œ              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿš€ ์„ค์น˜ ๋ฐ ์‹คํ–‰

1. ์˜์กด์„ฑ ์„ค์น˜

npm install

2. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •

.env.local ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ํ•„์š”ํ•œ ๊ฐ’์„ ์„ค์ •:

# RefManager Functions (์„ ํƒ)
VITE_REFMANAGER_API_URL=https://your-refmanager-app.base44.app/api

# Google Drive ์—ฐ๋™ (์„ ํƒ)
VITE_GOOGLE_CLIENT_ID=your_google_client_id.apps.googleusercontent.com
VITE_GOOGLE_API_KEY=your_google_api_key

# Supabase (์„ ํƒ)
VITE_SUPABASE_URL=https://YOUR-PROJECT-REF.supabase.co
VITE_SUPABASE_ANON_KEY=your_anon_key

3. ๊ฐœ๋ฐœ ์„œ๋ฒ„ ์‹คํ–‰

npm run dev

๋ธŒ๋ผ์šฐ์ €์—์„œ http://localhost:3000 ์—ด๋ฆผ (vite.config.js์—์„œ ํฌํŠธ 3000 ์ง€์ •)

4. ๋นŒ๋“œ

npm run build

๋นŒ๋“œ ๊ฒฐ๊ณผ๋ฌผ์€ dist ํด๋”์— ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ› ๋””๋ฒ„๊น… ๋ชจ๋“œ

RefManager API ํ†ต์‹  ๋ฌธ์ œ๋ฅผ ์ง„๋‹จํ•˜๋ ค๋ฉด ๋ธŒ๋ผ์šฐ์ € ์ฝ˜์†”์—์„œ ๋””๋ฒ„๊น… ๋ชจ๋“œ๋ฅผ ํ™œ์„ฑํ™”ํ•˜์„ธ์š”:

// ํ™œ์„ฑํ™”
localStorage.setItem("debug_refmanager", "true");

// ๋น„ํ™œ์„ฑํ™”
localStorage.removeItem("debug_refmanager");

๋””๋ฒ„๊น… ๋ชจ๋“œ์—์„œ๋Š”:

  • ๋ชจ๋“  API ์š”์ฒญ/์‘๋‹ต์˜ ์ƒ์„ธ ์ •๋ณด๊ฐ€ ์ฝ˜์†”์— ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค
  • ํ”„๋ก์‹œ ์„œ๋ฒ„ ๋กœ๊ทธ (Vercel Functions)์—๋„ ์ถ”๊ฐ€ ์ •๋ณด๊ฐ€ ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค
  • ์—…์ŠคํŠธ๋ฆผ ํƒ€๊ฒŸ URL, ์š”์ฒญ ๋ฐ”๋””, ์‘๋‹ต ๋ฐ”๋”” ๋ฏธ๋ฆฌ๋ณด๊ธฐ ํ™•์ธ ๊ฐ€๋Šฅ

์ค‘์š”: ํ”„๋กœ๋•์…˜์—์„œ๋Š” ๋ฐ˜๋“œ์‹œ ๋น„ํ™œ์„ฑํ™”ํ•˜์„ธ์š” (ํ† ํฐ ์ •๋ณด๊ฐ€ ๋กœ๊ทธ์— ๋…ธ์ถœ๋  ์ˆ˜ ์žˆ์Œ)

๐Ÿ”— RefManager์™€ ์—ฐ๋™

URL ํŒŒ๋ผ๋ฏธํ„ฐ

PDF Annotator๋Š” ๋‹ค์Œ URL ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค:

https://your-pdf-annotator.app/?referenceId=REF123&token=AUTH_TOKEN&title=๋…ผ๋ฌธ์ œ๋ชฉ&pdfUrl=https://...

ํŒŒ๋ผ๋ฏธํ„ฐ:

  • referenceId (์„ ํƒ): RefManager ์ฐธ๊ณ ๋ฌธํ—Œ ID. ๋ฏธ์ œ๊ณต ์‹œ ์ž„์‹œ ๋ชจ๋“œ๋กœ ๋™์ž‘ํ•˜๋ฉฐ URL ์ž…๋ ฅ ๋˜๋Š” ๋กœ์ปฌ ์—…๋กœ๋“œ๋กœ PDF๋ฅผ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • token (์„ ํƒ): Base44 ์ธ์ฆ ํ† ํฐ. RefManager API๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งŒ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  • title (์„ ํƒ): PDF ์ œ๋ชฉ (API์—์„œ ๊ฐ€์ ธ์˜ค์ง€ ์•Š์„ ๊ฒฝ์šฐ)
  • pdfUrl (์„ ํƒ): PDF ์ง์ ‘ URL (API์—์„œ ๊ฐ€์ ธ์˜ค์ง€ ์•Š์„ ๊ฒฝ์šฐ)

RefManager์—์„œ ํ˜ธ์ถœ

๋ฐฉ๋ฒ• 1: ์ƒˆ ํƒญ์œผ๋กœ ์—ด๊ธฐ

// RefManager์˜ References.jsx
const openPDFAnnotator = (reference) => {
  const token = getBase44AuthToken(); // Base44 ์„ธ์…˜ ํ† ํฐ
  const url = new URL('https://your-pdf-annotator.app/');
  url.searchParams.set('referenceId', reference.id);
  url.searchParams.set('token', token);
  if (reference.title) url.searchParams.set('title', reference.title);
  if (reference.pdf_url) url.searchParams.set('pdfUrl', reference.pdf_url);
  
  window.open(url.toString(), '_blank');
};

๋ฐฉ๋ฒ• 2: iframe ์ž„๋ฒ ๋“œ

// RefManager์˜ PDFViewModal.jsx
<iframe
  src={`https://your-pdf-annotator.app/?referenceId=${refId}&token=${token}`}
  style={{ width: '100%', height: '100%', border: 'none' }}
  allow="fullscreen"
/>

๐Ÿ”ง Base44 Functions API

RefManager ์•ฑ์— ๋‹ค์Œ Functions๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

1. getPdfInfo

์š”์ฒญ:

POST /api/functions/getPdfInfo
{
  "referenceId": "REF123"
}

์‘๋‹ต:

{
  "referenceId": "REF123",
  "title": "์—ฐ๊ตฌ ๋…ผ๋ฌธ ์ œ๋ชฉ",
  "pdfUrl": "https://drive.google.com/...",
  "author_ids": ["AUTH1", "AUTH2"],
  "year": 2023
}

2. getAnnotations

์š”์ฒญ:

POST /api/functions/getAnnotations
{
  "referenceId": "REF123"
}

์‘๋‹ต:

{
  "success": true,
  "annotations": [
    {
      "id": "ANNOT1",
      "reference_id": "REF123",
      "type": "highlight",
      "page_number": 1,
      "content": "ํ•˜์ด๋ผ์ดํŠธ๋œ ํ…์ŠคํŠธ",
      "position": { "rects": [...] },
      "color": "#FFFF00"
    }
  ]
}

3. saveAnnotation

์š”์ฒญ:

POST /api/functions/saveAnnotation
{
  "reference_id": "REF123",
  "type": "highlight",
  "page_number": 1,
  "content": "ํ•˜์ด๋ผ์ดํŠธ ํ…์ŠคํŠธ",
  "position": { "rects": [...] },
  "color": "#FFFF00"
}

์‘๋‹ต:

{
  "success": true,
  "annotation": {
    "id": "ANNOT2",
    "reference_id": "REF123",
    ...
  }
}

4. deleteAnnotation

์š”์ฒญ:

POST /api/functions/deleteAnnotation
{
  "annotationId": "ANNOT1"
}

์‘๋‹ต:

{
  "success": true
}

๐Ÿ—„๏ธ Base44 ๋ฐ์ดํ„ฐ ๋ชจ๋ธ

RefManager์— PdfAnnotation ์—”ํ‹ฐํ‹ฐ ์ƒ์„ฑ:

// Base44์—์„œ
const PdfAnnotation = Entity({
  name: 'PdfAnnotation',
  fields: {
    reference_id: { type: 'reference', entity: 'Reference' },
    type: { type: 'string' }, // 'highlight', 'text_note', 'drawing'
    page_number: { type: 'number' },
    content: { type: 'text' },
    position: { type: 'json' },
    color: { type: 'string' },
    created_at: { type: 'datetime', default: 'now' },
  }
});

๐Ÿ” ์ธ์ฆ

PDF Annotator๋Š” RefManager์—์„œ ์ „๋‹ฌ๋ฐ›์€ Base44 ์ธ์ฆ ํ† ํฐ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

// API ํด๋ผ์ด์–ธํŠธ (src/api/refManagerClient.js)
const token = localStorage.getItem('base44_auth_token');
fetch(API_URL, {
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

๐Ÿ“ฆ ๋ฐฐํฌ

Netlify

npm run build

dist ํด๋”๋ฅผ Netlify์— ๋ฐฐํฌ

Vercel

vercel --prod

ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ • (๋ฐฐํฌ ์‹œ)

๋ฐฐํฌ ํ”Œ๋žซํผ(Vercel/Netlify)์˜ ํ”„๋กœ์ ํŠธ ์„ค์ •์—์„œ ์œ„ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋“ค์„ ๋™์ผํ•˜๊ฒŒ ๋“ฑ๋กํ•˜์„ธ์š”. Drive ๋˜๋Š” Supabase๋ฅผ ์“ฐ์ง€ ์•Š์œผ๋ฉด ํ•ด๋‹น ํ‚ค๋Š” ์ƒ๋žต ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ถ”๊ฐ€๋กœ, Drive ์—ฐ๋™์„ ์“ด๋‹ค๋ฉด Google Cloud OAuth์˜ Authorized JavaScript origins์— ๋ฐฐํฌ ๋„๋ฉ”์ธ์„ ๋“ฑ๋กํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ› ๏ธ ๊ฐœ๋ฐœ

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

pdf_annotator/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ api/
โ”‚   โ”‚   โ””โ”€โ”€ refManagerClient.js   # RefManager API ํด๋ผ์ด์–ธํŠธ
โ”‚   โ”œโ”€โ”€ components/
โ”‚   โ”‚   โ””โ”€โ”€ pdf/
โ”‚   โ”‚       โ”œโ”€โ”€ PDFViewer.jsx      # ๋ฉ”์ธ PDF ๋ทฐ์–ด
โ”‚   โ”‚       โ”œโ”€โ”€ PDFHighlight.jsx   # ํ•˜์ด๋ผ์ดํŠธ ํˆด๋ฐ”
โ”‚   โ”‚       โ””โ”€โ”€ PageHighlightOverlay.jsx  # ์ฃผ์„ ์˜ค๋ฒ„๋ ˆ์ด
โ”‚   โ”œโ”€โ”€ utils/
โ”‚   โ”‚   โ”œโ”€โ”€ pdfExport.js          # PDF ๋‚ด๋ณด๋‚ด๊ธฐ
โ”‚   โ”‚   โ””โ”€โ”€ pdfManager.js         # PDF ๊ด€๋ฆฌ
โ”‚   โ”œโ”€โ”€ db/
โ”‚   โ”‚   โ””โ”€โ”€ localDB.js            # IndexedDB (์˜คํ”„๋ผ์ธ ์บ์‹œ)
โ”‚   โ”œโ”€โ”€ App.jsx                   # ๋ฉ”์ธ ์•ฑ
โ”‚   โ””โ”€โ”€ main.jsx                  # ์—”ํŠธ๋ฆฌ ํฌ์ธํŠธ
โ”œโ”€โ”€ package.json
โ”œโ”€โ”€ vite.config.js
โ””โ”€โ”€ index.html

์ฃผ์š” ์˜์กด์„ฑ

  • react: ^18.3.1
  • react-pdf: ^9.1.1
  • pdfjs-dist: ^4.8.69
  • pdf-lib: ^1.17.1
  • idb: ^8.0.0
  • @supabase/supabase-js: ^2.x (์„ ํƒ)

๐Ÿ› ๋ฌธ์ œ ํ•ด๊ฒฐ

CORS ์—๋Ÿฌ

RefManager API์—์„œ CORS ํ—ค๋” ์„ค์ •:

// Base44 Function์—์„œ
response.headers['Access-Control-Allow-Origin'] = 'https://your-pdf-annotator.app';

PDF ๋กœ๋“œ ์‹คํŒจ

  1. pdfUrl์ด ์˜ฌ๋ฐ”๋ฅธ์ง€ ํ™•์ธ
  2. Google Drive ํŒŒ์ผ์˜ ๊ณต์œ  ์„ค์ • ํ™•์ธ
  3. CORS ํ”„๋ก์‹œ ์‚ฌ์šฉ ๊ณ ๋ ค

Supabase Save/Load ๋ฒ„ํŠผ์ด ๋ณด์ด์ง€ ์•Š์Œ

  • VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ
  • ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋ณ€๊ฒฝ ํ›„์—๋Š” ๊ฐœ๋ฐœ ์„œ๋ฒ„ ์žฌ์‹œ์ž‘/๋ฐฐํฌ ์žฌ์‹คํ–‰ ํ•„์š”

๐Ÿ“ ๋ผ์ด์„ ์Šค

MIT License

๐Ÿค ๊ธฐ์—ฌ

์ด์Šˆ ๋ฐ PR ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค!

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published