3.3 KiB
3.3 KiB
EdgeEver Project Structure
edgeever/
├── apps/
│ ├── web/
│ │ ├── public/
│ │ │ ├── manifest.webmanifest
│ │ │ └── icons/
│ │ ├── src/
│ │ │ ├── app/
│ │ │ │ ├── App.tsx
│ │ │ │ └── routes.tsx
│ │ │ ├── components/
│ │ │ │ ├── editor/
│ │ │ │ ├── layout/
│ │ │ │ ├── memo-list/
│ │ │ │ ├── notebook-tree/
│ │ │ │ └── ui/
│ │ │ ├── hooks/
│ │ │ ├── lib/
│ │ │ ├── styles/
│ │ │ └── main.tsx
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── vite.config.ts
│ └── api/
│ ├── src/
│ │ ├── index.ts
│ │ ├── env.ts
│ │ ├── db/
│ │ ├── routes/
│ │ │ ├── memos.ts
│ │ │ ├── notebooks.ts
│ │ │ └── resources.ts
│ │ └── services/
│ │ ├── merge-memos.ts
│ │ └── resource-store.ts
│ ├── package.json
│ └── tsconfig.json
├── packages/
│ └── shared/
│ ├── src/
│ │ ├── content.ts
│ │ ├── index.ts
│ │ ├── schemas.ts
│ │ └── types.ts
│ ├── package.json
│ └── tsconfig.json
├── migrations/
│ └── 0001_initial.sql
├── docs/
│ └── project-structure.md
├── tailwind.config.ts
├── wrangler.toml
├── bun.lock
└── package.json
Deployment Shape
EdgeEver should deploy as one Cloudflare Worker:
/api/*is routed to the Hono app first.- Static files from
apps/web/distare served by Workers Assets. - Unknown static routes fall back to
index.htmlfor SPA and PWA navigation. env.DBis the D1 binding.env.RESOURCESis the R2 bucket binding for images and attachments.
Frontend Boundaries
components/layoutowns the responsive three-pane shell.components/notebook-treerenders recursive notebooks fromparent_id.components/memo-listowns checkbox selection and merge action surfaces.components/editorowns TipTap integration and Markdown serialization.lib/api-client.tsshould be the only browser module that talks to/api/*.
API Boundaries
routes/*should stay thin: validate input, call services, return JSON.services/merge-memos.tsowns the D1 transaction that creates a merged memo, soft deletes source memos, and re-points resources.services/resource-store.tsowns R2 object keys and upload/download URL policy.db/*owns SQL snippets and row mapping.
Data Model Notes
- Notebook nesting is unbounded through
notebooks.parent_id. - Every memo belongs to exactly one notebook through
memos.notebook_id. - Merge output is represented by a new memo with
source_memo_idsandmerge_source_count. - Merge inputs are retained as soft-deleted rows with
merged_into_memo_id. - R2 objects are not moved during merge;
resources.memo_idis updated to the new memo.