fix(api): use admin app URL for teacher auto-enroll email links (#771)
* fix(api): use admin app URL for teacher auto-enroll links Teacher payment-request emails now build course and grant-access URLs with getAppBaseUrl() instead of getDashboardBaseUrl(org), so links point at app.classroomio.com rather than a custom or tenant domain. Document the teacher vs student email link rule in AGENTS.md. Co-authored-by: Rotimi Best <[email protected]> * docs: surface email link URL rules where emails are wired Document getAppBaseUrl vs getDashboardBaseUrl in dashboard-url.ts, packages/email/README.md, enqueueTransactionalEmail JSDoc, and AGENTS.md so staff vs learner hosts are discoverable when building email links. Co-authored-by: Rotimi Best <[email protected]> --------- Co-authored-by: Cursor Agent <[email protected]> Co-authored-by: Rotimi Best <[email protected]>
This commit is contained in:
co-authored by
Rotimi Best
Cursor Agent
parent
e09b3caa8a
commit
0f23453f91
@@ -5,7 +5,7 @@ import { getCourseWithOrgData } from '@cio/db/queries/course';
|
||||
import { buildEmailFromName, buildEmailBranding } from '@cio/email';
|
||||
import { enqueueTransactionalEmail } from '@api/services/jobs';
|
||||
import { trackServerEvent, SERVER_EVENTS } from '@cio/analytics';
|
||||
import { getDashboardBaseUrl } from '@cio/core/config/dashboard-url';
|
||||
import { getAppBaseUrl } from '@cio/core/config/dashboard-url';
|
||||
|
||||
export interface PaymentRequestData {
|
||||
courseId: string;
|
||||
@@ -48,14 +48,9 @@ export async function createPaymentRequest(data: PaymentRequestData) {
|
||||
|
||||
const teacherEmail = teacherResult[0].email;
|
||||
|
||||
const dashboardOrg = {
|
||||
siteName: course.orgSiteName,
|
||||
customDomain: course.orgCustomDomain,
|
||||
isCustomDomainVerified: course.orgIsCustomDomainVerified
|
||||
};
|
||||
const dashboardBaseUrl = getDashboardBaseUrl(dashboardOrg);
|
||||
const courseUrl = `${dashboardBaseUrl}/courses/${data.courseId}`;
|
||||
const autoEnrollUrl = `${dashboardBaseUrl}/courses/${data.courseId}/people?grantAccess=${encodeURIComponent(data.studentEmail)}`;
|
||||
const appBaseUrl = getAppBaseUrl();
|
||||
const courseUrl = `${appBaseUrl}/courses/${data.courseId}`;
|
||||
const autoEnrollUrl = `${appBaseUrl}/courses/${data.courseId}/people?grantAccess=${encodeURIComponent(data.studentEmail)}`;
|
||||
|
||||
try {
|
||||
await enqueueTransactionalEmail('teacherStudentBuyRequest', {
|
||||
|
||||
@@ -59,6 +59,11 @@ function recipientKey(base: string | undefined, recipient: string, total: number
|
||||
* against the template's Zod schema up front so bad payloads fail in the
|
||||
* domain handler instead of silently inside the worker.
|
||||
*
|
||||
* **Link fields** (`courseUrl`, `autoEnrollUrl`, `loginUrl`, `inviteUrl`, etc.)
|
||||
* must be built by the caller before enqueueing. Use `getAppBaseUrl()` for
|
||||
* teacher/tutor/admin dashboard links and `getDashboardBaseUrl(org)` for
|
||||
* student/learner links — see `packages/email/README.md` § Email link URLs.
|
||||
*
|
||||
* BullMQ tracks send state, retries, and failure history — no DB ledger is
|
||||
* written. Final failures are recorded in `dead_letter_job` by the worker
|
||||
* for operator triage.
|
||||
|
||||
Reference in New Issue
Block a user