memi-board 0.29.1 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -240,13 +240,16 @@ const { post: postSeo } = await useMemiBoardPostSeo({
240
240
  1. [docs/firestore.rules.example](docs/firestore.rules.example) → 호스트 `firestore.rules`에 병합
241
241
  (`memiBoardPosts`/`memiBoardComments`/`memiBoardLikes`/`memiBoardSettings`/`memiBoardUsers` — 전부 최상위 flat 컬렉션)
242
242
  2. [docs/storage.rules.example](docs/storage.rules.example) → `storage.rules` 병합
243
- 3. 목록/작성자별 쿼리에 필요한 복합 인덱스 배포 (아래)
244
- 4. 배포:
243
+ 3. `firebase.json`의 Storage `bucket`이 `vuefire.config.storageBucket`과 같은지 확인
244
+ (`*.appspot.com` vs `*.firebasestorage.app` — [firebase-setup.md](docs/firebase-setup.md) 참고)
245
+ 4. 목록/작성자별 쿼리에 필요한 복합 인덱스 배포 (아래)
246
+ 5. 배포:
245
247
  ```bash
246
248
  firebase deploy --only firestore:rules,storage,firestore:indexes
247
249
  ```
248
250
 
249
251
  **Rules를 파일에만 넣고 배포 안 하면** 글쓰기에서 `permission-denied` — 가장 흔한 설치 실수.
252
+ **Storage 규칙을 앱이 쓰는 버킷이 아닌 곳에 배포하면** 본문 이미지에서 `storage/unauthorized`.
250
253
 
251
254
  #### 복합 인덱스
252
255
 
@@ -376,6 +379,7 @@ const router = useRouter()
376
379
 
377
380
  **에디터 이미지:** 툴바 / 붙여넣기 / 드롭 → Firebase Storage
378
381
  `memiBoardPosts/{postId}/images/*` + `.../images/thumbnails/*` (최적화 이미지+썸네일).
382
+ 글 문서는 아직 없을 수 있고, 붙여넣기는 `image/png` 등이 온다. Storage 예시 규칙은 쓰기를 **로그인 + 5MB + `image/*`** 로 본다. 규칙은 **앱 `storageBucket`과 같은 버킷**에 배포해야 한다.
379
383
 
380
384
  본문 이미지는 휴대폰 원본 기준 최대 25MB까지 선택할 수 있다. 5MB를 넘으면 브라우저에서 최대 2560px·JPEG 85%로 최적화하고, 결과가 여전히 5MB를 넘으면 2048px·75%로 한 번 더 줄인 뒤 업로드한다. 5MB 이하 이미지는 원본을 유지한다.
381
385
  본문 HTML에는 원본 URL. 수정 중 버려진 파일은 호스트 스케줄러로 정리 (`extractEditorImageUrls` 로 본문 참조 비교).
@@ -505,6 +509,15 @@ export default defineNuxtPlugin(() => {
505
509
 
506
510
  App Check 토큰, `appId` 일치, 모델명(3.x), AI Logic 활성화, 네트워크. 브라우저 콘솔의 `moderation AI failed` warn 확인.
507
511
 
512
+ ### 에디터 이미지 `storage/unauthorized`
513
+
514
+ 본문 붙여넣기·업로드가 `User does not have permission to access 'memiBoardPosts/…/images/…'` 로 실패하면:
515
+
516
+ 1. 로그인 상태인지 확인
517
+ 2. `vuefire.config.storageBucket`과 `firebase.json` `storage.bucket`이 **같은 이름**인지 확인. 구 프로젝트는 `*.appspot.com`(앱)과 `*.firebasestorage.app`(CLI 기본)이 갈라질 수 있다 — 앱이 쓰는 쪽에 규칙을 배포한다.
518
+ 3. 호스트 `storage.rules`에 `docs/storage.rules.example`의 `memiBoardPosts/{postId}/images` 규칙이 있는지 확인. 쓰기는 `image/*` 이어야 한다(붙여넣기 PNG).
519
+ 4. `firebase deploy --only storage` 후 다시 올려 본다.
520
+
508
521
  ### monorepo `link:` / `file:` 로 개발할 때
509
522
 
510
523
  링크하기 전에 패키지 의존성과 `dist`를 준비한다.
package/dist/index.js CHANGED
@@ -658,12 +658,12 @@ function mt(t) {
658
658
  return s(l())?.listView === "image";
659
659
  }
660
660
  function _(e) {
661
- let t = g();
662
- if (!Qe(e.content)) throw Error(t ? "내용을 입력해 주세요." : "본문에 글자를 입력해 주세요. 이미지나 첨부만으로는 게시할 수 없습니다.");
661
+ let t = g(), n = Qe(e.content), r = $e(e.content, e.attachments);
663
662
  if (t) {
664
- if (!$e(e.content, e.attachments)) throw Error("사진을 올려 주세요.");
663
+ if (!r) throw Error("사진을 올려 주세요.");
665
664
  return;
666
665
  }
666
+ if (!n && !r) throw Error("본문에 글자를 입력하거나 이미지를 첨부해 주세요.");
667
667
  if (!e.title?.trim()) throw Error("제목을 입력해 주세요.");
668
668
  }
669
669
  function y() {
@@ -1724,6 +1724,16 @@ function Wt(e) {
1724
1724
  //#endregion
1725
1725
  //#region src/data/versionHistory.ts
1726
1726
  var Gt = [
1727
+ {
1728
+ version: "0.30.0",
1729
+ date: "2026-08-13",
1730
+ highlights: [
1731
+ "본문 글 없이 사진만 첨부해도 글을 올릴 수 있어요",
1732
+ "목록은 게시판 설정에서 정한 보기 방식을 사용하고, 테스트용 보기 전환 버튼은 숨겼어요",
1733
+ "글쓰기 중 사진 업로드 권한과 Storage 버킷 설정 안내를 보강했어요"
1734
+ ],
1735
+ note: "이미지 업로드가 거부되면 호스트의 Storage 규칙과 firebase.json 버킷 설정을 최신 예시로 확인해 주세요."
1736
+ },
1727
1737
  {
1728
1738
  version: "0.29.1",
1729
1739
  date: "2026-08-13",