Skip to content

Comments

feat(auth): add register API route#54

Merged
chemist-god merged 19 commits intomainfrom
feature/invite
Nov 22, 2025
Merged

feat(auth): add register API route#54
chemist-god merged 19 commits intomainfrom
feature/invite

Conversation

@chemist-god
Copy link
Owner

Invite & Auth: invite APIs, landing pages, and social-share improvements

Summary

This PR implements a complete invite flow (API endpoints, landing pages, and client components), updates authentication/signup to integrate invites, enhances stake-sharing endpoints, and improves social sharing UI and service logic. These changes enable invite-based onboarding, better share metadata/links across platforms, and new UI for managing invitations.


What changed (high level)

Backend / API

  • src/app/api/auth/register/route.ts — update/add registration behavior to support invite association
  • src/app/api/invite/[code]/accept/route.ts — accept invite by code
  • src/app/api/invite/[code]/route.ts — lookup invite details by code
  • src/app/api/invite/code/route.ts — generate invite codes
  • src/app/api/invite/invitations/route.ts — create/list invitations
  • src/app/api/invite/stats/route.ts — invite metrics endpoint
  • src/app/api/stakes/[id]/share/route.ts — improve stake share endpoint (metadata / platform links)
  • src/app/api/stakes/route.ts — stakes collection improvements for invites/sharing

Frontend / Pages / Components

  • src/app/invite/[code]/page.tsx — invite landing page
  • src/app/stakes/invite/[id]/page.tsx — stake invite page updates
  • src/app/auth/signup/page.tsx — signup adjustments to accept invites
  • New components:
    • src/components/invite/InviteLandingClient.tsx
    • src/components/invite/PlatformInviteLanding.tsx
    • src/components/settings/InvitationManagement.tsx
  • Updates:
    • src/components/settings/InviteFriendsSettings.tsx
    • src/components/stakes/EnhancedSocialShare.tsx
    • src/components/stakes/EnhancedUniversalShareModal.tsx

Libraries / Services

  • src/lib/social-share-service.ts — updated logic for building share metadata, platform links, and invite-aware sharing behavior

Why

  • Provide a robust invite flow for user acquisition and friend referrals (code generation, landing/accept, stats).
  • Surface invites in onboarding and stake flows to boost conversion.
  • Improve social sharing reliability and metadata across platforms to increase click-through and correct behavior on different devices and social channels.
  • Add invite management UI for admins/users to manage invites.

How to test (smoke checklist)

  1. Start dev server:

    • npm run dev
  2. Invite API checks

    • Generate a code:
      curl -X POST http://localhost:3000/api/invite/code -H "Content-Type: application/json" -d '{}'
      • Verify response contains an invite code.
    • Create and list invites:
      curl -X POST http://localhost:3000/api/invite/invitations -H "Content-Type: application/json" -d '{"targetEmail":"test@example.com"}'
      curl http://localhost:3000/api/invite/invitations
    • Accept invite:
      curl -X POST http://localhost:3000/api/invite/<code>/accept -H "Content-Type: application/json" -d '{"userId":"<id>"}'
      • Confirm the invite is consumed and user association occurs (or expected join behavior).
    • Check stats:
      curl http://localhost:3000/api/invite/stats
  3. Invite landing page

    • Visit http://localhost:3000/invite/<code> in a browser.
    • Confirm the landing CTA shows invite details and routes to signup/sign-in if needed.
  4. Signup flow

    • Go through /auth/signup while carrying an invite code; ensure the created account is associated with the invite (or the UI highlights invite benefits).
  5. Share & stake flows

    • Use the stake share modal and confirm that:
      • The share endpoint (/api/stakes/[id]/share) returns proper metadata.
      • Platform links (Twitter, WhatsApp, copy link) include invite/referral when appropriate.
    • Validate EnhancedSocialShare and EnhancedUniversalShareModal render correctly and produce expected share data.
  6. UI sanity checks

    • Open InvitationManagement and InviteFriendsSettings pages; verify lists, actions (revoke/resend), and toggles work.
  7. Lint & tests

    • npm run lint
    • npm test (if available)

Database / Migrations

  • This PR does not intentionally include any schema-breaking changes. If migration files are present, run:
    • npx prisma generate
    • Local: npx prisma db push
    • Staging/Prod: npx prisma migrate deploy

If any DB errors occur, report them and we can prepare a migration or revert strategy.


Review notes / Focus areas

  • Invite acceptance edge cases:
    • Expired codes
    • Already-accepted codes
    • Wrong-account acceptance attempts
  • Security:
    • Ensure invite tokens/codes are validated and not logged in plaintext
    • Rate-limit code generation endpoints if necessary
  • Sharing logic:
    • Verify metadata and de-duplication across platforms (mobile vs desktop link previews)
  • Signup flow:
    • Confirm it doesn’t regress non-invite signups or social login flows
  • Integration:
    • Make sure share URLs and landing page behavior works with deployed domains (env/runtime link generation)

@chemist-god chemist-god requested a review from Copilot November 21, 2025 00:12
@vercel
Copy link

vercel bot commented Nov 21, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
smart-todo Error Error Nov 22, 2025 0:16am
smart-todo-wum3 Error Error Nov 22, 2025 0:16am

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements a comprehensive invite system for the Smart Todo platform, integrating invite flows for both platform-level and stake-specific invitations. The changes enable users to invite friends via unique codes, track invitation metrics, and accept invitations during signup or while logged in.

Key Changes:

  • Added complete invite API infrastructure with code generation, lookup, acceptance, and statistics endpoints
  • Integrated invite codes into the signup/registration flow with automatic invitation acceptance
  • Enhanced social sharing with security codes for more secure and trackable stake invitations
  • Added UI components for managing invitations and displaying invite landing pages

Reviewed Changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 25 comments.

Show a summary per file
File Description
src/app/api/auth/register/route.ts Extended registration to accept and validate invite codes, automatically linking new users to their inviters
src/app/api/invite/[code]/route.ts Unified endpoint to fetch invitation details for both platform and stake invitations by code
src/app/api/invite/[code]/accept/route.ts Handles platform invitation acceptance with validation and referral tracking
src/app/api/invite/code/route.ts Generates and retrieves user referral codes, creates platform invitations
src/app/api/invite/invitations/route.ts CRUD operations for managing user's sent invitations (list, resend, cancel)
src/app/api/invite/stats/route.ts Provides referral statistics including invitation counts, acceptance rates, and view metrics
src/app/api/stakes/[id]/share/route.ts Changed from POST to GET; returns shareable links with security codes for stake invitations
src/app/api/stakes/route.ts Pre-generates public stake invitations with security codes during SOCIAL_STAKE creation
src/app/invite/[code]/page.tsx Unified landing page that routes to appropriate invite component based on invitation type
src/app/stakes/invite/[id]/page.tsx Redirects legacy stake invite URLs to new unified invite route using security codes
src/app/auth/signup/page.tsx Captures invite codes from URL parameters and passes them to registration endpoint
src/components/invite/InviteLandingClient.tsx Client component for stake invitation landing pages with auto-accept functionality
src/components/invite/PlatformInviteLanding.tsx Client component for platform invitation landing pages with authentication flow
src/components/settings/InvitationManagement.tsx New UI for managing sent invitations with filtering, resending, and cancellation
src/components/settings/InviteFriendsSettings.tsx Updated to fetch real stats from API and embed invitation management component
src/components/stakes/EnhancedSocialShare.tsx Fetches and uses security codes for generating shareable stake URLs
src/components/stakes/EnhancedUniversalShareModal.tsx Updated to use security codes in QR codes, direct links, and embed codes
src/lib/social-share-service.ts Enhanced to generate URLs using security codes when available, falling back to stake IDs
.gitignore Added documentation file to ignore list
Comments suppressed due to low confidence (1)

src/components/settings/InvitationManagement.tsx:59

  • Unused variable url.
            const url = type ? `/api/invite/invitations?type=${type}` : '/api/invite/invitations?type=PLATFORM';

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +42 to +49
useEffect(() => {
if (typeof window !== "undefined" && session && invitation?.status === 'PENDING') {
const params = new URLSearchParams(window.location.search);
if (params.get("autoAccept") === "1" && !accepting) {
handleAccept();
}
}
}, [session, invitation]);
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

The useEffect has a missing dependency: handleAccept. Either include it in the dependency array or wrap the function in useCallback. Additionally, the dependency array [session, invitation] should also include accepting to prevent calling handleAccept multiple times while a request is in progress.

Copilot uses AI. Check for mistakes.
Copy link
Owner Author

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

data: {
stakeId: stake.id,
inviterId: stake.userId,
inviteeEmail: 'public@share.com', // Placeholder for public shares
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

The placeholder email 'public@share.com' is hardcoded here, which creates a magic string that's repeated across multiple files (also in /api/stakes/route.ts and /api/stakes/[id]/share/route.ts). This should be extracted to a constant in a shared location to improve maintainability and reduce the risk of typos.

Copilot uses AI. Check for mistakes.
Copy link
Owner Author

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

Comment on lines 8 to 9
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || process.env.VERCEL_URL || 'http://localhost:3000';

Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

The server component fetches data using fetch with baseUrl constructed from environment variables. However, on server-side, NEXT_PUBLIC_BASE_URL or VERCEL_URL might not include the protocol (http/https), especially for VERCEL_URL. This could result in malformed URLs like vercel-deployment.vercel.app/api/invite/... instead of https://vercel-deployment.vercel.app/api/invite/.... Consider adding protocol handling or using a more robust URL construction method.

Suggested change
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || process.env.VERCEL_URL || 'http://localhost:3000';
let baseUrl = process.env.NEXT_PUBLIC_BASE_URL || process.env.VERCEL_URL || 'http://localhost:3000';
// Ensure baseUrl includes protocol
if (!/^https?:\/\//i.test(baseUrl)) {
baseUrl = `https://${baseUrl}`;
}

Copilot uses AI. Check for mistakes.

await prisma.stakeInvitation.update({
where: { id: invitationId },
data: { status: 'DECLINED' } // Use DECLINED for cancelled stake invitations
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

The status update to 'DECLINED' is used for cancelled stake invitations, but 'DECLINED' typically means the invitee rejected the invitation, not that the inviter cancelled it. Consider using 'CANCELLED' for consistency with platform invitations, or ensure the schema supports 'CANCELLED' status for stake invitations as well.

Suggested change
data: { status: 'DECLINED' } // Use DECLINED for cancelled stake invitations
data: { status: 'CANCELLED' } // Use CANCELLED for cancelled stake invitations

Copilot uses AI. Check for mistakes.
Comment on lines 61 to 62
// Check if this invitation was already accepted by someone else
if (invitation.acceptedBy) {
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

This check prevents multiple users from accepting the same invitation, but it doesn't handle the case where inviteeEmail is set to a specific email. Platform invitations can be accepted by anyone if no inviteeEmail is specified, but when an inviteeEmail is set, only one person should accept it. However, the current logic allows the same invitation code to be accepted only once regardless of whether it was targeted. Consider whether this is the intended behavior - if invitations without inviteeEmail should be reusable codes, this check would prevent that.

Suggested change
// Check if this invitation was already accepted by someone else
if (invitation.acceptedBy) {
// For invitations with inviteeEmail, only allow one acceptance
if (invitation.inviteeEmail && invitation.acceptedBy) {

Copilot uses AI. Check for mistakes.
"use client";

import React, { useState, useEffect } from "react";
import { signIn, useSession } from "next-auth/react";
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

Unused import signIn.

Suggested change
import { signIn, useSession } from "next-auth/react";
import { useSession } from "next-auth/react";

Copilot uses AI. Check for mistakes.
}

export default function PlatformInviteLanding({ invitation, error }: PlatformInviteLandingProps) {
const { data: session, status: sessionStatus } = useSession();
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

Unused variable sessionStatus.

Suggested change
const { data: session, status: sessionStatus } = useSession();
const { data: session } = useSession();

Copilot uses AI. Check for mistakes.
export default function PlatformInviteLanding({ invitation, error }: PlatformInviteLandingProps) {
const { data: session, status: sessionStatus } = useSession();
const router = useRouter();
const [loading, setLoading] = useState(false);
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

Unused variable loading.

Suggested change
const [loading, setLoading] = useState(false);

Copilot uses AI. Check for mistakes.
export default function PlatformInviteLanding({ invitation, error }: PlatformInviteLandingProps) {
const { data: session, status: sessionStatus } = useSession();
const router = useRouter();
const [loading, setLoading] = useState(false);
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

Unused variable setLoading.

Suggested change
const [loading, setLoading] = useState(false);

Copilot uses AI. Check for mistakes.
TrashIcon,
EyeIcon
} from "@heroicons/react/24/outline";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

Unused imports CardDescription, CardHeader, CardTitle.

Suggested change
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Card, CardContent } from "@/components/ui/card";

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI commented Nov 22, 2025

@chemist-god I've opened a new pull request, #55, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link

Copilot AI commented Nov 22, 2025

@chemist-god I've opened a new pull request, #56, to work on those changes. Once the pull request is ready, I'll request review from you.

@chemist-god chemist-god merged commit 5cba20a into main Nov 22, 2025
1 of 3 checks passed
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.

2 participants