Skip to content

Checkout backend actions#56

Open
thomasballarddev wants to merge 2 commits into
developfrom
feature/49-backend-actions
Open

Checkout backend actions#56
thomasballarddev wants to merge 2 commits into
developfrom
feature/49-backend-actions

Conversation

@thomasballarddev
Copy link
Copy Markdown

@thomasballarddev thomasballarddev commented Apr 18, 2026

Closes #49

Overview

Implements the backend actions for checking out coaching sessions (private lessons) and service bookings (programs).

Testing

Manual

Checklist

  • [ X ] Code is neat, readable, and works
  • [ X ] Code is commented where appropriate and well-documented
  • [ X ] Commit messages follow our guidelines
  • [ X ] Issue number is linked
  • [ X ] Branch is linked
  • [ X ] Reviewers are assigned (one of your tech leads)

Tip: You can make the issue and then check them after the fact or replace [ ] with [x] to check it!

Notes

{Any issues/suggestions relating to the ticket, repo, assignments, TL duties; please mention here!}

@RenaudBernier RenaudBernier changed the base branch from main to dev April 19, 2026 15:01
@RenaudBernier RenaudBernier changed the title [DRAFT] Feature/49 backend actions [DRAFT] Checkout backend actions Apr 19, 2026
Comment on lines +14 to +20
async function getDefaultPriceId(stripeProductId: string) {
const product = await stripe.products.retrieve(stripeProductId);
const defaultPrice = product.default_price;
if (typeof defaultPrice === "string") return defaultPrice;
return (defaultPrice as Stripe.Price | null)?.id ?? null;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should actions.ts only be for writes and maybe have a dedicated queries.ts for reads? also maybe we can use this instead?

https://github.com/hack4impact/mcld-project/pull/55/changes#diff-a1f48e30688a36b94c8e7eee51cc927f8e9ae87e7a37bf957a8db7bec0f672bbR196

Comment on lines +62 to +64
const service = await db.query.services.findFirst({
where: eq(services.id, serviceId),
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +123 to +125
const service = await db.query.services.findFirst({
where: eq(services.id, row.serviceId),
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as previous comment

@achneerov
Copy link
Copy Markdown

Honestly I would wait until this PR is merged #55, feels like life would be easier, then rebase onto dev

@thomasballarddev thomasballarddev force-pushed the feature/49-backend-actions branch from cac31f8 to 06b0440 Compare May 6, 2026 23:35
…is branch (services enum, title, description, price, isactive, stripe product id, status). Added relationship of coach id to profile (will discuss). added stripeorderid to servicebookings. stripeorderid to coaching services.
@thomasballarddev thomasballarddev force-pushed the feature/49-backend-actions branch from 06b0440 to 777721d Compare May 12, 2026 16:19
@thomasballarddev thomasballarddev changed the title [DRAFT] Checkout backend actions Checkout backend actions May 12, 2026
Copy link
Copy Markdown
Contributor

@martin0024 martin0024 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job thomas.
One concern:
Stripe retries checkout.session.completed regularly imagine if a later state (refund, cancellation) has already moved the row, a retry will re-flip it to confirmed or pending. Scope the update with and(eq(id,…), eq(status, 'awaiting_payment')) please.

Comment on lines +14 to +19
async function getDefaultPriceId(stripeProductId: string) {
const product = await stripe.products.retrieve(stripeProductId);
const defaultPrice = product.default_price;
if (typeof defaultPrice === "string") return defaultPrice;
return (defaultPrice as Stripe.Price | null)?.id ?? null;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
async function getDefaultPriceId(stripeProductId: string) {
const product = await stripe.products.retrieve(stripeProductId);
const defaultPrice = product.default_price;
if (typeof defaultPrice === "string") return defaultPrice;
return (defaultPrice as Stripe.Price | null)?.id ?? null;
}
async function getDefaultPriceId(stripeProductId: string): Promise<string> {
const product = await stripe.products.retrieve(stripeProductId);
const defaultPriceId = product.default_price;
if (!defaultPriceId) {
throw new Error(`Stripe product ${stripeProductId} has no default price`);
}
return defaultPriceId as string;
}

params.userId,
params.email,
);
const origin = (await headers()).get("origin") ?? "";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const origin = (await headers()).get("origin") ?? "";
const origin = getRequestOrigin();
function getRequestOrigin(): string {
  const origin = headers().get("origin");
  if (!origin) {
    throw new Error("Missing request origin");
  }
  return origin;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A row is inserted with awaiting_payment before the Stripe call. Abandoned checkouts leave permanent orphan rows.

Why does checkoutServiceBooking deletes the booking row if Stripe fails but checkoutCoachingSession does not?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants