Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 0 additions & 36 deletions .claude/references/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ src/components/
├── contact-logs/ # Contact log CRUD feature
├── contact-lookup/ # Contact search feature
├── contact-lookup-details/ # Contact details view
├── tool/ # Tool layout components (ToolContainer, ToolHeader, ToolFooter, ToolParamsDebug)
├── user-tools-debug/ # Debug: User permissions display (dev only)
└── user-menu/ # User dropdown menu
```

Expand All @@ -42,16 +40,6 @@ src/components/
| `contact-lookup/` | Contact search with results display | Yes |
| `contact-lookup-details/` | Contact profile and logs view | Yes |
| `user-menu/` | User dropdown with sign-out | Yes |
| `tool/` | Tool layout components (ToolContainer, ToolHeader, ToolFooter, ToolParamsDebug) | No |

### Debug Components (Development Only)

| Folder | Purpose | Remove Before Production |
|--------|---------|-------------------------|
| `tool/` (ToolParamsDebug) | Displays parsed URL tool parameters | Yes |
| `user-tools-debug/` | Shows user's authorized tool paths | Yes |

**Note**: `ToolParamsDebug` is located inside the consolidated `tool/` folder alongside the other tool layout components.

### UI Components (shadcn/ui)

Expand All @@ -72,7 +60,6 @@ Actions are co-located with their feature components:
| contact-lookup | `contact-lookup/actions.ts` | `searchContacts` |
| contact-lookup-details | `contact-lookup-details/actions.ts` | `getContactDetails`, `getContactLogsByContactId` |
| user-menu | `user-menu/actions.ts` | `handleSignOut` |
| user-tools-debug | `user-tools-debug/actions.ts` | `getUserTools` |
| **shared** | `shared-actions/user.ts` | `getCurrentUserProfile` |

**Shared Actions Folder**: `src/components/shared-actions/` contains actions used across multiple features. See the README in that folder for guidelines on when to use shared vs co-located actions.
Expand All @@ -85,9 +72,6 @@ import { ContactLookup } from '@/components/contact-lookup';
import { ContactLogs } from '@/components/contact-logs';
import { UserMenu } from '@/components/user-menu';

// Tool components (use barrel export)
import { ToolContainer, ToolHeader, ToolFooter, ToolParamsDebug } from '@/components/tool';

// UI components (individual imports)
import { Button } from '@/components/ui/button';
import { Card, CardHeader, CardContent } from '@/components/ui/card';
Expand Down Expand Up @@ -136,17 +120,6 @@ All components pass the following checks:
- **dialog.tsx**: Uses mixed patterns (direct assignment vs forwardRef) - works but inconsistent.
- **tooltip.tsx**: Auto-wraps with `TooltipProvider` internally - no need to wrap manually.

### Debug Components

The `ToolParamsDebug` (inside `tool/`) and `user-tools-debug` components are marked for removal before production. They are currently used in `src/app/(web)/tools/template/template-tool.tsx`.

Consider conditional rendering:
```typescript
import { ToolParamsDebug } from '@/components/tool';

{process.env.NODE_ENV === 'development' && <ToolParamsDebug params={params} />}
```

## Quick Reference: Component Responsibilities

### contact-logs
Expand All @@ -163,14 +136,6 @@ import { ToolParamsDebug } from '@/components/tool';
- **Purpose**: Display full contact profile with associated logs
- **Features**: Profile info display, embedded ContactLogs component, loading/error states

### tool
- **Purpose**: Consolidated folder containing reusable layout components for tool interfaces
- **Components**: `ToolContainer`, `ToolHeader`, `ToolFooter`, `ToolParamsDebug`
- **Usage**: Wrap tool content with consistent header/footer styling
- **Pattern**: Composition via children prop
- **Import**: `import { ToolContainer, ToolHeader, ToolFooter, ToolParamsDebug } from '@/components/tool';`
- **Note**: `ToolParamsDebug` is a debug component for development only

### user-menu
- **Purpose**: User profile dropdown with sign-out
- **Features**: Displays user name/email, implements OIDC logout flow
Expand All @@ -184,7 +149,6 @@ Components interact with these service classes:
|---------|----------|---------|
| ContactService | `@/services/contactService` | contact-lookup, contact-lookup-details |
| ContactLogService | `@/services/contactLogService` | contact-logs |
| ToolService | `@/services/toolService` | user-tools-debug |
| UserService | `@/services/userService` | user-menu |

All services ultimately use `MPHelper` from `@/lib/providers/ministry-platform` for API calls.
2 changes: 0 additions & 2 deletions .claude/references/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,10 @@ npx vitest run --coverage --coverage.reportOnFailure
| `services/contactService.test.ts` | 10 | Contact search, getByGuid, updateContact |
| `services/contactLogService.test.ts` | 16 | Contact log CRUD, date conversion, Zod validation |
| `services/userService.test.ts` | 4 | User profile lookup |
| `services/toolService.test.ts` | 7 | Page data + user tools via stored procedures |
| `components/contact-lookup/actions.test.ts` | 5 | Search contacts action |
| `components/contact-logs/actions.test.ts` | 19 | Contact log CRUD actions with auth |
| `components/contact-lookup-details/actions.test.ts` | 10 | Contact details + log type mapping |
| `components/user-menu/actions.test.ts` | 3 | Sign-out + OAuth end session redirect |
| `components/user-tools-debug/actions.test.ts` | 4 | User tools with auth + MP lookup |
| `components/shared-actions/user.test.ts` | 2 | getCurrentUserProfile delegation |
| `proxy.test.ts` | 8 | Route protection (public paths, session, errors) |
| `lib/providers/ministry-platform/provider.test.ts` | 9 | Provider delegation to services |
Expand Down
14 changes: 12 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
# client_secret for each provider. The OIDC client_id and client_secret are
# used for user login and best practice is re-use the same one as Widgets for
# congregant-facing applications.

OIDC_CLIENT_ID=TM.Widgets
OIDC_CLIENT_SECRET=

Expand All @@ -29,11 +28,22 @@ BETTER_AUTH_URL=http://localhost:3000
# =============================================================================
# This API Client / Secret will be used for server-side data access and will be
# the user for audit log data when no userId is provided.

MINISTRY_PLATFORM_CLIENT_ID=MPNext
MINISTRY_PLATFORM_CLIENT_SECRET=
MINISTRY_PLATFORM_BASE_URL=https://mpi.ministryplatform.com/ministryplatformapi

# -----------------------------------------------------------------------------
# Development-only MinistryPlatform API credentials
# -----------------------------------------------------------------------------
# DEVELOPMENT ONLY — DO NOT USE IN PRODUCTION.
# These credentials are intended solely for local development and testing
# against a non-production MP environment. They are ignored in production
# builds and must never be deployed to production environments.
#
# Use a separate MP API Client registered against your dev/staging MP instance.
MINISTRY_PLATFORM_DEV_CLIENT_ID=MPNextDEV
MINISTRY_PLATFORM_DEV_CLIENT_SECRET=

# =============================================================================
# NEXT Public Keys
# =============================================================================
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Ministry Platform is a shared production database containing real church member
- **Critical**: `session.user.id` is Better Auth's internal ID, NOT the MP User_GUID. Use `session.user.userGuid` for all MP API lookups.
- **Stateless Sessions**: JWT cookie cache, no database; `customSession` does name splitting only (no API calls)
- **Required Environment Variables**: `MINISTRY_PLATFORM_BASE_URL`, `BETTER_AUTH_URL` (or `NEXTAUTH_URL` fallback), `BETTER_AUTH_SECRET` (or `NEXTAUTH_SECRET` fallback)
- **Services Layer**: Singleton service classes in `src/services/` wrap MPHelper for domain logic (ContactService, ContactLogService, ToolService, UserService)
- **Services Layer**: Singleton service classes in `src/services/` wrap MPHelper for domain logic (ContactService, ContactLogService, UserService)
- **Contexts**: React context providers in `src/contexts/` (UserProvider) composed in `src/app/providers.tsx`; `useAppSession()` wraps Better Auth's `authClient.useSession()`
- **UI**: Radix UI primitives + shadcn/ui components in `src/components/ui/`, Tailwind CSS v4
- **Validation**: Zod v4 (`zod@^4.3`) — note: different API from Zod v3 (e.g., `z.object()` vs `z.interface()`)
Expand Down
70 changes: 10 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
# MPNext

[![Release](https://img.shields.io/github/v/release/MinistryPlatform-Community/MPNext?logo=github)](https://github.com/MinistryPlatform-Community/MPNext/releases/latest)
[![Tests](https://github.com/MinistryPlatform-Community/MPNext/actions/workflows/test.yml/badge.svg)](https://github.com/MinistryPlatform-Community/MPNext/actions/workflows/test.yml)
[![codecov](https://codecov.io/gh/MinistryPlatform-Community/MPNext/graph/badge.svg)](https://codecov.io/gh/MinistryPlatform-Community/MPNext)
[![Version](https://img.shields.io/github/v/release/MinistryPlatform-Community/MPNext)](https://github.com/MinistryPlatform-Community/MPNext/releases/latest)

[![Next.js](https://img.shields.io/badge/Next.js-16-black?logo=next.js)](https://nextjs.org/)
[![React](https://img.shields.io/badge/React-19-61DAFB?logo=react&logoColor=white)](https://react.dev/)
[![TypeScript](https://img.shields.io/badge/TypeScript-6.0-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
[![Tailwind CSS](https://img.shields.io/badge/Tailwind_CSS-v4-06B6D4?logo=tailwindcss&logoColor=white)](https://tailwindcss.com/)
[![shadcn/ui](https://img.shields.io/badge/shadcn%2Fui-new--york-000000?logo=shadcnui&logoColor=white)](https://ui.shadcn.com/)
[![Radix UI](https://img.shields.io/badge/Radix_UI-primitives-161618?logo=radixui&logoColor=white)](https://www.radix-ui.com/)
[![Lucide](https://img.shields.io/badge/Lucide-icons-F56565?logo=lucide&logoColor=white)](https://lucide.dev/)

A modern Next.js application integrated with Ministry Platform authentication and REST API, built with TypeScript, Next.js 16, React 19, and Better Auth.

Expand Down Expand Up @@ -36,7 +44,6 @@ A modern Next.js application integrated with Ministry Platform authentication an
- **Schema Documentation**: Auto-generated markdown documentation with type file links
- **Validation**: Optional Zod v4 schema validation in MPHelper for runtime data validation before API calls
- **Testing**: Vitest test framework with comprehensive coverage for auth, proxy, and API services
- **Tools Framework**: Reusable tool components for building Ministry Platform page tools

## Architecture

Expand Down Expand Up @@ -303,8 +310,6 @@ MPNext/
│ │ │ ├── contactlookup/ # Contact lookup demo
│ │ │ │ └── [guid]/ # Dynamic contact detail page
│ │ │ ├── home/ # Home redirect
│ │ │ ├── tools/ # Tools framework
│ │ │ │ └── template/ # Template tool example
│ │ │ ├── layout.tsx # Web layout with auth
│ │ │ └── page.tsx # Dashboard/home page
│ │ ├── api/auth/[...all]/ # Better Auth API routes
Expand Down Expand Up @@ -333,20 +338,10 @@ MPNext/
│ │ │ ├── header.tsx
│ │ │ ├── sidebar.tsx
│ │ │ └── index.ts
│ │ ├── tool/ # Tool framework components
│ │ │ ├── tool-container.tsx
│ │ │ ├── tool-header.tsx
│ │ │ ├── tool-footer.tsx
│ │ │ ├── tool-params-debug.tsx
│ │ │ └── index.ts
│ │ ├── user-menu/ # User menu feature
│ │ │ ├── user-menu.tsx
│ │ │ ├── actions.ts
│ │ │ └── index.ts
│ │ ├── user-tools-debug/ # Development debug helper
│ │ │ ├── user-tools-debug.tsx
│ │ │ ├── actions.ts
│ │ │ └── index.ts
│ │ ├── shared-actions/ # Cross-feature server actions
│ │ │ └── user.ts
│ │ └── ui/ # shadcn/ui components (19 components)
Expand All @@ -363,7 +358,6 @@ MPNext/
│ │ │ ├── contacts.ts
│ │ │ ├── contact-logs.ts
│ │ │ └── index.ts
│ │ ├── tool-params.ts # Tool parameter utilities
│ │ ├── utils.ts # General utilities
│ │ └── providers/
│ │ └── ministry-platform/ # Ministry Platform provider
Expand All @@ -390,8 +384,7 @@ MPNext/
│ ├── services/ # Application services
│ │ ├── contactService.ts
│ │ ├── contactLogService.ts
│ │ ├── userService.ts
│ │ └── toolService.ts
│ │ └── userService.ts
│ │
│ ├── auth.test.ts # Auth tests
│ ├── proxy.ts # Next.js 16 proxy (route protection)
Expand Down Expand Up @@ -537,12 +530,6 @@ Built with Radix UI primitives and styled with Tailwind CSS. Located in `src/com
- **contact-logs**: Full CRUD for contact interaction history
- **user-menu**: User profile dropdown with sign-out

### Tool Components (`src/components/tool/`)
- **ToolContainer**: Main wrapper for tool pages
- **ToolHeader**: Tool title bar with optional info tooltip
- **ToolFooter**: Save/Close action buttons
- **ToolParamsDebug**: Development helper for debugging URL parameters

All components follow kebab-case naming and use named exports for consistency.

## Services
Expand All @@ -554,41 +541,9 @@ Application services provide business logic abstraction over the Ministry Platfo
| **ContactService** | `contactService.ts` | Contact search and updates |
| **ContactLogService** | `contactLogService.ts` | Contact log CRUD with validation |
| **UserService** | `userService.ts` | User profile retrieval |
| **ToolService** | `toolService.ts` | Tool page data and user permissions |

All services follow the singleton pattern and use `MPHelper` for API communication.

## Building Custom Tools

### Template Tool

The project includes a template tool (`src/app/(web)/tools/template/`) that demonstrates best practices for building Ministry Platform tools that can be launched from within MP pages.

**Key features:**
- URL parameter parsing for MP page context (`pageID`, record selection, etc.)
- Dual-mode support (create new vs. edit existing records)
- Standard tool UI with save/close actions
- Development helpers for debugging tool params and user context
- Integration with `ToolContainer` component for consistent UX

**Structure:**
```
src/app/(web)/tools/template/
├── page.tsx # Server component that parses URL params
└── template-tool.tsx # Client component with tool UI
```

**Usage as a starting point:**
1. Copy the `template` folder to create your new tool
2. Rename files and components appropriately
3. Implement your tool logic inside the `ToolContainer`
4. Remove `ToolParamsDebug` and `UserToolsDebug` before production

**URL Parameters:**
Tools receive standard MP parameters like `pageID`, `s` (selection), and `recordDescription`. Use `parseToolParams()` to handle them consistently.

See the [template tool](src/app/(web)/tools/template/) for implementation details.

## Testing

The project uses **Vitest 4.0** with comprehensive test coverage for critical functionality.
Expand Down Expand Up @@ -765,7 +720,6 @@ import { MPHelper } from '@/lib/providers/ministry-platform';
import { Button } from '@/components/ui/button';
import { ContactSearch } from '@/lib/dto';
import { Header, Sidebar } from '@/components/layout';
import { ToolContainer } from '@/components/tool';
```

### Component Style
Expand All @@ -788,7 +742,6 @@ src/components/
├── shared-actions/ # Cross-feature server actions
├── ui/ # shadcn/ui components
├── layout/ # Layout components (header, sidebar, etc.)
├── tool/ # Tool framework components
├── feature-name/ # Feature folder (kebab-case)
│ ├── feature-name.tsx # Main component
│ ├── actions.ts # Feature-specific server actions
Expand All @@ -805,9 +758,6 @@ import { UserMenu } from '@/components/user-menu';
// Import layout components
import { Header, Sidebar, AuthWrapper } from '@/components/layout';

// Import tool components
import { ToolContainer, ToolParamsDebug } from '@/components/tool';

// Import application DTOs
import { ContactSearch, ContactLookupDetails } from '@/lib/dto';

Expand Down
2 changes: 1 addition & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import nextTs from "eslint-config-next/typescript";
const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
globalIgnores([".next/**", "out/**", "build/**", "next-env.d.ts"]),
globalIgnores([".next/**", "out/**", "build/**", "coverage/**", "next-env.d.ts"]),
]);

export default eslintConfig;
2 changes: 1 addition & 1 deletion next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";
import "./.next/dev/types/routes.d.ts";

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
Loading
Loading