From 1afb825860cd293b8065d51746f4b23e4e8dab5d Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 12 Feb 2026 14:54:18 +0000 Subject: feat: 学習カード数の上限を撤廃 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit REVIEW_CARDS_LIMIT(復習カード80枚制限)とnewCardsPerDay(1日の新規カード制限) を削除し、期日が来たすべてのカードを制限なく返すように変更。 削除した主な要素: - REVIEW_CARDS_LIMIT定数とカード取得時のlimitパラメータ - newCardsPerDayフィールド(DB schema, 型定義, Zod schema, sync, CRDT) - countDueNewCards, countDueReviewCards, findDueNewCardsForStudy, findDueReviewCardsForStudy(CardRepository) - countTodayNewCardReviews(ReviewLogRepository) - デッキルートからのReviewLogRepository依存 https://claude.ai/code/session_018hrEJ9vg3RPoeAPyEc17gS --- src/client/sync/crdt/concurrent-edits.test.ts | 33 +++++++++++++-------------- src/client/sync/crdt/document-manager.test.ts | 13 ----------- src/client/sync/crdt/document-manager.ts | 3 --- src/client/sync/crdt/migration.test.ts | 1 - src/client/sync/crdt/repositories.test.ts | 14 ++++-------- src/client/sync/crdt/types.test.ts | 3 --- src/client/sync/crdt/types.ts | 1 - 7 files changed, 20 insertions(+), 48 deletions(-) (limited to 'src/client/sync/crdt') diff --git a/src/client/sync/crdt/concurrent-edits.test.ts b/src/client/sync/crdt/concurrent-edits.test.ts index 2b6f182..d55b233 100644 --- a/src/client/sync/crdt/concurrent-edits.test.ts +++ b/src/client/sync/crdt/concurrent-edits.test.ts @@ -34,7 +34,6 @@ function createTestDeck(overrides: Partial = {}): LocalDeck { userId: "user-1", name: "Test Deck", description: null, - newCardsPerDay: 20, createdAt: now, updatedAt: now, deletedAt: null, @@ -89,10 +88,10 @@ describe("Concurrent edit scenarios", () => { d.meta.lastModified = Date.now(); }); - // Device B: Offline edit - change newCardsPerDay + // Device B: Offline edit - change description const deviceBDoc = Automerge.clone(serverDoc); const deviceBEdited = updateDocument(deviceBDoc, (d) => { - d.data.newCardsPerDay = 30; + d.data.description = "Updated by Device B"; d.meta.lastModified = Date.now(); }); @@ -101,7 +100,7 @@ describe("Concurrent edit scenarios", () => { // Both changes should be present expect(mergeResult.merged.data.name).toBe("Updated by Device A"); - expect(mergeResult.merged.data.newCardsPerDay).toBe(30); + expect(mergeResult.merged.data.description).toBe("Updated by Device B"); expect(mergeResult.hasChanges).toBe(true); }); @@ -120,7 +119,7 @@ describe("Concurrent edit scenarios", () => { const deviceBDoc = Automerge.clone(serverDoc); const deviceBEdited = updateDocument(deviceBDoc, (d) => { - d.data.newCardsPerDay = 50; + d.data.userId = "user-updated"; d.meta.lastModified = Date.now(); }); @@ -129,7 +128,7 @@ describe("Concurrent edit scenarios", () => { expect(mergedDeck.name).toBe("New Name"); expect(mergedDeck.description).toBe("Added by Device A"); - expect(mergedDeck.newCardsPerDay).toBe(50); + expect(mergedDeck.userId).toBe("user-updated"); }); }); @@ -342,7 +341,7 @@ describe("Concurrent edit scenarios", () => { // Device B makes a different edit const deviceBEdited = updateDocument(deviceBDoc, (d) => { - d.data.newCardsPerDay = 100; + d.data.description = "Description from B"; d.meta.lastModified = Date.now(); }); @@ -354,7 +353,7 @@ describe("Concurrent edit scenarios", () => { // Both changes should be present expect(serverWithB.data.name).toBe("Edit 1 from A"); - expect(serverWithB.data.newCardsPerDay).toBe(100); + expect(serverWithB.data.description).toBe("Description from B"); }); it("should handle three-way merge correctly", () => { @@ -377,7 +376,7 @@ describe("Concurrent edit scenarios", () => { }); const deviceCEdited = updateDocument(deviceCDoc, (d) => { - d.data.newCardsPerDay = 75; + d.data.userId = "user-from-C"; }); // Sequential merge: A + B @@ -389,7 +388,7 @@ describe("Concurrent edit scenarios", () => { // All three changes should be present expect(mergeABC.merged.data.name).toBe("Name from A"); expect(mergeABC.merged.data.description).toBe("Description from B"); - expect(mergeABC.merged.data.newCardsPerDay).toBe(75); + expect(mergeABC.merged.data.userId).toBe("user-from-C"); }); }); @@ -575,7 +574,7 @@ describe("Concurrent edit scenarios", () => { // Edit 3 const beforeEdit3 = Automerge.clone(deviceADoc); deviceADoc = updateDocument(deviceADoc, (d) => { - d.data.newCardsPerDay = 42; + d.data.userId = "user-offline"; }); offlineEdits.push(getChanges(beforeEdit3, deviceADoc)); @@ -588,7 +587,7 @@ describe("Concurrent edit scenarios", () => { // Verify all offline edits are applied expect(currentServer.data.name).toBe("Offline edit 1"); expect(currentServer.data.description).toBe("Offline edit 2"); - expect(currentServer.data.newCardsPerDay).toBe(42); + expect(currentServer.data.userId).toBe("user-offline"); }); it("should handle two devices syncing after extended offline periods", () => { @@ -612,22 +611,22 @@ describe("Concurrent edit scenarios", () => { // Device B: Different offline edits let deviceBDoc = Automerge.clone(serverDoc); deviceBDoc = updateDocument(deviceBDoc, (d) => { - d.data.newCardsPerDay = 50; + d.data.userId = "B: First user"; }); deviceBDoc = updateDocument(deviceBDoc, (d) => { - d.data.newCardsPerDay = 60; + d.data.userId = "B: Second user"; }); deviceBDoc = updateDocument(deviceBDoc, (d) => { - d.data.newCardsPerDay = 100; + d.data.userId = "B: Final user"; }); // Both devices come online and sync const mergeResult = mergeDocuments(deviceADoc, deviceBDoc); - // Device A's content edits and Device B's card setting + // Device A's content edits and Device B's user edits expect(mergeResult.merged.data.name).toBe("A: Final name"); expect(mergeResult.merged.data.description).toBe("A: Added description"); - expect(mergeResult.merged.data.newCardsPerDay).toBe(100); + expect(mergeResult.merged.data.userId).toBe("B: Final user"); }); }); }); diff --git a/src/client/sync/crdt/document-manager.test.ts b/src/client/sync/crdt/document-manager.test.ts index 7c0fc00..b578c77 100644 --- a/src/client/sync/crdt/document-manager.test.ts +++ b/src/client/sync/crdt/document-manager.test.ts @@ -51,7 +51,6 @@ describe("createDocument", () => { userId: "user-1", name: "My Deck", description: null, - newCardsPerDay: 20, createdAt: Date.now(), deletedAt: null, }, @@ -154,7 +153,6 @@ describe("saveDocument and loadDocument", () => { userId: "user-1", name: "Test Deck", description: "A test deck", - newCardsPerDay: 15, createdAt: 1234567890, deletedAt: null, }, @@ -168,7 +166,6 @@ describe("saveDocument and loadDocument", () => { const loaded = loadDocument(binary); expect(loaded.meta.entityId).toBe("deck-123"); expect(loaded.data.name).toBe("Test Deck"); - expect(loaded.data.newCardsPerDay).toBe(15); }); }); @@ -195,7 +192,6 @@ describe("createEmptyDocument", () => { expect(doc.meta.entityId).toBe(""); expect(doc.meta.deleted).toBe(false); expect(doc.data.name).toBe(""); - expect(doc.data.newCardsPerDay).toBe(20); }); it("should create empty card document", () => { @@ -226,7 +222,6 @@ describe("deckToCrdtDocument and crdtDocumentToDeck", () => { userId: "user-1", name: "My Deck", description: "A deck for testing", - newCardsPerDay: 25, createdAt: now, updatedAt: now, deletedAt: null, @@ -240,7 +235,6 @@ describe("deckToCrdtDocument and crdtDocumentToDeck", () => { expect(crdtDoc.meta.deleted).toBe(false); expect(crdtDoc.data.name).toBe("My Deck"); expect(crdtDoc.data.description).toBe("A deck for testing"); - expect(crdtDoc.data.newCardsPerDay).toBe(25); expect(crdtDoc.data.createdAt).toBe(now.getTime()); }); @@ -252,7 +246,6 @@ describe("deckToCrdtDocument and crdtDocumentToDeck", () => { userId: "user-1", name: "Deleted Deck", description: null, - newCardsPerDay: 20, createdAt: now, updatedAt: deletedAt, deletedAt: deletedAt, @@ -278,7 +271,6 @@ describe("deckToCrdtDocument and crdtDocumentToDeck", () => { userId: "user-2", name: "Converted Deck", description: "Converted from CRDT", - newCardsPerDay: 30, createdAt: now - 10000, deletedAt: null, }, @@ -289,7 +281,6 @@ describe("deckToCrdtDocument and crdtDocumentToDeck", () => { expect(localDeck.id).toBe("deck-3"); expect(localDeck.userId).toBe("user-2"); expect(localDeck.name).toBe("Converted Deck"); - expect(localDeck.newCardsPerDay).toBe(30); expect(localDeck.deletedAt).toBeNull(); expect(localDeck.syncVersion).toBe(0); // Set by sync layer }); @@ -465,7 +456,6 @@ describe("createDocumentFromEntity", () => { userId: "user-1", name: "Test", description: null, - newCardsPerDay: 20, createdAt: now, updatedAt: now, deletedAt: null, @@ -546,7 +536,6 @@ describe("getLastModified", () => { userId: "user-1", name: "Test", description: null, - newCardsPerDay: 20, createdAt: timestamp, deletedAt: null, }, @@ -569,7 +558,6 @@ describe("isDeleted", () => { userId: "user-1", name: "Test", description: null, - newCardsPerDay: 20, createdAt: Date.now(), deletedAt: null, }, @@ -590,7 +578,6 @@ describe("isDeleted", () => { userId: "user-1", name: "Test", description: null, - newCardsPerDay: 20, createdAt: Date.now(), deletedAt: Date.now(), }, diff --git a/src/client/sync/crdt/document-manager.ts b/src/client/sync/crdt/document-manager.ts index 5c32b67..b753d88 100644 --- a/src/client/sync/crdt/document-manager.ts +++ b/src/client/sync/crdt/document-manager.ts @@ -187,7 +187,6 @@ function getEmptyDocumentData( userId: "", name: "", description: null, - newCardsPerDay: 20, createdAt: 0, deletedAt: null, }, @@ -301,7 +300,6 @@ export function deckToCrdtDocument(deck: LocalDeck): CrdtDeckDocument { userId: deck.userId, name: deck.name, description: deck.description, - newCardsPerDay: deck.newCardsPerDay, createdAt: deck.createdAt.getTime(), deletedAt: deck.deletedAt?.getTime() ?? null, }, @@ -319,7 +317,6 @@ export function crdtDocumentToDeck( userId: doc.data.userId, name: doc.data.name, description: doc.data.description, - newCardsPerDay: doc.data.newCardsPerDay, createdAt: new Date(doc.data.createdAt), updatedAt: new Date(doc.meta.lastModified), deletedAt: doc.data.deletedAt ? new Date(doc.data.deletedAt) : null, diff --git a/src/client/sync/crdt/migration.test.ts b/src/client/sync/crdt/migration.test.ts index 22f311d..ba90be2 100644 --- a/src/client/sync/crdt/migration.test.ts +++ b/src/client/sync/crdt/migration.test.ts @@ -109,7 +109,6 @@ describe("migration", () => { userId: "user-1", name: "Test Deck", description: null, - newCardsPerDay: 20, createdAt: new Date(), updatedAt: new Date(), deletedAt: null, diff --git a/src/client/sync/crdt/repositories.test.ts b/src/client/sync/crdt/repositories.test.ts index f237536..f7b75b3 100644 --- a/src/client/sync/crdt/repositories.test.ts +++ b/src/client/sync/crdt/repositories.test.ts @@ -35,7 +35,6 @@ describe("crdtDeckRepository", () => { userId: "user-1", name: "Test Deck", description: "A test deck", - newCardsPerDay: 20, createdAt: now, updatedAt: now, deletedAt: null, @@ -77,14 +76,14 @@ describe("crdtDeckRepository", () => { d.data.name = "Updated Name"; }); const updated2 = Automerge.change(doc2, (d) => { - d.data.newCardsPerDay = 30; + d.data.description = "Updated Description"; }); const result = crdtDeckRepository.merge(updated1, updated2); expect(result.hasChanges).toBe(true); expect(result.merged.data.name).toBe("Updated Name"); - expect(result.merged.data.newCardsPerDay).toBe(30); + expect(result.merged.data.description).toBe("Updated Description"); }); it("should convert CRDT document to local entity", () => { @@ -379,7 +378,6 @@ describe("entitiesToCrdtDocuments", () => { userId: "user-1", name: "Deck 1", description: null, - newCardsPerDay: 20, createdAt: now, updatedAt: now, deletedAt: null, @@ -391,7 +389,6 @@ describe("entitiesToCrdtDocuments", () => { userId: "user-1", name: "Deck 2", description: "Second deck", - newCardsPerDay: 15, createdAt: now, updatedAt: now, deletedAt: null, @@ -418,7 +415,6 @@ describe("mergeAndConvert", () => { userId: "user-1", name: "Remote Deck", description: null, - newCardsPerDay: 20, createdAt: now, updatedAt: now, deletedAt: null, @@ -440,7 +436,6 @@ describe("mergeAndConvert", () => { userId: "user-1", name: "Original", description: null, - newCardsPerDay: 20, createdAt: now, updatedAt: now, deletedAt: null, @@ -452,7 +447,7 @@ describe("mergeAndConvert", () => { // Create remote with different changes const remoteDoc = Automerge.change(Automerge.clone(localDoc), (d) => { - d.data.newCardsPerDay = 30; + d.data.description = "Remote Description"; }); const remoteBinary = saveDocument(remoteDoc); @@ -471,7 +466,7 @@ describe("mergeAndConvert", () => { expect(result.hasChanges).toBe(true); // Both changes should be merged expect(result.entity.name).toBe("Updated Local"); - expect(result.entity.newCardsPerDay).toBe(30); + expect(result.entity.description).toBe("Remote Description"); }); it("should detect no changes when documents are identical", () => { @@ -481,7 +476,6 @@ describe("mergeAndConvert", () => { userId: "user-1", name: "Same", description: null, - newCardsPerDay: 20, createdAt: now, updatedAt: now, deletedAt: null, diff --git a/src/client/sync/crdt/types.test.ts b/src/client/sync/crdt/types.test.ts index 15fd79b..07ae0f2 100644 --- a/src/client/sync/crdt/types.test.ts +++ b/src/client/sync/crdt/types.test.ts @@ -149,7 +149,6 @@ describe("CRDT Document type structures", () => { userId: "user-1", name: "My Deck", description: "A test deck", - newCardsPerDay: 20, createdAt: now, deletedAt: null, }, @@ -157,7 +156,6 @@ describe("CRDT Document type structures", () => { expect(doc.meta.entityId).toBe("deck-1"); expect(doc.data.name).toBe("My Deck"); - expect(doc.data.newCardsPerDay).toBe(20); }); it("should allow creating a valid CrdtNoteTypeDocument", () => { @@ -305,7 +303,6 @@ describe("CRDT Document type structures", () => { userId: "user-1", name: "Deleted Deck", description: null, - newCardsPerDay: 20, createdAt: now - 86400000, deletedAt: now, }, diff --git a/src/client/sync/crdt/types.ts b/src/client/sync/crdt/types.ts index 1dfae1a..e2f5d4c 100644 --- a/src/client/sync/crdt/types.ts +++ b/src/client/sync/crdt/types.ts @@ -36,7 +36,6 @@ export interface CrdtDeckDocument { userId: string; name: string; description: string | null; - newCardsPerDay: number; createdAt: number; // Unix timestamp in ms deletedAt: number | null; }; -- cgit v1.3-1-g0d28