Version 1.2.2
Review the Jakarta Faces code in $ARGUMENTS (if no argument, scan the project for .xhtml and backing bean files) against the rules in .claude/faces/rules.md and its topic files.
Review Checklist
XHTML / Facelets
- XML namespaces match the project's Faces version.
- HTML5 doctype
<!DOCTYPE html>is used, not XHTML doctype. - No "god form" (single form wrapping entire page); forms are scoped to logical sections.
- No nested
UIFormcomponents. UIInputandUICommandcomponents are insideUIForm.- Every
UIInputhas a correspondingUIMessage. - A catch-all
UIMessageswithredisplay="false"exists in each view; when using ajax, its ID is covered byrender/update. - Conditionally rendered components that are ajax-updated are wrapped in an always-rendered container, and ajax updates target the wrapper ID.
NamingContainer,UIInputandUICommandcomponents have explicit IDs (no generated IDs); IDs follow naming convention (property name forvalue, method name foraction, view ID name for forms/panels).bindingis not used for data binding;bindingis only used on page-scoped variables for component cross-referencing within the same view.- Ajax
render/updatereferences acrossNamingContainerboundaries use full client ID with leading colon. - JSTL tags are only used for build-time view construction, not for conditional rendering (use
renderedattribute instead). - No inline styles; CSS is in separate files.
- Templates, includes, tag files, and composites are inside
/WEB-INF/to prevent direct client access. - Resources (scripts, styles, images) are referenced via
<h:outputScript>,<h:outputStylesheet>,<h:graphicImage>, or#{resource[]}; whenWEBAPP_RESOURCES_DIRECTORYis set toWEB-INF/resources, verify resources are actually in that location. - No duplicate/copy-pasted XHTML blocks; reusable code is in templates, includes, tag files, or composite components.
- File download commands do not use ajax (or use
<p:fileDownload>if PrimeFaces).
Backing Beans
@Namedis used with a CDI scope annotation (not@ManagedBean, not missing scope).@ViewScopedis imported fromjakarta.faces.view(orjavax.faces.view), not fromjakarta.enterprise.contextorjavax.faces.bean.- Beans stored in
HttpSession(@ViewScoped,@SessionScoped,@ConversationScoped,@FlowScoped,@ClientWindowScoped) implementSerializable. - Initial state is loaded in
@PostConstruct, not in constructors, field initializers, or getters. - Getters are pure (no business logic, no lazy-loading, no side effects).
UISelectManybacking properties use mutable collections (new ArrayList), notList.of(),Arrays.asList(), orStream.toList().actionmethods are used for business logic;actionListeneris only used to prepare/gate the action.- Scope matches usage:
@RequestScopedfor simple non-ajax forms,@ViewScopedfor ajax forms/datatables,@ApplicationScopedfor shared caches (must be thread-safe).
Configuration (if accessible)
web.xmlhasFACELETS_SKIP_COMMENTSset totrue.web.xmlhasINTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULLset totrue.WEBAPP_RESOURCES_DIRECTORY: when the resources directory contains composite components (.xhtmlfiles), it MUST be set toWEB-INF/resourcesto prevent direct client access to composite component source code; for plain assets only (scripts, styles, images, fonts) it's merely a recommendation.- FacesServlet is mapped to
*.xhtmlonly (no legacy*.jsf,*.faces,/faces/*). faces-config.xmlversion matchespom.xmlFaces dependency version.
PrimeFaces (if present)
- Consult
.claude/faces/topics/primefaces.mdand check its rules.
OmniFaces (if present)
- Consult
.claude/faces/topics/omnifaces.mdand check for opportunities to simplify code.
Output Format
For each finding, report:
- File and line — the location.
- Rule violated — short description of which rule.
- Severity — error (will cause bugs), warning (anti-pattern/risk), or info (improvement opportunity).
- Fix — concrete suggestion.
Group findings by file. If no issues are found, confirm the code follows Faces best practices.