# TeaQL Runtime Customization Guide (Java)

> This guide covers runtime setup, configuration, and advanced customization.
> For core API reference (UserContext, SmartList, Entity, etc.), see `java-assist-tool-api`.
> For debugging and logging, see `java-assist-debug`.

---

## 1. Runtime Setup

### Spring Boot (Recommended)

Use the generated `TeaQLConfiguration` class — it auto-registers all entity
descriptors, repositories, behaviors, checkers, and initial data:

```java
@SpringBootApplication
@Import(TeaQLConfiguration.class)
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
```

The configuration calls `ctx.ensureSchema()` on startup, which auto-creates
tables, adds new columns, and seeds constant/root data from the generated
`initialGraph`. Do not hand-write duplicate seed INSERT statements for
generated constants.

### Micronaut / Quarkus

The same pattern applies — import the generated configuration class for your
framework. The generated project scaffold includes the correct setup.

### Manual UserContext Assembly (Advanced)

Only use when you need a custom runtime and understand which generated
registries you are bypassing:

```java
UserContext ctx = new DefaultUserContext();
ctx.setDomainName("crm-erp-service");
ctx.registerEntityDescriptor(MerchantDescriptor.instance());
// ... register all entity descriptors, checkers, etc.
ctx.ensureSchema();
```

### Key Configuration Methods
| Method | Description |
|--------|-------------|
| `ctx.setDomainName(name)` | Set the domain name |
| `ctx.setUserIdentifier(id)` | Set who is performing actions |
| `ctx.getUserIdentifier()` | Get current user ID |
| `ctx.setTimezone(tz)` | Set timezone for date operations |
| `ctx.ensureSchema()` | Auto-create or migrate database tables |
| `ctx.getEntityDescriptor(name)` | Get entity metadata by name |
| `ctx.allEntityDescriptors()` | List all registered entity descriptors |
| `ctx.nextId(entityName)` | Generate next ID for an entity |
| `ctx.putLocal(key, value)` | Store request-scoped key-value data |
| `ctx.getLocal(key)` | Retrieve request-scoped value |
| `ctx.getBean(Class)` | Retrieve framework bean (Spring/Micronaut/Quarkus) |
| `ctx.now()` | Get current timestamp |

---

## 2. Value Types

| Java Type | Model Type | DB Mapping |
|-----------|-----------|------------|
| `String` | `string()` | VARCHAR |
| `long` / `Long` | `number()` | BIGINT |
| `java.math.BigDecimal` | `money()` / `decimal()` | DECIMAL |
| `boolean` / `Boolean` | `boolean()` | BOOLEAN |
| `java.time.LocalDate` | `date()` | DATE |
| `java.time.LocalDateTime` | `dateTime()` / `createTime()` | DATETIME |
| `String` (JSON) | `json()` | TEXT (JSON) |
| `long` | `id()` | BIGINT (FK) |

---

## 3. DateRange — Time Period Filtering

```java
import io.teaql.core.DateRange;

request.withCreateTimeBetweenRange(DateRange.today());
request.withCreateTimeBetweenRange(DateRange.thisMonth());
request.withCreateTimeBetweenRange(DateRange.lastNDays(7));
request.withCreateTimeBetweenRange(DateRange.thisYear());
request.withCreateTimeBetweenRange(DateRange.between(startDate, endDate));
```

---

## 4. Custom Checker

Checkers run automatically before every `save()`. Implement custom validation
logic in the generated checker class:

```java
public class MerchantChecker extends BaseChecker {
    @Override
    public CheckResult checkAndFix(UserContext ctx, BaseEntity entity) {
        Merchant merchant = (Merchant) entity;
        CheckResult result = new CheckResult();

        // Required field validation
        if (merchant.getName() == null || merchant.getName().isEmpty()) {
            result.addError("name", "Name is required");
        }

        // Business rule validation
        if (merchant.getLevel() != null && merchant.getLevel() > 10) {
            result.addError("level", "Level must be <= 10");
        }

        return result;
    }
}
```

---

## 5. Entity Events

Listen for entity change events to implement post-save side effects:

```java
public class MerchantEventHandler implements EntityEventHandler {
    @Override
    public void onCreated(UserContext ctx, BaseEntity entity) {
        Merchant merchant = (Merchant) entity;
        ctx.info("Merchant created: {}", merchant.getDisplayName());
    }

    @Override
    public void onUpdated(UserContext ctx, BaseEntity entity, List<String> changedFields) {
        // React to field changes
    }

    @Override
    public void onDeleted(UserContext ctx, BaseEntity entity) {
        // Cleanup related resources
    }
}
```

---

## 6. XlsWorkbook — Excel Export

```java
import io.teaql.core.xls.XlsWorkbook;
import io.teaql.core.xls.XlsPage;
import io.teaql.core.xls.XlsBlock;

XlsPage page = new XlsPage("orders")
    .addBlock(new XlsBlock("orders", 0, 0, "Order Report").span(3, 1));
XlsWorkbook workbook = new XlsWorkbook().addPage(page);
String json = workbook.toJsonString();
```

---

## 7. Schema Management

```java
ctx.ensureSchema();
// Auto-creates tables and adds new columns. Never drops columns.
// Also seeds initial data (constants, root entities) from the generated initialGraph.
```

If a requested change requires new entities, fields, relations, constants, or
modules, update the KSML model first and regenerate the project.

Do not manually edit generated entity/request/expression files. Treat generated
files as disposable.

---

## 8. WebResponse Patterns

### Success with single entity
```java
return WebResponse.of(merchant);
```

### Success with paginated list
```java
SmartList<Merchant> list = Q.merchants()
    .comment("list merchants").purpose("API response")
    .executeForPage(ctx, offset, limit);
return WebResponse.of(list);
```

### Error response
```java
return WebResponse.fail("Merchant not found");
```

### Custom response data
```java
return WebResponse.of(merchant)
    .withAction(WebAction.of("edit").withTitle("Edit").withTarget("/edit/" + id));
```

---

## 9. Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `TEAQL_LOG_ENDPOINT` | *(stdout)* | Log output file path |
| `TEAQL_LOG_FORMAT` | `human` | `human` or `json` |
| `TEAQL_LOG_SELECT` | `false` | Log SELECT SQL |
| `TEAQL_LOG_MUTATION` | `true` | Log INSERT/UPDATE/DELETE SQL |
| `TEAQL_ENFORCE_INTENT` | `off` | `off`, `warn`, `strict` |
| `TEAQL_LOG_MAX_SIZE` | `50M` | Max log file size |
| `TEAQL_LOG_MAX_FILES` | `7` | Max rotated log files |

> For detailed debugging instructions, see `java-assist-debug`.