--- name: specgen-spring-jpa-jtehtmx model: claude-opus-4-8 effort: high description: > Generate a detailed specification document for building a monolith Spring Boot 3 web application with server-rendered views (JTE), Tailwind CSS, Alpine.js, htmx, and Spring Modulith packaging. Database (MongoDB, PostgreSQL, MySQL, or none), authentication (Keycloak OAuth2 Client, Spring Security form login, or none), scheduling (Quartz + Spring Batch or none), messaging (RabbitMQ pub/sub or none), and internationalisation (multi-locale via Spring's native MessageSource, or none) are configurable based on user input. Standardized input: application name (mandatory), version (mandatory), module (optional). Use this skill whenever the user asks to create a spec, specification, blueprint, or technical design document for a new Spring Boot web application with server-side rendering. Also trigger when the user says things like "spec out a new web project", "design a Spring Boot web skeleton", "write a technical spec for my new web app", "scaffold spec for a monolith web app", or any request for a specification document describing a Spring Boot + JTE + Tailwind application. Even if the user only mentions a subset of the stack (e.g., "Spring Boot web app" or "Spring web with Mongo" or "Spring Boot with Keycloak"), this skill likely applies — ask and confirm.
Spring Boot Web Application Specification Generator
This skill generates a comprehensive specification document (Markdown) that serves as a blueprint for building a monolith Spring Boot 3 web application with server-rendered views. The spec is intended to be followed by a developer or a coding agent to produce a fully functional project scaffold.
The specification does NOT generate code. It produces a detailed, opinionated technical document describing every layer of the application — from Maven configuration to JTE layouts to security filter chains — so that implementation becomes a mechanical exercise.
Technology Stack
Core Stack (Always Included)
These are the fixed versions the spec targets. Do not deviate unless the user explicitly requests different versions.
| Component | Version |
|---|---|
| Java JDK | 21 |
| Spring Boot | 3.5.7 |
| Maven | 4.0.0 |
| JTE | 3.2.1 |
| Tailwind CSS | 4.x |
| Alpine.js | 3.x |
| htmx | 2.x |
| Vite | 6.x |
Optional Integration Versions
Include in the version table only when the corresponding integration is selected.
| Component | Version | When Selected |
|---|---|---|
| MongoDB | 8.0.19 | Database = MongoDB |
| PostgreSQL | 17.x | Database = PostgreSQL |
| MySQL | 8.4.x | Database = MySQL |
| Keycloak | 26.5.3 | Auth = Keycloak |
| RabbitMQ | 4.x | Messaging = yes OR Remote Partitioning = yes |
Core Dependencies
The spec must include these in the Maven configuration section (always):
- Spring Web (starter-web)
- Spring Modulith (core, events-api)
- JTE Spring Boot Starter (
gg.jte:jte-spring-boot-starter-3) - JTE precompiler (
gg.jte:jte-maven-pluginwithprecompilegoal atprocess-classesphase, output totarget/classesso precompiled templates are included in the Spring Boot fat JAR) - Lombok
- Spring Boot DevTools
- MapStruct (with annotation processor)
- frontend-maven-plugin (for Node/Vite build)
Conditional Dependencies
If Database = MongoDB:
- Spring Data MongoDB (
spring-boot-starter-data-mongodb) - MongoDB Driver
- Spring Modulith starter-mongodb (
spring-modulith-starter-mongodb)
If Database = PostgreSQL or MySQL:
- Spring Data JPA (
spring-boot-starter-data-jpa) - PostgreSQL driver (
org.postgresql:postgresql) or MySQL driver (com.mysql:mysql-connector-j) - Flyway (
org.flywaydb:flyway-core) for schema migration - Spring Modulith starter-jpa (
spring-modulith-starter-jpa)
If Auth = Keycloak:
- Spring Security (
spring-boot-starter-security) - Spring Security OAuth2 Client (
spring-boot-starter-oauth2-client)
If Auth = Spring Security (form login):
- Spring Security (
spring-boot-starter-security)
If Scheduling = yes:
- Spring Quartz (
spring-boot-starter-quartz) - If Database = MongoDB:
io.fluidsonic.mirror:fluidsonic-mirror-quartz(MongoDB job store for Quartz) - If Database = PostgreSQL/MySQL: Quartz JDBC job store (built-in)
If Scheduling = yes AND Spring Batch = yes:
- Spring Batch (
spring-boot-starter-batch)
If Scheduling = yes AND Spring Batch = yes AND Remote Partitioning = yes:
- Spring Batch Integration (
spring-batch-integration) - Spring Integration AMQP (
spring-integration-amqp) - Spring Boot AMQP Starter (
spring-boot-starter-amqp)
If Messaging = yes:
- Spring Boot AMQP Starter (
spring-boot-starter-amqp) (shared with Remote Partitioning — if both are selected, include the dependency once)
If i18n = yes:
- No extra dependency — uses Spring's built-in
MessageSource(part ofspring-context, already on the classpath viastarter-web). Resource bundles undersrc/main/resources/i18n/, aCookieLocaleResolver, and aLocaleChangeInterceptorprovide locale resolution and switching; a smallLocalizerhelper exposes messages to JTE templates.
If Reporting = yes:
- JasperReports (
net.sf.jasperreports:jasperreports:7.0.3) — report engine with JRDesign API for programmatic layout - JasperReports Fonts (
net.sf.jasperreports:jasperreports-fonts:7.0.3) - OpenPDF (
com.github.librepdf:openpdf:2.0.4) — PDF export engine for JasperReports 7.x - Apache POI OOXML (
org.apache.poi:poi-ooxml:5.4.1) — XLSX export support
When the Skill Triggers
Generate the spec when the user provides an application name and version that
corresponds to one of the custom applications defined in CLAUDE.md. The skill
reads all required inputs from the project's context files — no interactive Q&A is needed
for the core inputs.
The user invokes this skill by specifying the target application and version, for example:
/specgen-spring-jpa-jtehtmx hub_middleware v1.0.3/specgen-spring-jpa-jtehtmx hub_middleware v1.0.3 module:Location Information/specgen-spring-jpa-jtehtmx "Hub Middleware" v1.0.3
The skill then locates the matching context folder and reads all input files automatically.
Version Gate
Before starting any work, resolve the application folder first (see Input Resolution below), then check CHANGELOG.md in the application folder (<app_folder>/CHANGELOG.md):
- If
<app_folder>/CHANGELOG.mddoes not exist, skip this check (first-ever execution for this application). - If
<app_folder>/CHANGELOG.mdexists, scan all## vX.Y.Zheadings and determine the highest version using semantic versioning comparison. - Compare the requested version against the highest version:
- If requested version >= highest version: proceed normally.
- If requested version < highest version: STOP immediately. Print:
"Version {requested} is lower than the current application version {highest} recorded in <app_folder>/CHANGELOG.md. Execution rejected."Do NOT proceed with any work.
Input Resolution
This skill uses standardized input resolution. Provide:
| Argument | Required | Example | Description |
|---|---|---|---|
<application> |
Yes | hub_middleware |
Application name to locate the context folder |
<version> |
Yes | v1.0.3 |
Version to scope processing |
module:<name> |
No | module:Location Information |
Limit generation to a single module |
Application Folder Resolution
The application name is matched against root-level application folders:
- Strip any leading
<number>_prefix from folder names (e.g.,1_hub_middleware→hub_middleware) - Match case-insensitively against the provided application name
- Accept snake_case, kebab-case, or title-case input (all match the same folder)
- If no match found, list available applications and stop
Auto-Resolved Paths
| File | Resolved Path |
|---|---|
| PRD.md | <app_folder>/context/PRD.md |
| Module Models | <app_folder>/context/model/ |
| HTML Mockups | <app_folder>/context/mockup/ |
| Output (specification) | <app_folder>/context/specification/ |
Example Invocations
/specgen-spring-jpa-jtehtmx hub_middleware v1.0.3(all modules)/specgen-spring-jpa-jtehtmx hub_middleware v1.0.3 module:Location Information(one module)/specgen-spring-jpa-jtehtmx "Hub Middleware" v1.0.3
Version Filtering
When a version is provided, only include user stories, NFRs, and constraints from versions
<= the provided version. For example, if v1.0.3 is specified:
- Include items tagged
[v1.0.0],[v1.0.1],[v1.0.2],[v1.0.3] - Exclude items tagged
[v1.0.4]or later - Version comparison uses semantic versioning order
Module Filtering
When module:<name> is provided:
- Only generate the
SPEC.mdfor that specific module - Other existing module spec files remain untouched
SPECIFICATION.md(root) gets a partial update — only that module's entry in the TOC is added or updated; all other TOC entries are preserved as-is
Gathering Input
The specification is driven by six input sources that are read from the project's context files. The skill does NOT ask the user for database, authentication, scheduling, or messaging choices — it determines these automatically from the context.
Input 1: Application Name (from CLAUDE.md)
From CLAUDE.md (already loaded in context), locate the target application under the Custom Applications section. Extract:
- Application name: The section heading (e.g., "Hub Middleware", "HC Adapter")
- Application description: The description paragraph below the heading
- Dependencies: The "Depends on" list — this is the primary source for determining optional components (see Determining Optional Components)
The application name is used to derive:
- Artifact ID: Kebab-case of the application name (e.g.,
hub-middleware) - Group ID:
com.bestinet.urp(project-level constant) - Base package:
com.bestinet.urp.<artifactid_no_hyphens>(e.g.,com.bestinet.urp.hubmiddleware)
Input 2: User Stories (from PRD.md)
Read <app_folder>/context/PRD.md. This file contains all user stories
organized by module. Extract:
- System modules: Modules under the
# System Moduleheading (e.g., User, Notification, Activities, Audit Trail). These become system-level modules in the spec. - Business modules: Modules under the
# Business Moduleheading (e.g., Location Information, Corridor, Employer). These become business-level modules. - User stories per module: Each
### User Storysection contains tagged items like[USHM00108] As a user, I want to.... These define the functional requirements for each module's service interface and page controllers.
The user stories directly inform:
- Which CRUD operations each module's service must expose
- Which page controllers and JTE views are needed
- Which form fields and validation rules apply
Important: Items with strikethrough (~~text~~) are deprecated — do NOT include them
as active requirements. Instead, list them in the "Removed / Replaced" subsection of the
traceability table (see spec-template.md) so that developers can see what was removed and
which version removed it. If a deprecated item has a replacement (e.g., USHM00015 replaced
by USHM00222), note the replacement ID.
- Version tags per item: Each
### User Story,### Non Functional Requirement, and### Constraintsection contains one or more version blocks formatted as[v1.0.x]. Items listed under each version tag belong to that version. The skill must track the version tag for each item (user story, NFR, constraint) and carry it through to the generated specification's traceability section. When a version block explicitly lists "Removed ... from previous version", record those removals in a "Removed / Replaced" subsection with the version that removed them and the replacement ID (if any).
Input 3: Non-Functional Requirements (from PRD.md)
Within the same PRD.md, each module has a ### Non Functional Requirement section
with tagged items like [NFRHM0120]. These inform:
- Data storage strategies (e.g., "stored in JWT token", "stored in the database")
- Integration patterns (e.g., "API call to SSO service", "sent asynchronously")
- Performance constraints (e.g., "automatically deleted after 30 days")
- Security requirements (e.g., "require user to relogin")
NFRs should be mapped to specific technical decisions in the spec — for example, an NFR stating "stored in JWT token" confirms stateless auth, while "sent asynchronously" confirms event-driven processing.
Input 4: Constraints (from PRD.md)
Within the same PRD.md, each module has a ### Constraint section with tagged
items like [CONSHM042]. These define hard boundaries that the spec must enforce:
- Field-level restrictions (e.g., "can only change name and phone number")
- Feature boundaries (e.g., "only 2 delivery channels supported")
- Scope limitations (e.g., "does not manage any user, permissions and roles")
Constraints are embedded directly into the relevant module blueprint — they inform service interface contracts, validation rules, and UI form configurations.
Input 5: Module Model (from model/ folder)
Read <app_folder>/context/model/MODEL.md first as the index, then read the
individual module model files in each module subfolder.
MODEL.md provides:
- Summary table of all modules with collection counts and design decisions
- Links to each module's detailed model files
Per-module files (e.g., model/location-information/model.md):
- Complete document/entity field definitions with types and constraints
- Embedded vs. referenced relationships
- Collection/table names
- Index specifications
- Audit field patterns
Per-module schema (e.g., model/location-information/schemas.json):
- JSON schemas defining exact field types, required fields, and validation rules
Per-module diagram (e.g., model/location-information/document-model.mermaid):
- Visual representation of document structure and relationships
The module model directly maps to:
MongoDB documents or JPA entities (field-for-field, not placeholder)
Repository methods and query patterns
MapStruct mapper definitions
DTO structures matching the actual module fields
Service interface method signatures
Version tracking: The MODEL.md summary table includes a "Versions" column listing which versions each module participates in (e.g., "1.0.0, 1.0.1, 1.0.3"). Per-module model.md files may also include version annotations on fields and indexes. The skill must carry these version tags into the generated specification.
Input 6: HTML Mockup Screens (from mockup/ folder)
Read <app_folder>/context/mockup/MOCKUP.html first as the index page, then
read the HTML files organized by role in subfolders.
MOCKUP.html provides:
- Application identity (name, version, short name)
- Design tokens: fonts, colors, spacing from Tailwind config
- List of user roles and their screen sets
- Setup instructions for the shared Mockup Hub (
<root>/mockup)
Role-specific subfolders (e.g., mockup/hub_administrator/content/):
- Individual HTML screens for each page in the application
- Screen layout: which components are used (tables, forms, cards, tabs, modals)
- Navigation structure from sidebar HTML files
- Data display patterns (list pages, detail pages, create/edit forms)
IMPORTANT — Role folders inform access control, NOT URL paths. The role-specific
folder structure (e.g., mockup/hub_administrator/content/corridor.html) determines:
- Which role can access the page →
@PreAuthorize("hasRole('HUB_ADMINISTRATOR')") - Which sidebar navigation items appear for each role It does NOT determine the URL path. The URL path is always module-based:
@RequestMapping("/corridor")— NOT@RequestMapping("/hub_administrator/corridor")- Fragment URL:
@RequestMapping("/corridor/fragments")— NOT@RequestMapping("/api/content/hub_administrator/corridor")
Shared partials (e.g., mockup/partials/):
header.html— Header bar layout and elementsfooter.html— Footer layoutsidebar-<role>.html— Per-role navigation menusshell.html— Page shell/wrapper structure
The mockup screens directly map to:
JTE page templates (one per HTML screen)
JTE fragment templates (for htmx partial updates)
Page controller endpoints (one per screen)
View model classes (with fields matching the data shown in each screen)
Sidebar navigation items per role
Form field layouts and validation display
Design tokens for Tailwind configuration (colors, fonts from MOCKUP.html)
Version tracking: The MOCKUP.html index page shows a version tag on each screen card (e.g.,
v1.0.0,v1.0.3). Individual mockup screens may include version annotations. The skill must associate each mockup screen with its version and carry this through to the generated specification.
PRD.md Extended Sections
Before determining optional components, check PRD.md for the following extended sections and extract their content for use throughout specification generation:
Architecture Principle Extraction
If PRD.md contains an # Architecture Principle section, read it and extract architectural patterns as a structured context object. These patterns serve as primary signals for optional component determination and specification content:
| Pattern to Extract | How It Influences the Specification |
|---|---|
| Framework mention (e.g., "Spring Boot") | Validates technology stack choice; confirms Spring Modulith approach |
| "Monolithic" / "modular architecture" | Validates Spring Modulith module structure; cross-module communication via application events |
| "Stateless" | Confirms no HTTP session — JWT/OAuth2 token-based auth; include in Security Configuration section |
| "Event-driven" | Enhances Event-Driven Architecture section (Section 14) with event catalog, event payload DTOs, and explicit listener registration patterns per module |
| "Message driven" / "message queue" | Validates RabbitMQ integration sections; include message flow documentation per module |
| "Document based database" / "MongoDB" | Primary signal for Database = MongoDB (overrides CLAUDE.md if conflicting) |
| "Container based deployment" | Confirms environment-variable-based configuration (${ENV_VAR} syntax) |
| "Scale out" / "horizontally scalable" | Include HPA-related notes in deployment considerations |
| View engine mention (e.g., "JTE") | Validates JTE template engine choice |
| Build tool mention (e.g., "Vite") | Include Vite build configuration in the specification |
If the section is absent, proceed with existing CLAUDE.md-only detection.
Design System Extraction
If PRD.md contains a # Design System section with a file reference (e.g., [DESIGN_SYSTEM.md](reference/DESIGN_SYSTEM.md)):
- Resolve the path relative to PRD.md and read the referenced file
- Extract design tokens: color palettes, typography, component patterns
- Include a "Design System Integration" subsection in SPECIFICATION.md under "Application Configuration" specifying:
- Tailwind CSS custom theme configuration (colors, fonts from design system)
- JTE layout template design token variables
- CSS variable definitions for dynamic theming
- In per-module SPEC.md, reference which design tokens apply to specific components (e.g., status badges use
accent-successcolor for Active)
If the section is absent, use design tokens from MOCKUP.html Tailwind config (existing behavior).
High Level Process Flow Extraction
If PRD.md contains a # High Level Process Flow section:
- Parse all named process flows and their ordered steps
- Each process flow becomes an authoritative source for the messaging pipeline sections in per-module SPEC.md:
- Each step maps to a specific service method, event listener, or message handler
- Error paths generate corresponding exception handlers and dead-letter queue configurations
- ACK/NACK patterns become outbound message publisher specifications with defined message schemas
- Include a "Process Flow Implementation" subsection in each affected module's SPEC.md that maps flow steps to service methods
- Generate an event catalog in SPECIFICATION.md listing all domain events derived from process flows
If the section is absent, derive messaging patterns from NFRs only (existing behavior).
Determining Optional Components
Instead of asking the user, the skill determines optional components by analyzing the
dependencies listed in CLAUDE.md, the # Architecture Principle section in PRD.md (if present),
and cross-referencing with PRD.md NFRs and constraints.
Database Detection
First check PRD.md # Architecture Principle: If it explicitly mentions a database type (e.g., "document based database", "MongoDB", "relational database", "MySQL"), use that as the primary signal.
Fallback to CLAUDE.md: Examine the "Depends on" list in CLAUDE.md for the target application:
| Dependency Pattern | Database Selection |
|---|---|
| References "Hub Database" (MongoDB) | Database = MongoDB |
| References "HC Database" or "SC Database" (MySQL) | Database = MySQL |
| No database dependency listed | Database = none |
Also check CLAUDE.md's database section for the exact database name, and read
ENVIRONMENT.md (in the project root) for host, port, and credentials to use in the
spec's application configuration.
Authentication Detection
| Dependency Pattern | Auth Selection |
|---|---|
| References "Hub Single Sign On" (Keycloak) | Auth = Keycloak |
| PRD.md constraint says "does not manage any user, permissions and roles" | Auth = none |
| PRD.md NFRs reference "SSO service" or "JWT token" | Auth = Keycloak |
| No SSO/Keycloak dependency but has user management stories | Auth = form |
If Auth = Keycloak, also extract from CLAUDE.md:
- Keycloak version from "Hub Single Sign On" section
- Keycloak realm: Default derived from project name
- Keycloak client ID: Default
<artifact-id>-web - Keycloak issuer URI: Default
http://localhost:8180/realms/<realm> - Keycloak roles: Infer from mockup sidebar roles (e.g.,
hub_administrator→HUB_ADMINISTRATOR)
Messaging Detection
| Dependency Pattern | Messaging Selection |
|---|---|
| References "Hub to HC Adapter Message Queue" or "Hub to SC Adapter Message Queue" (RabbitMQ) | Messaging = yes |
| No message queue dependency listed | Messaging = no |
If Messaging = yes, also extract the RabbitMQ version from the corresponding message queue section in CLAUDE.md.
Scheduling Detection
Scheduling is determined from PRD.md content:
| Content Pattern | Scheduling Selection |
|---|---|
| NFRs mention "automatically deleted after X days", "scheduled", "periodic", "batch processing" | Scheduling = yes |
| User stories describe recurring jobs, cleanup tasks, or time-triggered operations | Scheduling = yes |
| No scheduling-related requirements found | Scheduling = no |
If Scheduling = yes, further determine:
- Spring Batch = yes if NFRs mention "batch processing", "ETL", "bulk import/export", or processing large volumes of data with reader/processor/writer patterns
- Remote Partitioning = yes if NFRs mention "distributed processing", "horizontal scaling", or "partitioned batch jobs"
Reporting Detection
Reporting is determined from PRD.md content:
| Content Pattern | Reporting Selection |
|---|---|
| NFRs mention "report", "Report interface", "generate report", "report generation" | Reporting = yes |
| User stories describe generating/downloading PDF, Excel, or CSV reports | Reporting = yes |
| A "Report" module exists in PRD.md with NFRs defining a Report interface | Reporting = yes |
| No reporting-related requirements found | Reporting = no |
If Reporting = yes, the spec includes:
- JasperReports with JRDesign API for fully programmatic report layout (no .jrxml templates)
ReportDefinitioninterface withbuildDesign()method for modules to implementReportDesignHelperutility class with static builders for common layout patternsReportServiceorchestrating compile → fill → export viaJRBeanCollectionDataSource- Report registry persisted in the database
- Report page controller with parameter form and download endpoint
- JTE templates for report list and parameter form pages
- Multi-format export: PDF (OpenPDF), XLSX (Apache POI), CSV
Internationalisation Detection
Internationalisation is determined from PRD.md content:
| Content Pattern | i18n Selection |
|---|---|
| PRD.md mentions multiple languages or localization (e.g., "English and Bahasa Malaysia", "multilingual", "support multiple locales") | i18n = yes |
| NFRs require translatable UI, locale-specific date/number formatting, or a language switcher | i18n = yes |
| User stories describe choosing/switching the interface language | i18n = yes |
| No language/localization requirements found | i18n = no |
If i18n = yes, the spec includes:
- An
I18nConfigproviding aMessageSource, aCookieLocaleResolver, and aLocaleChangeInterceptor - Resource bundles under
src/main/resources/i18n/(messages.properties+messages_<locale>.properties) - An
app.i18nconfig block (default-locale,supported-locales) under theapp:namespace - A
Localizerhelper exposed as a global@ModelAttributeso JTE templates resolve message keys - A language switcher fragment (htmx-driven, hitting
?lang=<locale>) - Bean-validation message localization wired to the same
MessageSource
If i18n = no, do NOT generate a locale/language switcher or any message-bundle scaffolding — JTE templates use literal copy. This is the existing "do NOT generate UI without backend support" constraint (see Constraints below).
Summary of Determination
After analyzing all inputs, produce a determination summary before generating the spec. Present it to the user for confirmation:
Optional Component Determination:
- Database: MongoDB (from CLAUDE.md → depends on Hub Database)
- Authentication: Keycloak (from CLAUDE.md → depends on Hub Single Sign On)
- Scheduling: yes (from PRD.md → NFR mentions automatic deletion)
- Spring Batch: no
- Remote Partitioning: no
- Messaging: yes (from CLAUDE.md → depends on Hub to HC/SC Adapter Message Queue)
- Reporting: yes (from PRD.md → Report module with Report interface NFR)
- Internationalisation: yes (en, ms) (from PRD.md → English + Bahasa Malaysia required)
If the user disagrees with any determination, allow them to override before proceeding.
Required Inputs
After determination, these values are needed. Most are derived automatically:
Auto-derived from context files:
- Application name: From CLAUDE.md section heading
- Artifact ID: Kebab-case of application name
- Group ID:
com.bestinet.urp - Base package:
com.bestinet.urp.<artifactid> - Application description: From CLAUDE.md description
- Modules: From PRD.md module headings + model/MODEL.md
- Database: Auto-determined (see above)
- Authentication: Auto-determined (see above)
- Scheduling: Auto-determined (see above)
- Messaging: Auto-determined (see above)
- Database name/credentials: From ENVIRONMENT.md (root-level file with local environment credentials)
- User roles: From mockup sidebar files
- Design tokens: From MOCKUP.html Tailwind config
Auto-derived from CLAUDE.md (Port Allocation table):
- Server port: Look up the application's port from the
Port Allocationtable in theCustom Applicationssection ofCLAUDE.md. Do NOT hardcode a default — the port MUST match the allocated port for this application.
Optional (use sensible defaults if not found in context):
- Default theme: Default
light(supportslight/dark) - Log level: Default
INFOfor application,WARNfor frameworks - Default locale: Default
en(only relevant if i18n = yes) - Supported locales: Derived from PRD.md language requirements (e.g.,
en,ms); default[en]
Generating the Specification
Once inputs are gathered from context files and optional components are determined,
generate the specification as a multi-file output split by module. Read the spec
template at references/spec-template.md for the exact structure and content of each
section. The template is the authoritative guide — follow it closely.
The specification is split into two categories:
- Root
SPECIFICATION.md— Contains the Table of Contents, shared infrastructure, and application-level sections that apply across all modules. - Per-module
<module-name>/SPEC.md— Each module gets its own folder with a self-contained specification file covering that module's complete blueprint.
This split enables a coding agent to:
- First, scaffold the shared infrastructure from
SPECIFICATION.md - Then, implement each module independently by picking up its
<module>/SPEC.md
Important: The generated spec must use real module data from the context files, not generic placeholders. Specifically:
- Modules must use the actual module names from PRD.md and MODEL.md
(e.g.,
locationInformation,corridor,employer— notmodule1,module2) - Document/Entity fields must match the actual fields defined in the module model
files (e.g.,
model/location-information/model.md), not placeholderfieldOne/fieldTwo - Service interfaces must expose methods matching the actual user stories (e.g., if
a story says "view provinces by country", the service needs
listProvincesByCountry()) - Page controllers must map to the actual mockup screens (e.g., if
hub_administrator/content/location_information.htmlexists, there must be a matching controller endpoint and JTE page). The controller URL is module-based (e.g.,/location-information), NOT role-prefixed (e.g., NOT/hub_administrator/location-information). The mockup's role folder determines@PreAuthorizeannotations, not URL structure. - Sidebar navigation must match the mockup sidebar files per role. Sidebar hrefs use
module-based paths (e.g.,
/corridor,/quota) — the role determines which items appear in the sidebar, not the URL prefix - Form fields must match what the mockup screens display
- Design tokens (colors, fonts) must match the MOCKUP.html Tailwind configuration
- Version tags: Every user story ID, NFR ID, constraint ID, and mockup screen in
the traceability section must include its version tag (e.g.,
USHM00228 [v1.0.3]). This enables incremental implementation by version. ALL traceability sub-tables (User Stories, NFRs, AND Constraints) MUST include the| Version |column. Do not omit the Version column from any table — even if a module only has v1.0.0 items. - Removed / Replaced items: The traceability section must include a "Removed / Replaced"
subsection listing any deprecated items from previous versions — showing the removed ID,
the version that removed it, the replacement ID (if any), and a brief reason. This
ensures developers can see what was removed and understand the evolution of requirements.
If a module has no removed items, include the subsection with
_None._to make it explicit that nothing was removed.
Output Structure
<app_folder>/context/specification/
├── SPECIFICATION.md ↠TOC + shared/application-level specs
├── location-information/
│ └── SPEC.md ↠Module blueprint for Location Information
├── corridor/
│ └── SPEC.md ↠Module blueprint for Corridor
├── employer/
│ └── SPEC.md ↠Module blueprint for Employer
├── ... ↠One folder per module from PRD.md
What Goes in SPECIFICATION.md (Root)
The root file contains the TOC and all shared/application-level sections. These are the sections that a coding agent implements first before any module work:
1. Project Overview
Project metadata, application description, technology stack summary, the complete
list of user roles extracted from mockup sidebar files, and the Module Index —
a table listing every module with a link to its <module>/SPEC.md file.
2. Maven Configuration
Complete pom.xml structure with all dependencies (core + selected conditional),
plugin configurations (MapStruct annotation processor, Spring Boot Maven plugin,
frontend-maven-plugin for Vite build, maven-clean-plugin to delete on-demand
jte-classes/ folder, jte-maven-plugin with precompile goal at process-classes
phase outputting to ${project.build.directory}/classes), and property management.
3. Application Configuration (conditional content varies)
A single application.yml (no profile-specific files like application-dev.yml or
application-prod.yml) covering database connection (MongoDB URI or JDBC datasource
depending on selection), auth settings (Keycloak/OAuth2 if selected, or form login if
selected), JTE configuration (with JTE_DEV_MODE and JTE_PRECOMPILED env vars),
scheduling config (if selected), theme defaults, and logging configuration. All environment-sensitive values (ports, hostnames, credentials,
URIs) MUST use Spring's ${ENV_VAR:default} syntax to allow externalization via
environment variables while keeping sensible defaults for local development. Do NOT use
Spring profiles or profile-specific YAML files — environment differences are handled
entirely through environment variables (e.g., via .env file locally or system
environment variables in deployment).
3a. Application-Specific Configuration (app: namespace)
All application-owned configuration — any config specific to THIS application, as
opposed to the Spring/Java ecosystem — MUST live under the top-level app: key in
application.yml. NEVER place application-specific keys under Spring framework
namespaces (spring.*, server.*, management.*, logging.*) — those are
reserved for framework configuration.
Grouping rule. Organise the app: tree by module:
- Cross-cutting values (version, shared feature flags, shared timeouts, CORS,
shared security settings, shared messaging infrastructure, shared object-storage
settings) sit directly under
app.*with no module prefix. - Per-module values are grouped under
app.<module-kebab-case>.*, one block per module that needs runtime config. A module with a single config value still gets its own block — do not flatten. - NEVER place module-specific keys at the YAML root (e.g., top-level
notification:,batch-job:,audit-trail:). They MUST be nested underapp:.
Naming rule. YAML keys use kebab-case (from-address, retry-limit,
max-retry). Spring Boot's relaxed binding maps them to camelCase Java fields
automatically. Do NOT use camelCase or snake_case in YAML.
Binding rule. For every app.* subtree (cross-cutting OR per-module), bind once
via @ConfigurationProperties on a record in the corresponding module's config
subpackage — or, for cross-cutting values, in the application-level config
subpackage. Do NOT inject individual values via @Value("${app....}") scattered
across beans or templates. Bind once at the module boundary and inject the typed record.
Environment-override rule. Every app.* leaf value MUST use Spring's
${ENV_VAR:default} syntax so it can be overridden per environment without editing
YAML. Every referenced ${ENV_VAR} MUST appear in the .env file generated in
section 3b.
Example structure:
app:
# Cross-cutting (no module prefix)
version: ${APP_VERSION:1.0.0}
cors:
allowed-origins: ${APP_CORS_ALLOWED_ORIGINS:http://localhost:3000}
security:
public-paths:
- /actuator/health
- /login
- /error
# Per-module blocks — one per module with runtime config
notification:
email:
from-address: ${NOTIFICATION_FROM_ADDRESS:noreply@example.com}
retry-limit: ${NOTIFICATION_RETRY_LIMIT:3}
cleanup:
retention-days: ${NOTIFICATION_RETENTION_DAYS:30}
batch-job:
cleanup:
retention-days: ${BATCH_JOB_RETENTION_DAYS:90}
audit-trail:
cleanup:
retention-days: ${AUDIT_TRAIL_RETENTION_DAYS:365}
Example cross-cutting record (app.*):
@ConfigurationProperties(prefix = "app")
public record AppProperties(String version, Cors cors, Security security) {
public record Cors(List<String> allowedOrigins) {}
public record Security(List<String> publicPaths) {}
}
Example per-module record (app.<module>.*):
@ConfigurationProperties(prefix = "app.notification")
public record NotificationProperties(
Email email,
Cleanup cleanup
) {
public record Email(String fromAddress, int retryLimit) {}
public record Cleanup(int retentionDays) {}
}
Enable binding at the application root with @ConfigurationPropertiesScan on the
main application class, or register each record individually via
@EnableConfigurationProperties on a @Configuration class in the owning module.
Mandatory cross-cutting values:
| Key | Purpose | Binding |
|---|---|---|
app.version |
Current application version; must match pom.xml <version> |
AppProperties.version() |
Additional cross-cutting keys may be added as the application grows, but
app.version is always present.
app.version specifics. The .env file must include APP_VERSION={version}
with the actual version value. The pom.xml <version> element MUST also be set to
the same version value (e.g., 1.0.3). When multiple versions were provided during
skill invocation, use the highest one. The application MUST expose this version in
the footer of every page. Expose it by injecting AppProperties into a
@ControllerAdvice-annotated class that registers appVersion as a global
@ModelAttribute, then read it from the shared footer layout (footer.jte or
footer.html) as ${appVersion} and render it as v{version} (e.g., v1.0.3).
Do NOT use @Value("${app.version}") in controllers or templates.
3b. .env File Generation from ENVIRONMENT.md
Generate a .env file at the project root by reading ENVIRONMENT.md from the project root.
The .env file maps ENVIRONMENT.md credential and platform values to the environment variable
names referenced in application.yml. The spec must define the complete .env content
with actual values from ENVIRONMENT.md.
Process:
- Read
ENVIRONMENT.mdfrom the project root - Extract credential values from
ENVIRONMENT.md(# Supporting 3rd Party Applicationsfor database hosts, ports, usernames, passwords, plus Keycloak/RabbitMQ); read toolchain paths (JDK, Maven, Node.js) fromDEVTOOL.md - Map each value to the corresponding
${ENV_VAR}name used inapplication.yml - Generate the
.envfile withKEY=valuepairs
Example .env output (derived from ENVIRONMENT.md):
# Database
DB_HOST=localhost
DB_PORT=3306
DB_NAME=hub_supp
DB_USERNAME=root
DB_PASSWORD=B3st1n3t@2025
# Authentication (Keycloak)
KEYCLOAK_HOST=http://localhost:8180
KEYCLOAK_REALM=urp
KEYCLOAK
…(truncated)