Project Structure

Khadem projects follow a clean, organized structure inspired by Laravel. When you create a new project using the Khadem CLI, it generates a complete folder structure designed for scalability, maintainability, and modern development practices.

📁

Well-Organized Structure

Every file and folder has a specific purpose, making your codebase easy to navigate and maintain.

Complete Project Structure

Here's the complete folder structure generated by khadem new:

text
my_api/
├── lib/
│   ├── main.dart               # Application entry point
│   ├── app/
│   │   ├── http/
│   │   │   ├── controllers/
│   │   │   │   └── home_controller.dart
│   │   │   └── middleware/
│   │   │       └── cors_middleware.dart
│   │   ├── jobs/
│   │   │   └── send_user_notification_job.dart
│   │   ├── listeners/
│   │   │   └── user_events_handler.dart
│   │   ├── models/
│   │   │   └── user.dart
│   │   └── providers/
│   │       ├── app_service_provider.dart
│   │       ├── event_service_provider.dart
│   │       └── scheduler_service_provider.dart
│   ├── bin/                    # CLI commands and utilities
│   ├── config/
│   │   └── app.dart           # Application configuration
│   ├── core/
│   │   └── kernel.dart        # Application kernel
│   ├── database/
│   │   ├── migrations/
│   │   │   ├── 0_create_users_table.dart
│   │   │   ├── 0_create_personal_access_token_table.dart
│   │   │   └── migrations.dart
│   │   └── seeders/
│   │       ├── seeders.dart
│   │       └── user_seeder.dart
│   └── routes/
│       ├── socket.dart
│       └── web.dart
├── config/
│   ├── development/
│   │   └── logging.json
│   └── production/
│       └── logging.json
├── lang/
│   ├── ar/
│   │   ├── ar.json
│   │   ├── fields.json
│   │   └── validation.json
│   └── en/
│       ├── en.json
│       ├── fields.json
│       └── validation.json
├── public/
│   └── assets/
│       └── logo.png
├── resources/
│   └── views/
│       └── welcome.khdm.html
├── storage/
│   └── logs/
│       └── app.log
├── tests/                      # Test files
├── .env                        # Environment variables
├── .gitignore                  # Git ignore rules
├── pubspec.yaml                # Package configuration
└── pubspec.lock                # Package lock file

📂 Application Layer

  • lib/app/ - Business logic and domain code
  • lib/core/ - Application kernel and bootstrap
  • routes/ - HTTP and WebSocket route definitions
  • config/ - Environment-specific configurations

🗄️ Data & Storage

  • lib/database/ - Migrations and database seeders
  • storage/ - File storage and cache directories
  • lang/ - Localization files
  • resources/ - Views and assets

lib/ Directory

The core of your Dart application, following modern Dart package conventions. All application code lives within the lib/ directory.

lib/app/ Directory

The heart of your application. Contains all business logic, domain models, and application services.

HTTP Layer

Handles web requests, responses, and HTTP-specific logic:

  • controllers/ - Route handlers that process requests and return responses
  • middleware/ - Request/response filters (auth, CORS, logging, etc.)

Domain Layer

Core business logic and data models:

  • models/ - Database entity representations with relationships
  • providers/ - Service providers for dependency injection
  • jobs/ - Background job classes for queue processing
  • listeners/ - Event listeners for async processing
text
lib/app/
├── http/
│   ├── controllers/
│   │   ├── home_controller.dart
│   │   ├── user_controller.dart
│   │   └── api/
│   │       └── v1/
│   │           └── auth_controller.dart
│   └── middleware/
│       ├── auth_middleware.dart
│       ├── cors_middleware.dart
│       └── logging_middleware.dart
├── models/
│   ├── user.dart
│   └── post.dart
├── providers/
│   ├── app_service_provider.dart
│   ├── event_service_provider.dart
│   └── scheduler_service_provider.dart
├── jobs/
│   ├── send_welcome_email_job.dart
│   ├── process_image_job.dart
│   └── email/
│       └── send_notification_job.dart
├── listeners/
│   └── user_registered_listener.dart

routes/ Directory

Define all your application routes here. Routes are organized by protocol and purpose:

  • web.dart - HTTP routes for web endpoints
  • socket.dart - WebSocket routes for real-time communication
dart
// lib/routes/web.dart
import 'package:khadem/khadem_dart.dart';
import '../app/http/controllers/home_controller.dart';
import '../core/kernel.dart';

void registerRoutes(Server server) {
  // Register global middlewares
  server.useMiddlewares(Kernel.middlewares);

  // API Routes
  server.group(
    prefix: '/api',
    middleware: [],
    routes: (router) async {
      router.get('/hello', HomeController.index);
      router.get('/welcome', HomeController.welcome);
      router.get('/stream', HomeController.stream);
    },
  );

  // Serve static files
  server.serveStatic();
}

// routes/socket.dart
import 'package:khadem/khadem_dart.dart';

void registerSocketRoutes(SocketServer socketServer) {
  socketServer.on('chat:message', (socket, data) {
    // Handle chat messages
    socketServer.broadcast('chat:message', data);
  });

  socketServer.on('user:join', (socket, data) {
    // Handle user joining
    socket.broadcast('user:joined', data);
  });
}

config/ Directory

Environment-specific configuration files. Each file exports configuration maps that are merged with environment variables:

Configuration Structure

  • app.dart - Main application configuration
  • development/ - Development-specific settings
  • production/ - Production-specific settings
dart
// config/app.dart
import 'package:khadem/khadem_dart.dart';

class AppConfig {
  static final env = Khadem.env;

  static Map<String, Map<String, dynamic>> get configs => {
    'database': {
      'driver': env.getOrDefault('DB_CONNECTION', 'mysql'),
      'host': env.getOrDefault('DB_HOST', 'localhost'),
      'port': env.getInt('DB_PORT'),
      'database': env.get('DB_DATABASE'),
      'username': env.get('DB_USERNAME'),
      'password': env.get('DB_PASSWORD'),
      'run_migrations': true,
      'run_seeders': false,
    },
    'cache': {
      'default': 'hybrid',
      'drivers': {
        'file': {'driver': 'file', 'path': 'storage/cache'},
        'memory': {'driver': 'memory'},
        'hybrid': {'driver': 'hybrid', 'path': 'storage/cache'},
      },
    },
    'queue': {
      'driver': 'file',
      'run_in_background': true,
      'auto_start': true,
    },
    'auth': {
      'default': 'users',
      'guards': {
        'users': {'driver': 'token', 'provider': 'users'},
      },
      'providers': {
        'users': {
          'table': 'users',
          'primary_key': 'id',
          'fields': ['email'],
        },
      },
    },
  };
}

lib/core/ Directory

Contains the application kernel that handles bootstrapping, service registration, and core framework setup:

dart
// lib/core/kernel.dart
import 'package:khadem/khadem_dart.dart';
import '../app/providers/app_service_provider.dart';
import '../app/providers/event_service_provider.dart';
import '../app/providers/scheduler_service_provider.dart';
import '../../config/app.dart';
import '../database/migrations/migrations.dart';

class Kernel {
  Kernel._();

  static List<ServiceProvider> get coreProviders => [
    QueueServiceProvider(),
    AuthServiceProvider(),
    DatabaseServiceProvider(),
  ];

  static List<ServiceProvider> get applicationProviders => [
    AppServiceProvider(),
    EventServiceProvider(),
    SchedulerServiceProvider(),
  ];

  static List<ServiceProvider> get allProviders => [
    ...coreProviders,
    ...applicationProviders,
  ];

  static List<Middleware> get middlewares => [
    CorsMiddleware(),
    LoggingMiddleware(),
    SetLocaleMiddleware(),
  ];

  static final Map<String, Map<String, dynamic>> configs = AppConfig.configs;
  static List<MigrationFile> get migrations => migrationsFiles;

  static Future<void> bootstrap() async {
    await Khadem.registerCoreServices();
    Khadem.register(allProviders);
    Khadem.loadConfigs(configs);
    await Khadem.boot();

    if (configs['database']?['run_migrations'] == true) {
      await Khadem.migrator.upAll(migrations);
    }
  }
}

lib/database/ Directory

Database-related files including migrations and seeders:

  • migrations/ - Database schema changes and migrations.dart registry
  • seeders/ - Database seeding scripts
text
lib/database/
├── migrations/
│   ├── 001_create_users_table.dart
│   ├── 002_create_posts_table.dart
│   ├── 003_add_user_id_to_posts.dart
│   └── migrations.dart
└── seeders/
    ├── database_seeder.dart
    ├── user_seeder.dart
    └── post_seeder.dart

storage/ Directory

File storage system with organized subdirectories:

  • app/ - Application-specific files
  • framework/ - Framework cache, sessions, and views
  • logs/ - Application log files
text
storage/
├── app/
│   ├── public/
│   └── private/
├── framework/
│   ├── cache/
│   │   ├── data/
│   │   └── views/
│   ├── sessions/
│   └── views/
└── logs/
    ├── khadem.log
    └── error.log

lang/ Directory

Localization files for multi-language support:

  • ar/ - Arabic language files
  • en/ - English language files

public/ Directory

Publicly accessible files served directly by the web server:

  • index.html - Default HTML page
  • assets/ - Static assets (CSS, JS, images)

resources/ Directory

Application resources like views and templates:

  • views/ - Template files for rendering

lib/main.dart

The main application entry point following Dart package conventions:

  • lib/main.dart - Application bootstrap and server startup
dart
// lib/main.dart
import 'dart:async';
import 'dart:io';
import 'package:khadem/khadem_dart.dart';
import 'lib/core/kernel.dart';
import '../routes/socket.dart';
import '../routes/web.dart';

Future<void> main(List<String> args) async {
  if (_isSnapshotBuild()) return;

  final container = Khadem.container;
  await Kernel.bootstrap();

  final port = _extractPort(args) ?? Khadem.env.getInt("APP_PORT", defaultValue: 8080);

  await Future.wait([
    _startHttpServer(port, container),
    _startSocketServer(container, Khadem.socket),
  ]);
}

bool _isSnapshotBuild() => Platform.environment.containsKey('KHADIM_JIT_TRAINING');

Future _startHttpServer(int port, ContainerInterface container) async {
  final server = Server();
  registerRoutes(server);
  server.setInitializer(() async {
    registerRoutes(server);
    await server.start(port: port);
  });
  await server.reload();
}

Future<void> _startSocketServer(container, manager) async {
  final socketPort = Khadem.env.getInt("SOCKET_PORT", defaultValue: 8080);
  final socketServer = SocketServer(socketPort, manager: manager);
  registerSocketRoutes(socketServer);
  await socketServer.start();
}

int? _extractPort(List<String> args) {
  final portIndex = args.indexOf('--port');
  if (portIndex != -1 && args.length > portIndex + 1) {
    return int.tryParse(args[portIndex + 1]);
  }
  return null;
}

bin/ Directory

CLI entry points and command-line scripts:

  • server.dart - CLI wrapper for the main application
dart
// lib/main.dart
import '../lib/main.dart' as app;

Future<void> main(List<String> args) async {
  await app.main(args);
}

tests/ Directory

Unit and integration tests for your application:

  • Unit tests for individual components
  • Integration tests for full workflows
  • Test utilities and mocks

Configuration Files

pubspec.yaml

Dart project configuration and dependencies:

yaml
name: my_api
description: A new Khadem Dart project.
version: 1.0.0
environment:
  sdk: '>=3.0.0 <4.0.0'

dependencies:
  khadem:
    path: ../khadem

dev_dependencies:
  lints: ^6.0.0
  build_runner: ^2.4.6

.env

Environment variables for configuration:

properties
# Application Configuration
APP_NAME=MyFirstAPI
APP_ENV=development
APP_PORT=8080
APP_LOCALE=en

# Database Configuration (MySQL)
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=my_first_api_db
DB_USERNAME=root
DB_PASSWORD=

# JWT Authentication
JWT_SECRET="your-super-secret-jwt-key-here"
JWT_ACCESS_EXPIRY_MINUTES=60
JWT_REFRESH_EXPIRY_DAYS=30

.gitignore

Git ignore patterns for Dart/Khadem projects:

text
# Dart
.dart_tool/
.packages
pubspec.lock

# Environment variables
.env
.env.local
.env.*.local

# Build outputs
build/
.dart_tool/

# IDEs
.vscode/
.idea/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db

# Logs
*.log
logs/

# Temporary files
tmp/
temp/

# Test coverage
coverage/

# Khadem specific
storage/framework/cache/*
storage/framework/sessions/*
storage/framework/views/*
storage/logs/*

Best Practices

✅ Do's

  • • Keep controllers thin and delegate to services
  • • Use meaningful names for files and directories
  • • Group related functionality together
  • • Follow the single responsibility principle

❌ Don'ts

  • • Don't put business logic in controllers
  • • Don't create deep directory nesting
  • • Don't mix different concerns in one file
  • • Don't hardcode configuration values

Customizing the Structure

While Khadem provides a solid foundation, you can customize the structure to fit your needs:

⚠️ Important

When customizing the structure, ensure you update the corresponding imports and service registrations in lib/core/kernel.dart.

Adding New Directories

You can add custom directories for specific functionality:

text
my_api/
├── lib/
│   ├── app/
│   │   ├── http/
│   │   ├── services/
│   │   │   ├── payment/
│   │   │   │   ├── stripe_service.dart
│   │   │   │   └── paypal_service.dart
│   │   │   └── notification/
│   │   │       ├── email_service.dart
│   │   │       └── sms_service.dart
│   │   └── repositories/
│   │       ├── user_repository.dart
│   │       └── post_repository.dart
│   ├── core/
│   └── database/
├── config/
│   ├── payment.dart
│   └── notification.dart
└── tests/
    ├── unit/
    │   ├── services/
    │   └── repositories/
    └── feature/
        ├── payment/
        └── notification/

Next Steps

Now that you understand the project structure:

On this page