MyApp

Getting Started

IntroductionInstallationPull Updates
Architecture
Architecture OverviewProject StructureNaming ConventionsCode StyleRouting

Setup

IDEAI AgentsMCP ServersEnvironment Variables

Workflow

Git WorkflowBuild & DeployTroubleshooting

Authentication

OverviewSetup & ConfigurationUsage & IntegrationTroubleshooting

Payments

OverviewSetup & ConfigurationUsage & IntegrationTroubleshooting

Supabase

OverviewSetup & ConfigurationTroubleshooting

Database

Database SetupPrisma ORMUsage & IntegrationMigrationsTroubleshooting

Storage

OverviewSetup & ConfigurationUsage & IntegrationTroubleshooting

Emails

OverviewSetup and ConfigurationUsage and IntegrationTroubleshooting

SEO

OverviewConfiguration & Best PracticesCustomization & Optimization

UI

OverviewSetup and ConfigurationThemingTroubleshooting
MyApp
Architecture

Code Style

TypeScript patterns and component structure

Modern TypeScript and React patterns used in Plainform.

TypeScript

Type Annotations

Type annotations
// Always annotate function params and returns
function formatDate(date: Date): string {
  return new Intl.DateTimeFormat('en-US').format(date);
}

// Let TypeScript infer variables
const userName = 'John';  // string inferred
const count = 42;  // number inferred

Interfaces vs Types

Interfaces vs types
// Interfaces for objects
interface IUser {
  id: string;
  name: string;
}

// Types for unions and complex types
type Status = 'pending' | 'active' | 'inactive';
type Result<T> = { success: true; data: T } | { success: false; error: string };

Type Guards

Type guards
function isError(value: unknown): value is Error {
  return value instanceof Error;
}

if (typeof value === 'string') { }
if (Array.isArray(value)) { }

Import Organization

Import organization
// 1. External packages
import { useState } from 'react';
import { z } from 'zod';

// 2. Internal modules (use @/ alias)
import { Button } from '@/components/ui/Button';
import { prisma } from '@/lib/prisma/prisma';

// 3. Types
import type { IUser } from '@/types/UserInterfaces';

// 4. Styles
import styles from './Component.module.css';

Prefer named exports over default exports (except Next.js pages/layouts).

Component Structure

Component structure
'use client';  // Only if needed

// 1. Imports
import { useState } from 'react';
import { Button } from '@/components/ui/Button';

// 2. Interface
interface IComponentProps {
  title: string;
  isActive?: boolean;
}

// 3. Component
export function ComponentName({ title, isActive = false }: IComponentProps) {
  // 4. Hooks (always at top)
  const [state, setState] = useState(false);

  // 5. Event handlers
  const handleClick = () => {
    setState(true);
  };

  // 6. Early returns
  if (!title) return null;

  // 7. JSX
  return (
    <div>
      <h1>{title}</h1>
      <Button onClick={handleClick}>Click</Button>
    </div>
  );
}

Server vs Client Components

Server vs client components
// Server Component (default) - no 'use client'
export async function BlogList() {
  const posts = await prisma.post.findMany();
  return <div>{posts.map(post => ...)}</div>;
}

// Client Component - add 'use client'
'use client';
export function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

Use Client Components for: hooks, event handlers, browser APIs, third-party libraries.

Error Handling

Error handling in API routes
export async function POST(req: Request) {
  try {
    const body = await req.json();
    const validated = schema.parse(body);
    const result = await processData(validated);
    
    return NextResponse.json({ success: true, data: result });
  } catch (error) {
    if (error instanceof z.ZodError) {
      return NextResponse.json(
        { error: 'Validation failed', details: error.errors },
        { status: 400 }
      );
    }
    
    return NextResponse.json(
      { error: 'Internal server error' },
      { status: 500 }
    );
  }
}

Async/Await

Async/await patterns
// Prefer async/await
async function fetchData(userId: string) {
  const user = await prisma.user.findUnique({ where: { id: userId } });
  const orders = await prisma.order.findMany({ where: { userId } });
  return { user, orders };
}

// Use Promise.all() for parallel operations
async function fetchDashboard() {
  const [users, orders, products] = await Promise.all([
    prisma.user.findMany(),
    prisma.order.findMany(),
    prisma.product.findMany()
  ]);
  return { users, orders, products };
}

Best Practices

Avoid magic numbers

Use constants
const MAX_FILE_SIZE = 5 * 1024 * 1024;  // 5MB
if (file.size > MAX_FILE_SIZE) { }

Single responsibility

Single responsibility
// Each function does one thing
function validateEmail(email: string): boolean { }
function sendWelcomeEmail(email: string): Promise<void> { }

DRY (Don't Repeat Yourself)

DRY principle
function formatCurrency(amount: number): string {
  return new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD'
  }).format(amount);
}

Run npm run lint and npm run prettier before committing. Husky hooks enforce this automatically.

How is this guide ?

Last updated on

Naming Conventions

File, component, and code naming patterns

Routing

Next.js App Router structure and navigation

On this page

TypeScript
Type Annotations
Interfaces vs Types
Type Guards
Import Organization
Component Structure
Server vs Client Components
Error Handling
Async/Await
Best Practices