Skip to content
Closed
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
197 changes: 197 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# libmodulor - Agent Development Guide

This guide provides essential information for agentic coding agents working with the libmodulor TypeScript library.

## Project Overview

**libmodulor** is a TypeScript library for creating platform-agnostic applications following a 4-layer architecture:
- **UseCase** - Business logic layer
- **App** - Application layer
- **Product** - Product layer
- **Target** - Platform-specific deployment targets

This is a distribution repository containing compiled ESM modules in `dist/esm/`.

## Build & Development Commands

### Core Commands
```bash
# Lint and auto-fix code
pnpm lint

# Lint without auto-fix (CI)
pnpm lint:ci

# Type check and run tests
pnpm test

# Type check only
tsc

# Run tests only
vitest run
```

### Running Individual Tests
```bash
# Run specific test file
vitest run examples/apps/Trading/test/App.test.ts

# Run tests with pattern
vitest run --reporter=verbose "**/test/**/*.test.ts"

# Run tests in watch mode
vitest examples/apps/Trading/test/App.test.ts
```

### CLI Scaffolding Commands
```bash
# Create new project
npx libmodulor CreateProject --projectName my-project

# Create app in existing project
pnpm libmodulor CreateApp --appName Banking

# Create use case
pnpm libmodulor CreateUC --appName Banking --ucName CreateAccount

# Create product
pnpm libmodulor CreateProduct --productName CustomerPortal

# Create target
pnpm libmodulor CreateTarget --productName CustomerPortal --targetName node-express-server
```

## Code Style Guidelines

### Formatting (Biome)
- **Indentation**: 4 spaces
- **Quotes**: Single quotes for strings
- **Semicolons**: Required
- **Trailing commas**: Enforced where appropriate

### Import Organization
Imports are automatically organized in this specific order:
1. Node.js built-in modules (`fs`, `path`, etc.)
2. Blank line
3. Package imports (`lodash`, `express`, etc.)
4. Blank line
5. Path imports (`./utils`, `../types`, etc.)

Example:
```typescript
import { join } from 'node:path';
import { readFile } from 'node:fs';

import express from 'express';
import { injectable } from 'inversify';

import { Configurator } from './Configurator.js';
import { Logger } from '../types/Logger.js';
```

### TypeScript Configuration
- **Strict mode**: Enabled
- **Target**: ESNext
- **Module**: NodeNext
- **Module Resolution**: NodeNext
- **Decorators**: Enabled with metadata
- **No implicit any**: Strict
- **No unused variables**: Error
- **Exact optional properties**: Enabled

### Naming Conventions
- **Classes**: PascalCase (`UserManager`, `OrderService`)
- **Interfaces/Types**: PascalCase with descriptive prefixes (`TOrderStatus`, `UCInput`)
- **Functions/Methods**: camelCase (`getUserById`, `processOrder`)
- **Constants**: UPPER_SNAKE_CASE (`MAX_RETRY_COUNT`, `DEFAULT_TIMEOUT`)
- **Files**: PascalCase for classes (`UserManager.ts`), kebab-case for utilities (`file-utils.ts`)

### Error Handling
- Use `CustomError` class from libmodulor for all business logic errors
- Never log or expose stack traces for `CustomError` instances
- Log unexpected errors before re-throwing
- Always handle errors in async functions with try/catch or proper error propagation

### Decorators & Dependency Injection
- Use `@injectable()` for all service classes
- Use `@inject(TOKEN)` for constructor injection
- Enable `unsafeParameterDecoratorsEnabled` in Biome config
- Import from `inversify` for DI container setup

### Testing Guidelines
- Tests are auto-generated - DO NOT EDIT test files directly
- Use Vitest as test runner
- Property testing with fast-check for monkey testing
- Test files located in `examples/*/test/` directories
- Use `describe`, `test`, `expect` from Vitest
- Snapshot testing for output verification

### Architecture Patterns
- **Use Cases**: Implement business logic, extend `UCDef<I, O, S>`
- **Apps**: Container for use cases, have `manifest.ts`
- **Products**: Collection of apps, have `manifest.ts` and `i18n.ts`
- **Targets**: Platform-specific deployment configurations

### File Structure
```
examples/
├── apps/
│ └── AppName/
│ ├── src/
│ │ ├── manifest.ts
│ │ ├── i18n.ts
│ │ ├── lib/ # Shared utilities
│ │ └── ucds/ # Use case definitions
│ ├── test/
│ │ ├── App.test.ts # Auto-generated
│ │ └── Configurator.ts
│ └── index.ts
└── products/
└── ProductName/
├── targets/
│ └── PlatformName/
├── manifest.ts
└── i18n.ts
```

### Linting Rules (Key Biome Rules)
- `noInferrableTypes`: Error - Don't annotate obvious types
- `noParameterAssign`: Error - Don't reassign parameters
- `noConsole`: Error - Use proper logging instead
- `useAsConstAssertion`: Error - Use `as const` for literals
- `useSingleVarDeclarator`: Error - One variable per declaration
- `useSelfClosingElements`: Error - Use self-closing tags when possible

### Internationalization
- All user-facing text must support i18n
- Use the i18n system with locale files in `i18n/locales/`
- Supported languages: de, en, es, fr
- Keys should be descriptive and namespaced

### Platform Support
The library supports 25+ platform exports including:
- Node.js (Express, Hono, MCP, CLI, Test)
- React (Web, Native, Pure)
- Next.js
- Cloudflare Workers
- Vite
- Webpack
- Babel
- Web

Import the appropriate platform-specific entry point:
```typescript
import { newNodeAppTester } from 'libmodulor/node-test';
import { I18nEN } from 'libmodulor/locales/en';
import { NodeAppTesterConfigurator } from 'libmodulor/node-test';
```

## Important Notes

- **DO NOT EDIT** auto-generated test files (marked with auto-generation comments)
- This is a research project (v0.26.0) - breaking changes expected until v1.0.0
- Always run `pnpm lint` and `pnpm test` before committing changes
- Use property-based testing for comprehensive coverage
- Follow the 4-layer architecture strictly
- All business logic must be in Use Cases, not in Targets or Products
48 changes: 48 additions & 0 deletions examples/apps/Auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,57 @@ sequenceDiagram
Client-->>-User: 👍 OK
```

### SignUp

- **Type** : `Client / Server`
- **Client Policy** : `Anonymous`
- **Server Policy** : `Anonymous`

#### Input (I)

|#|name|humanized|dataType|
|---|---|---|---|
|1|`email`|Email|`string`|
|2|`password`|Password|`string`|

#### Output (O)

##### Part 0 (OPI0)

|#|name|humanized|dataType|
|---|---|---|---|
|1|`jwt`|Jwt|`JWT`|
|2|`id`|Id|`UUID`|

##### Part 1 (OPI1)

None

#### Sequence Diagram

```mermaid
sequenceDiagram
actor User
User->>+Client: ✏️ Fill<br/>email: string<br/>password: string
User->>Client: ↩️ Submit
Client->>Client: 🔐 Check policy "Anonymous"
break when any validation fails
Client-->User: show failure
end
Client->>+Server: 📤 Send<br/>email: string<br/>password: string
Server->>Server: 🔐 Check policy "Anonymous"
break when any validation fails
Server-->User: show failure
end
Server->>Server: Persist the use case first to get aggregateId
Server-->>-Client: 👍 OK<br/>jwt: JWT<br/>id: UUID
Client-->>-User: 👍 OK
```

## Technical Summary

|#|filePath|constName|metadataName|metadataAction|metadataBeta|metadataIcon|metadataNew|metadataSensitive|externalImports|internalImports|ioI|ioIFields|ioOPI0|ioOPI0Fields|ioOPI1|ioOPI1Fields|lifecycleClientPolicy|lifecycleServerPolicy|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|1|/src/ucds/SignInUCD.ts|SignInUCD|SignIn|Create||right-to-bracket||||../../../../../dist/esm/index.js<br>../lib/TRole.js<br>../manifest.js<br>./SignInServerMain.js|SignInInput|role: UCInputFieldValue&#60;Role&#62;|SignInOPI0|jwt: JWT<br>id: UUID|||Anonymous|Anonymous|
|2|/src/ucds/SignOutUCD.ts|SignOutUCD|SignOut|Delete||circle-xmark||true||../../../../../dist/esm/index.js<br>../manifest.js|||||||Authenticated|Authenticated|
|3|/src/ucds/SignUpUCD.ts|SignUpUCD|SignUp|Create||user-plus||||../../../../../dist/esm/index.js<br>../manifest.js<br>./SignUpServerMain.js|SignUpInput|email: UCInputFieldValue&#60;string&#62;<br>password: UCInputFieldValue&#60;string&#62;|SignUpOPI0|jwt: JWT<br>id: UUID|||Anonymous|Anonymous|
27 changes: 26 additions & 1 deletion examples/apps/Auth/src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ export const I18n = {
uc_SignOut_i_submit_idle: 'Abmelden',
uc_SignOut_i_submit_submitting: 'Abmeldung',
uc_SignOut_label: 'Abmelden',
uc_SignUp_desc: 'Erstellen Sie ein neues Konto, um loszulegen',
uc_SignUp_i_submit_idle: 'Konto erstellen',
uc_SignUp_i_submit_submitting: 'Konto wird erstellt',
uc_SignUp_label: 'Konto erstellen',
ucif_email_label: 'E-Mail',
ucif_password_label: 'Passwort',
ucif_role_label: 'Rolle',
ucof_id_label: 'Kennung',
ucof_jwt_label: 'JWT',
Expand All @@ -22,6 +28,13 @@ export const I18n = {
uc_SignOut_client_confirm_message: 'Are you sure?',
uc_SignOut_i_submit_idle: 'Sign out',
uc_SignOut_i_submit_submitting: 'Signing out',
uc_SignUp_desc: 'Create a new account to get started.',
uc_SignUp_i_submit_idle: 'Sign up',
uc_SignUp_i_submit_submitting: 'Signing up',
uc_SignUp_label: 'Sign up',
ucif_email_label: 'Email',
ucif_password_label: 'Password',
ucif_role_label: 'Role',
},
es: {
uc_SignIn_desc: 'Inicia sesión en tu cuenta para comenzar',
Expand All @@ -32,6 +45,12 @@ export const I18n = {
uc_SignOut_i_submit_idle: 'Cerrar sesión',
uc_SignOut_i_submit_submitting: 'Cerrando sesión',
uc_SignOut_label: 'Cerrar sesión',
uc_SignUp_desc: 'Crea una nueva cuenta para comenzar',
uc_SignUp_i_submit_idle: 'Crear cuenta',
uc_SignUp_i_submit_submitting: 'Creando cuenta',
uc_SignUp_label: 'Crear cuenta',
ucif_email_label: 'Correo electrónico',
ucif_password_label: 'Contraseña',
ucif_role_label: 'Rol',
ucof_id_label: 'Identificador',
ucof_jwt_label: 'JWT',
Expand All @@ -45,7 +64,13 @@ export const I18n = {
uc_SignOut_i_submit_idle: 'Se déconnecter',
uc_SignOut_i_submit_submitting: 'Déconnexion',
uc_SignOut_label: 'Se déconnecter',
ucif_role_label: 'Role',
uc_SignUp_desc: 'Créez un nouveau compte pour commencer',
uc_SignUp_i_submit_idle: 'Créer un compte',
uc_SignUp_i_submit_submitting: 'Création du compte',
uc_SignUp_label: 'Créer un compte',
ucif_email_label: 'Adresse e-mail',
ucif_password_label: 'Mot de passe',
ucif_role_label: 'Rôle',
ucof_id_label: 'Identifiant',
ucof_jwt_label: 'JWT',
},
Expand Down
5 changes: 5 additions & 0 deletions examples/apps/Auth/src/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,10 @@ export const Manifest = {
name: 'SignOut',
sensitive: true,
},
SignUp: {
action: 'Create',
icon: 'user-plus',
name: 'SignUp',
},
},
} satisfies AppManifest;
Loading
Loading