Skip to main content
This guide provides a comprehensive overview of the DPM Delivery Mobile app’s project structure, file organization, and naming conventions.

Root Structure

dpm-parcel-delivery-app/
├── src/                    # Source code
├── android/                # Android native project
├── ios/                    # iOS native project
├── scripts/                # Build and utility scripts
├── .vscode/                # VS Code configuration
├── app.json                # Expo configuration
├── package.json            # Dependencies and scripts
├── bun.lock                # Bun lockfile
├── tsconfig.json           # TypeScript configuration
├── metro.config.js         # Metro bundler configuration
├── eslint.config.js        # ESLint configuration
└── .gitignore              # Git ignore rules

Source Directory Structure

The src/ directory contains all application source code:
src/
├── app/                    # Expo Router screens (file-based routing)
│   ├── (public)/           # Unauthenticated routes
│   │   ├── (auth)/         # Authentication screens
│   │   │   └── sign-in.tsx
│   │   └── _layout.tsx
│   ├── (parcel)/           # Authenticated routes
│   │   ├── (tabs)/         # Bottom tab navigation
│   │   │   ├── index.tsx   # Home screen
│   │   │   ├── history.tsx # Order history
│   │   │   ├── transactions.tsx
│   │   │   ├── profile.tsx
│   │   │   └── _layout.tsx
│   │   ├── (stack)/        # Stack navigation
│   │   │   ├── request-payment.tsx
│   │   │   ├── shipments/[reference]/
│   │   │   │   └── index.tsx  # Shipment details
│   │   │   └── _layout.tsx
│   │   └── _layout.tsx
│   └── _layout.tsx         # Root layout
├── components/             # Reusable UI components
│   ├── ui/                 # Base UI components
│   ├── providers/          # React context providers
│   └── image-picker/       # Feature-specific components
├── constants/              # App-wide constants and configuration
├── hooks/                  # Custom React hooks
│   └── api/                # API-related hooks
├── lib/                    # Third-party library configurations
│   ├── tanstack-query/     # React Query setup
│   ├── payment-gateways/   # Payment integrations
│   └── logger/             # Logging utilities
├── modules/                # Feature modules
│   ├── auth/               # Authentication module
│   └── dashboard/          # Dashboard module
├── services/               # API services and HTTP clients
│   ├── api/                # API endpoints and configuration
│   ├── auth/               # Auth service
│   ├── shipments/          # Shipments service
│   ├── payment/            # Payment service
│   ├── users/              # Users service
│   └── http.service.ts     # Base HTTP client
├── types/                  # TypeScript type definitions
│   └── enums/              # Enums and constants
├── utils/                  # Utility functions
├── global.css              # Global styles (Tailwind + Uniwind)
└── uniwind-types.d.ts      # Auto-generated Uniwind types

Directory Breakdown

app/

File-based routing powered by Expo Router. Routes are automatically generated from the file structure.

Route Groups

Parentheses () create route groups without adding to the URL:
app/
├── (public)/              # URL: /
│   └── (auth)/
│       └── sign-in.tsx    # URL: /sign-in
└── (parcel)/              # URL: / (authenticated)
    ├── (tabs)/
    │   ├── index.tsx      # URL: /
    │   └── history.tsx    # URL: /history
    └── (stack)/
        └── request-payment.tsx  # URL: /request-payment

Dynamic Routes

Brackets [] create dynamic route segments:
shipments/[reference]/index.tsx
# Matches: /shipments/abc123
# Access via: useLocalSearchParams<{ reference: string }>()

Layout Files

_layout.tsx files define shared layouts for route groups:
app/_layout.tsx
export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen name="(public)" options={{ headerShown: false }} />
      <Stack.Screen name="(parcel)" options={{ headerShown: false }} />
    </Stack>
  );
}

components/

Reusable UI components organized by function:
components/
├── ui/                     # Base components
│   ├── input.tsx           # Input field component
│   ├── alert.tsx           # Alert component
│   └── icon-symbol.tsx     # Icon component
├── form-field.tsx          # Form field with validation
├── select-field.tsx        # Select dropdown
├── shipment-card.tsx       # Shipment display card
├── themed-text.tsx         # Theme-aware text
├── themed-view.tsx         # Theme-aware view
└── providers/              # Context providers
    └── index.tsx

Component Naming

  • Use PascalCase for component files: FormField.tsx or form-field.tsx
  • Export components with PascalCase: export function FormField()
  • Use descriptive names that indicate purpose
Example Component:
components/form-field.tsx
import { useController, type Control } from "react-hook-form";
import { Input, type InputProps } from "./ui/input";

interface FormFieldProps extends InputProps {
  control: Control<any, any, any>;
  name: string;
  defaultValue?: any;
}

export function FormField(props: FormFieldProps) {
  const { control, name, defaultValue, ...inputProps } = props;
  const { field, fieldState } = useController({
    control,
    name,
    defaultValue,n  });

  return (
    <Input
      onChangeText={field.onChange}
      value={field.value}
      errorMessage={fieldState.error?.message}
      isInvalid={!!fieldState.error}
      {...inputProps}
    />
  );
}

services/

API services handle all backend communication:
services/
├── api/
│   ├── end-points.ts       # API endpoint definitions
│   └── index.ts            # API exports
├── auth/
│   ├── auth.service.ts     # Authentication methods
│   └── interface.ts        # Auth types
├── shipments/
│   ├── shipments.service.ts
│   └── interface.ts
├── payment/
│   ├── payment.service.ts
│   └── interface.ts
├── users/
│   ├── users.service.ts
│   └── interface.ts
└── http.service.ts         # Base HTTP client (Axios)

Service Pattern

Each service follows a consistent structure:
  1. interface.ts - Type definitions
  2. [name].service.ts - Service implementation
  3. Uses base http.service.ts for requests
Example Service:
services/auth/auth.service.ts
import { httpService } from "../http.service";
import type { LoginRequest, LoginResponse } from "./interface";
import { API_ENDPOINTS } from "../api/end-points";

export const authService = {
  login: async (data: LoginRequest) => {
    return httpService.post<LoginResponse>(
      API_ENDPOINTS.auth.login,
      data
    );
  },
  
  logout: async () => {
    return httpService.post(API_ENDPOINTS.auth.logout);
  },
};

modules/

Feature-specific logic organized by domain:
modules/
├── auth/
│   ├── hooks/              # Auth-specific hooks
│   ├── components/         # Auth-specific components
│   └── utils/              # Auth utilities
└── dashboard/
    ├── components/
    └── hooks/
Modules group related functionality for a specific feature, keeping code modular and maintainable.

types/

TypeScript type definitions and enums:
types/
├── enums/
│   ├── shipment.enum.ts    # Shipment status enums
│   ├── payout-enums.ts     # Payout type enums
│   └── index.enum.ts       # Enum exports
├── auth.types.ts           # Authentication types
├── shipment.types.ts       # Shipment types
├── payout.types.ts         # Payout types
├── transactions.types.ts   # Transaction types
├── users.types.ts          # User types
├── wallet.types.ts         # Wallet types
└── index.ts                # Type exports

Type Naming Conventions

  • Interfaces and types use PascalCase: User, ShipmentDetails
  • Enums use PascalCase: ShipmentStatus
  • Enum values use SCREAMING_SNAKE_CASE: IN_TRANSIT, DELIVERED
Example Types:
types/shipment.types.ts
import { ShipmentStatus } from "./enums/shipment.enum";

export interface Shipment {
  id: string;
  reference: string;
  status: ShipmentStatus;
  recipientName: string;
  recipientPhone: string;
  deliveryAddress: string;
  amount: number;
  createdAt: string;
}

export interface ShipmentUpdateRequest {
  status: ShipmentStatus;
  notes?: string;
  photos?: string[];
}

lib/

Third-party library configurations and wrappers:
lib/
├── tanstack-query/
│   ├── client.ts           # Query client configuration
│   └── options.ts          # Default query options
├── payment-gateways/
│   └── paystack/
│       └── config.ts
└── logger/
    └── index.ts            # Logging utility

utils/

Utility functions and helpers:
utils/
├── env.ts                  # Environment variable validation
├── storage.ts              # MMKV storage wrapper
├── web-crypto.ts           # Web encryption utilities
├── currency.ts             # Currency formatting
├── validation.ts           # Validation helpers
├── validation-rules.ts     # Form validation rules
├── errors.ts               # Error handling
├── style.ts                # Style utilities
├── common.ts               # Common utilities
└── enum-helpers.ts         # Enum utility functions

Utility Naming

  • Use descriptive, action-oriented names
  • Group related utilities in the same file
  • Export individual functions, not default exports
Example Utility:
utils/currency.ts
import { AppConfig } from "@/constants/config";

export function formatCurrency(amount: number): string {
  return `${AppConfig.currency.symbol}${amount.toFixed(2)}`;
}

hooks/

Custom React hooks:
hooks/
├── api/
│   └── use-verify-phone-number.ts
├── use-theme-color.ts
├── use-color-scheme.ts
├── use-color-scheme.web.ts  # Platform-specific
└── use-error-handler.ts

Hook Naming

  • All hooks start with use: useThemeColor, useAuth
  • Use kebab-case for filenames: use-theme-color.ts
  • Platform-specific hooks use extensions: .ios.ts, .android.ts, .web.ts

constants/

App-wide constants and configuration:
constants/
├── config.ts               # App configuration (currency, etc.)
└── theme.ts                # Theme colors and fonts

File Naming Conventions

General Rules

  • Use kebab-case for file and folder names: user-profile.tsx
  • Use PascalCase for component exports: UserProfile
  • Use descriptive names that indicate file purpose
  • Add .ios, .android, .web extensions for platform-specific files

Examples

✅ Good:
components/form-field.tsx
services/auth/auth.service.ts
hooks/use-theme-color.ts
types/shipment.types.ts

❌ Avoid:
components/FormField.tsx (inconsistent casing)
services/authService.ts (missing structure)
hooks/ThemeColor.ts (missing 'use' prefix)
types/shipmentTypes.ts (inconsistent pattern)

Module Organization

Feature-First Structure

Organize by feature when complexity increases:
features/
├── shipments/
│   ├── components/
│   ├── hooks/
│   ├── services/
│   ├── types/
│   └── utils/
└── payments/
    ├── components/
    ├── hooks/
    └── services/

Shared vs. Feature-Specific

  • Shared (components/, hooks/, utils/): Used across multiple features
  • Feature-specific (modules/, features/): Used within a single feature

Import Path Aliases

The project uses @/ alias for imports:
// Instead of:
import { ENV } from "../../../utils/env";

// Use:
import { ENV } from "@/utils/env";
Configured in tsconfig.json:
{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

Best Practices

1. Keep Components Small

Break large components into smaller, focused pieces:
// ❌ Large component
function ShipmentDetails() {
  return (
    <View>
      {/* 200 lines of JSX */}
    </View>
  );
}

// ✅ Broken into smaller components
function ShipmentDetails() {
  return (
    <View>
      <ShipmentHeader />
      <ShipmentRoute />
      <ShipmentActions />
    </View>
  );
}
Keep related files close together:
services/auth/
├── auth.service.ts
├── interface.ts
└── __tests__/
    └── auth.service.test.ts

3. Use Index Files for Clean Exports

types/index.ts
export * from "./auth.types";
export * from "./shipment.types";
export * from "./payout.types";
Allows clean imports:
import { User, Shipment, Payout } from "@/types";

4. Separate Business Logic from UI

// ✅ Business logic in hook
function useShipmentActions(shipmentId: string) {
  const updateStatus = useMutation(...);
  const uploadPhoto = useMutation(...);
  return { updateStatus, uploadPhoto };
}

// ✅ UI component uses hook
function ShipmentActions({ shipmentId }) {
  const { updateStatus, uploadPhoto } = useShipmentActions(shipmentId);
  return <View>...</View>;
}

Next Steps

Build docs developers (and LLMs) love