Skip to main content

Architecture Layers

Simple Manager follows Clean Architecture principles with four distinct layers. Dependencies flow inward: outer layers depend on inner layers, but inner layers never depend on outer layers.

Layer Hierarchy

1

Domain Layer (Core)

Pure business logic and entities - no dependencies
2

Application Layer

Use cases and services - depends only on Domain
3

Infrastructure Layer

Database and external services - implements Domain interfaces
4

Presentation Layer

UI and user interaction - depends on Application

1. Domain Layer

Location

src/domain/
The innermost layer containing pure business logic with zero external dependencies.

Responsibilities

  • Define core entities and types
  • Establish business rules
  • Define interfaces (contracts)

Structure

src/domain/
└── entities/
    ├── Record.ts
    ├── Appointment.ts
    └── Service.ts

Example: Record Entity

export interface Record {
  id: string;
  title: string;
  subtitle?: string;
  metadata?: string;
  type: string;
  userId?: string;
  createdAt: string;
  updatedAt: string;
  isDeleted: boolean;
}
Domain entities are plain TypeScript interfaces with no dependencies on frameworks or libraries.

2. Application Layer

Location

src/application/
Contains use cases and business logic orchestration.

Responsibilities

  • Implement business use cases
  • Coordinate between domain and infrastructure
  • Handle validation
  • Manage error handling

Structure

src/application/
├── services/
│   └── RecordService.ts
├── validators/
│   └── recordValidator.ts
└── errors/
    └── getErrorMessage.ts

Example: RecordService

import { Record } from "@/src/domain/entities/Record";
import { RecordRepository } from "@/src/infraestructure/repositories/RecordRepository";
import * as Crypto from 'expo-crypto';

export class RecordService {
  private repository = new RecordRepository();

  async create(title: string, type: string) {
    const now = new Date().toISOString();
    
    const record: Record = {
      id: Crypto.randomUUID(),
      title,
      type,
      createdAt: now,
      updatedAt: now,
      isDeleted: false,
    };

    await this.repository.create(record);
    return record;
  }

  async list() {
    return await this.repository.findAll();
  }

  async delete(id: string) {
    await this.repository.softDelete(id);
  }

  async update(record: Record) {
    record.updatedAt = new Date().toISOString();
    await this.repository.update(record);
  }
}
Services contain business logic and use repositories to access data. They don’t know about UI or database implementation details.

3. Infrastructure Layer

Location

src/infraestructure/
Handles external concerns like databases, APIs, and file systems.

Responsibilities

  • Implement data persistence
  • Database access and queries
  • External API integration (future)
  • File storage

Structure

src/infraestructure/
├── database/
│   ├── database.ts
│   └── initDatabase.ts
└── repositories/
    └── RecordRepository.ts

Example: Database Setup

import * as SQLite from "expo-sqlite";

export const db = SQLite.openDatabaseSync("simple_manager.db");

Example: Repository Implementation

import { Record } from "../../domain/entities/Record";
import { db } from "../database/database";

export class RecordRepository {
  async create(record: Record) {
    await db.runAsync(
      `INSERT INTO records (
        id, title, subtitle, metadata, type, userId, 
        createdAt, updatedAt, isDeleted
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
      [
        record.id,
        record.title,
        record.subtitle ?? null,
        record.metadata ?? null,
        record.type,
        record.userId ?? null,
        record.createdAt,
        record.updatedAt,
        record.isDeleted ? 1 : 0,
      ]
    );
  }

  async findAll(): Promise<Record[]> {
    const rows = await db.getAllAsync<any>(
      `SELECT * FROM records WHERE isDeleted = 0`
    );
    
    return rows.map((r) => ({
      ...r,
      isDeleted: Boolean(r.isDeleted),
    }));
  }

  async softDelete(id: string) {
    await db.runAsync(
      `UPDATE records SET isDeleted = 1 WHERE id = ?`,
      [id]
    );
  }
}
Repositories handle all database interactions. Never access the database directly from services or UI components.

4. Presentation Layer

Location

src/presentation/
The outermost layer containing UI components and user interaction logic.

Responsibilities

  • Render UI components
  • Handle user input
  • Manage local component state
  • Connect to application services via hooks

Structure

src/presentation/
├── screens/
│   └── RecordsScreen.tsx
├── components/
│   └── RecordCard.tsx
└── hooks/
    └── useRecords.ts

Example: Custom Hook

import { RecordService } from "@/src/application/services/RecordService";
import { Record } from "@/src/domain/entities/Record";
import { useEffect, useMemo, useState } from "react";

export function useRecords() {
  const service = useMemo(() => new RecordService(), []);
  const [records, setRecords] = useState<Record[]>([]);

  const load = async () => {
    const data = await service.list();
    setRecords(data);
  };

  const create = async (title: string, type: string) => {
    await service.create(title, type);
    await load();
  };

  const remove = async (id: string) => {
    await service.delete(id);
    await load();
  };

  useEffect(() => {
    load();
  }, []);

  return { records, load, create, remove };
}
Custom hooks bridge the presentation layer and application layer, providing a clean API for components.

Benefits of This Architecture

Testability

Each layer can be tested independently with mocked dependencies

Maintainability

Clear separation of concerns makes code easier to understand and modify

Scalability

Easy to add new features without affecting existing code

Flexibility

Swap implementations (e.g., SQLite → API) without changing business logic

Dependency Rule

Critical Rule: Dependencies must point inward only. Inner layers must never import from outer layers.
✅ Presentation → Application ✅
✅ Application → Domain ✅
✅ Infrastructure → Domain ✅
❌ Domain → Application ❌
❌ Domain → Infrastructure ❌

Data Flow

See how data moves through layers

Folder Structure

Explore the complete project structure

Build docs developers (and LLMs) love