Lutece 8 architecture patterns and conventions. MUST READ before writing any new Lutece code (CRUD, bean, service, DAO, XPage, daemon, templates) or answering questions about Lutece 8 architecture, layered design, or coding conventions.
View on GitHubskills/lutece-patterns/SKILL.md
February 5, 2026
Select agents to install to:
npx add-skill https://github.com/lutece-platform/lutece-dev-plugin-claude/blob/main/skills/lutece-patterns/SKILL.md -a claude-code --skill lutece-patternsInstallation paths:
.claude/skills/lutece-patterns/# Lutece 8 — Architecture Patterns
Reference patterns extracted from `~/.lutece-references/lutece-core/`. Use these as the canonical way to write Lutece 8 code.
## Layered Architecture
Every Lutece feature follows 5 layers, top to bottom. Never skip a layer.
```
JspBean / XPage ← web layer (request handling, validation, templates)
↓
Service ← business logic, cross-cutting concerns
↓
Home ← static facade (CDI lookup of DAO, cache coordination)
↓
DAO ← data access (DAOUtil, SQL, try-with-resources)
↓
Entity ← POJO (fields, getters/setters, interfaces)
```
## 1. Entity
```java
public class Task implements Serializable {
private static final long serialVersionUID = 1L;
private int _nIdTask;
private String _strTitle;
private boolean _bCompleted;
private Timestamp _dateCreation;
// Getters/setters only. No logic. No annotations except validation.
}
```
**Field prefixes**: `_str` (String), `_n` (int), `_b` (boolean), `_date` (Timestamp), `_list` (Collection).
**Interfaces to implement when needed**:
- `RBACResource` → RBAC permissions (`getResourceTypeCode()`, `getResourceId()`)
- `AdminWorkgroupResource` → workgroup filtering
- `IExtendableResource` → resource extension system
## 2. DAO
```java
@ApplicationScoped
public final class TaskDAO implements ITaskDAO {
private static final String SQL_QUERY_SELECTALL = "SELECT id_task, title, completed FROM myplugin_task";
private static final String SQL_QUERY_SELECT = SQL_QUERY_SELECTALL + " WHERE id_task = ?";
private static final String SQL_QUERY_INSERT = "INSERT INTO myplugin_task ( title, completed ) VALUES ( ?, ? )";
private static final String SQL_QUERY_UPDATE = "UPDATE myplugin_task SET title = ?, completed = ? WHERE id_task = ?";
private static final String SQL_QUERY_DELETE = "DELETE FROM myplugin_task WHERE id_task = ?";
@Override
public void