Skip to content

Commit afc94f8

Browse files
committed
Address program cache and reset review
1 parent 06b0f79 commit afc94f8

5 files changed

Lines changed: 58 additions & 7 deletions

File tree

apps/www/lib/programs/server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import "server-only";
33
import { api } from "@repo/backend/convex/_generated/api";
44
import { fetchQuery } from "convex/nextjs";
55
import { Effect, Schema } from "effect";
6-
import { cacheLife } from "next/cache";
76
import type { Locale } from "next-intl";
87
import type {
98
ActiveLearningProfile,
109
LearningProgramCatalog,
1110
} from "@/components/programs/contract";
11+
import { applyContentRuntimeCache } from "@/lib/content/cache";
1212

1313
/** Expected failure while reading the current user's learning profile. */
1414
class ActiveLearningProfileReadError extends Schema.TaggedError<ActiveLearningProfileReadError>()(
@@ -47,7 +47,7 @@ export async function getLearningProgramCatalog(
4747
locale: Locale
4848
): Promise<LearningProgramCatalog> {
4949
"use cache";
50-
cacheLife("contentRuntime");
50+
applyContentRuntimeCache();
5151

5252
return await fetchQuery(api.learningPrograms.queries.listSelectablePrograms, {
5353
locale,
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {
2+
preservedProgramCatalogTableNames,
3+
resettableTableNames,
4+
} from "@repo/backend/convex/contentSync/reset/spec";
5+
import { describe, expect, it } from "vitest";
6+
7+
describe("contentSync/reset spec", () => {
8+
it("resets derived coverage while preserving referenced program catalog rows", () => {
9+
expect(resettableTableNames).toContain("learningProgramCoverage");
10+
expect(resettableTableNames).not.toContain("learningPrograms");
11+
expect(resettableTableNames).not.toContain("learningProgramSources");
12+
expect(preservedProgramCatalogTableNames).toEqual([
13+
"learningPrograms",
14+
"learningProgramSources",
15+
]);
16+
});
17+
});

packages/backend/convex/contentSync/reset/spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,17 @@ export const resettableTableNames = [
5959
] as const satisfies readonly TableNames[];
6060

6161
export type ResettableTableName = (typeof resettableTableNames)[number];
62+
63+
/**
64+
* Program catalog rows are sync-managed but intentionally preserved by the broad
65+
* content reset because learning profiles, plans, and plan items store generated
66+
* program document IDs. Coverage rows are derived from content routes and remain
67+
* reset-managed because they can be rebuilt without orphaning user state.
68+
*/
69+
export const preservedProgramCatalogTableNames = [
70+
"learningPrograms",
71+
"learningProgramSources",
72+
] as const satisfies readonly TableNames[];
73+
74+
export type PreservedProgramCatalogTableName =
75+
(typeof preservedProgramCatalogTableNames)[number];

packages/backend/scripts/sync-content/reset.test.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,27 @@ describe("sync-content reset", () => {
146146
expect(log).toHaveBeenCalledWith(" Quran Verses: 0");
147147
expect(log).toHaveBeenCalledWith(" Total derived items: 0");
148148
expect(logSuccess).toHaveBeenCalledWith(
149-
"\nDatabase is already empty. Nothing to delete."
149+
"\nReset-managed content is already empty. Nothing to delete."
150+
);
151+
expect(log).not.toHaveBeenCalledWith("\nTo delete all content, run:");
152+
});
153+
154+
it("preserves program catalog rows without treating them as reset-managed content", async () => {
155+
vi.mocked(getContentCounts).mockReturnValue(
156+
Effect.succeed({
157+
...emptyCounts,
158+
learningProgramSources: 5,
159+
learningPrograms: 4,
160+
})
161+
);
162+
163+
await Effect.runPromise(reset(config, { force: false }));
164+
165+
expect(log).toHaveBeenCalledWith(" Learning Programs: 4");
166+
expect(log).toHaveBeenCalledWith(" Learning Program Srcs: 5");
167+
expect(log).toHaveBeenCalledWith(" Preserved program catalog rows: 9");
168+
expect(logSuccess).toHaveBeenCalledWith(
169+
"\nReset-managed content is already empty. Nothing to delete."
150170
);
151171
expect(log).not.toHaveBeenCalledWith("\nTo delete all content, run:");
152172
});

packages/backend/scripts/sync-content/reset.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -446,22 +446,22 @@ export const reset = Effect.fn("sync.reset")(function* (
446446
counts.quranVerses +
447447
counts.audioContentSources +
448448
counts.contentAudios;
449+
const preservedProgramCatalog =
450+
counts.learningPrograms + counts.learningProgramSources;
449451

450452
log(`\n Total content items: ${totalContent}`);
451453
log(` Total related items: ${totalRelated}`);
452454
log(` Total runtime items: ${totalRuntime}`);
453455
log(` Total derived items: ${totalDerived}`);
454-
log(
455-
` Program catalog rows: ${counts.learningPrograms + counts.learningProgramSources}`
456-
);
456+
log(` Preserved program catalog rows: ${preservedProgramCatalog}`);
457457

458458
if (
459459
totalContent === 0 &&
460460
totalRelated === 0 &&
461461
totalRuntime === 0 &&
462462
totalDerived === 0
463463
) {
464-
logSuccess("\nDatabase is already empty. Nothing to delete.");
464+
logSuccess("\nReset-managed content is already empty. Nothing to delete.");
465465
return;
466466
}
467467

0 commit comments

Comments
 (0)