skills/.system/activitymaster/SKILL.md
Open-source implementation of the Functional Service Data Model (FSDM) for enterprise resource management. Provides canonical domain services (Enterprise, Address, Events, Arrangements, ResourceItem, Classification) with reactive persistence via Hibernate Reactive 7, Vert.x 5, GuicedEE DI, and PostgreSQL. Features security token propagation, ActiveFlag row-state enforcement, client libraries, and modular service APIs. Use when working with Activity Master services, FSDM domain models, enterprise management, reactive persistence, or building applications with canonical warehouse schemas.
npx skillsauth add guicedee/ai-rules activitymasterInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Open-source implementation of the Functional Service Data Model (FSDM) for enterprise resource management.
ActivityMaster is a comprehensive enterprise platform built on:
See references/fsdm-services.md for complete service reference.
Manages organizations, companies, and business entities:
Geographic location management:
Event and activity tracking:
Resource arrangements and bookings:
Physical and virtual resource management:
Taxonomies and categorization:
Core FSDM implementation with domain entities and services:
<dependency>
<groupId>com.guicedee.activitymaster</groupId>
<artifactId>activity-master</artifactId>
</dependency>
Features:
Client library for consuming Activity Master services:
<dependency>
<groupId>com.guicedee.activitymaster</groupId>
<artifactId>activity-master-client</artifactId>
</dependency>
Features:
Bill of Materials for version management:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.guicedee.activitymaster</groupId>
<artifactId>activitymaster-bom</artifactId>
<version>${activitymaster.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
See references/feature-modules.md for detailed coverage.
Serialization framework for Activity Master:
Client library for cerial services:
Copy .env.example to .env:
cp .env.example .env
Configure database and authentication:
DB_URL=jdbc:postgresql://localhost:5432/activitymaster
DB_USER=postgres
DB_PASS=secretpassword
JWT_TEST_TOKEN=your-test-token
OAUTH2_ISSUER_URL=https://auth.example.com
JWKS_URI=https://auth.example.com/.well-known/jwks.json
mvn -B clean verify
@Inject
private IActivityMasterService activityMaster;
@Inject
private IEnterpriseService enterpriseService;
public void createEnterprise() {
// Create new enterprise with fluent builder
Enterprise enterprise = new Enterprise()
.setName("ACME Corporation")
.setDescription("Leading widget manufacturer")
.setActiveFlag(ActiveFlag.Active);
// Persist reactively
enterpriseService.createEnterprise(enterprise)
.invoke(created -> log.info("Created: {}", created.getId()))
.await().indefinitely();
}
All services propagate SecurityToken for access control:
public interface IEnterpriseService {
Uni<Enterprise> createEnterprise(Enterprise enterprise);
Uni<Enterprise> updateEnterprise(Enterprise enterprise, SecurityToken token);
Uni<Optional<Enterprise>> getEnterprise(String id, SecurityToken token);
Uni<List<Enterprise>> listEnterprises(SecurityToken token);
}
Built-in token caching for system operations:
// System token cache helper
String systemToken = SYSTEM_TOKEN_CACHE.get();
// Use cached token for service calls
enterpriseService.getEnterprise(id, systemToken)
.await().indefinitely();
All entities support ActiveFlag row-state management:
public enum ActiveFlag {
Unknown, // Initial/undefined state
Deleted, // Soft-deleted
Active, // Active/visible
Permanent // Cannot be deleted
}
// Query only active records
var qb = new Enterprise().builder(session);
qb.where(qb.getAttribute("activeFlag"), Operand.Equals, ActiveFlag.Active)
.getAll();
// Soft delete
enterprise.setActiveFlag(ActiveFlag.Deleted);
enterpriseService.updateEnterprise(enterprise, token);
// Range queries
qb.where(qb.getAttribute("activeFlag"),
Operand.InList,
ActiveFlag.getActiveRange()); // Active to Permanent
See references/enterprise-lifecycle.md for detailed flow.
createNewEnterprise() → loadUpdates() → startNewEnterprise()
ISystemUpdate/@SortedUpdateIPasswordsService, execute post-startupSystem updates use @SortedUpdate for ordered execution:
@SortedUpdate(order = 100)
public class LoadClassifications implements ISystemUpdate {
@Override
public void executeUpdate(Session session) {
// Load classification data
}
}
Register via module-info.java:
provides ISystemUpdate with LoadClassifications;
sessionFactory.withSession(session ->
session.withTransaction(tx ->
enterpriseService.createEnterprise(enterprise)
.chain(created ->
addressService.createAddress(address, created.getId())
)
.chain(address ->
eventService.createEvent(event, address.getEnterpriseId())
)
.invoke(event -> log.info("Complete chain: {}", event.getId()))
)
);
Uni<Enterprise> enterpriseUni = enterpriseService.getEnterprise(id, token);
Uni<List<Address>> addressesUni = addressService.listAddresses(id, token);
Uni<List<Event>> eventsUni = eventService.listEvents(id, token);
Uni.combine().all()
.unis(enterpriseUni, addressesUni, eventsUni)
.asTuple()
.invoke(tuple -> {
Enterprise enterprise = tuple.getItem1();
List<Address> addresses = tuple.getItem2();
List<Event> events = tuple.getItem3();
// Process combined results
});
enterpriseService.createEnterprise(enterprise)
.onFailure().recoverWithUni(throwable -> {
log.error("Failed to create enterprise", throwable);
return Uni.createFrom().item(fallbackEnterprise);
})
.onFailure().retry().atMost(3);
@EntityManager(value = "activityMaster", defaultEm = true)
public class ActivityMasterDBModule
extends DatabaseModule<ActivityMasterDBModule>
implements IGuiceModule<ActivityMasterDBModule> {
@Override
protected String getPersistenceUnitName() {
return "activityMaster";
}
@Override
protected ConnectionBaseInfo getConnectionBaseInfo(
PersistenceUnitDescriptor unit, Properties filteredProperties) {
PostgresConnectionBaseInfo info = new PostgresConnectionBaseInfo();
info.setServerName(System.getenv("DB_HOST"));
info.setPort(System.getenv("DB_PORT"));
info.setDatabaseName(System.getenv("DB_NAME"));
info.setUsername(System.getenv("DB_USER"));
info.setPassword(System.getenv("DB_PASS"));
info.setDefaultConnection(true);
info.setReactive(true);
return info;
}
@Override
protected String getJndiMapping() {
return "jdbc:activityMaster";
}
}
module com.myapp.activitymaster {
requires com.guicedee.activitymaster;
requires com.guicedee.activitymaster.client;
requires com.entityassist;
requires com.guicedee.persistence;
opens com.myapp.activitymaster.entities
to org.hibernate.orm.core, com.google.guice, com.entityassist;
provides IGuiceModule with ActivityMasterDBModule;
}
@EntityManager(value = "activityMasterTest", defaultEm = true)
public class PostgreSQLTestDBModule
extends DatabaseModule<PostgreSQLTestDBModule>
implements IGuiceModule<PostgreSQLTestDBModule> {
private static final PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>(System.getenv("TEST_DB_CONTAINER_IMAGE"))
.withDatabaseName("activitymaster_test")
.withUsername("postgres")
.withPassword("postgres");
static { postgres.start(); }
@Override
protected ConnectionBaseInfo getConnectionBaseInfo(
PersistenceUnitDescriptor unit, Properties filteredProperties) {
PostgresConnectionBaseInfo info = new PostgresConnectionBaseInfo();
info.setServerName(postgres.getHost());
info.setPort(String.valueOf(postgres.getFirstMappedPort()));
info.setDatabaseName(postgres.getDatabaseName());
info.setUsername(postgres.getUsername());
info.setPassword(postgres.getPassword());
info.setReactive(true);
return info;
}
}
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class ActivityMasterTest {
@Inject
private IEnterpriseService enterpriseService;
private Mutiny.SessionFactory sessionFactory;
@BeforeAll
public void setup() {
IGuiceContext.instance();
sessionFactory = IGuiceContext.get(
Key.get(Mutiny.SessionFactory.class, Names.named("activityMaster")));
}
@Test
void testEnterpriseLifecycle() {
Enterprise enterprise = new Enterprise()
.setName("Test Corp")
.setActiveFlag(ActiveFlag.Active);
sessionFactory.withSession(session ->
session.withTransaction(tx ->
enterpriseService.createEnterprise(enterprise)
.chain(created ->
enterpriseService.getEnterprise(created.getId(), null)
)
.invoke(retrieved -> {
assertNotNull(retrieved);
assertEquals("Test Corp", retrieved.get().getName());
})
)
).await().indefinitely();
}
}
// Enterprise creation with fluent builder
EnterpriseCreateRequest request = new EnterpriseCreateRequest()
.setName("ACME Corp")
.setDescription("Widget manufacturer")
.setActiveFlag(ActiveFlag.Active)
.setSecurityToken(token);
enterpriseService.create(request)
.await().indefinitely();
// Type-safe query building
var qb = new Enterprise().builder(session);
List<Enterprise> results = qb
.where(qb.getAttribute("name"), Operand.Like, "ACME%")
.where(qb.getAttribute("activeFlag"), Operand.Equals, ActiveFlag.Active)
.orderBy(qb.getAttribute("name"), OrderByType.ASC)
.setMaxResults(50)
.getAll()
.await().indefinitely();
See references/configuration.md for complete reference.
| Variable | Purpose | Required |
|---|---|---|
| DB_URL | PostgreSQL JDBC URL | Yes |
| DB_USER | Database username | Yes |
| DB_PASS | Database password | Yes |
| DB_HOST | Database hostname | Yes |
| DB_PORT | Database port | Yes |
| DB_NAME | Database name | Yes |
| JWT_TEST_TOKEN | Test JWT token | Test only |
| OAUTH2_ISSUER_URL | OAuth2 issuer URL | Yes |
| JWKS_URI | JWKS endpoint | Yes |
| TEST_DB_CONTAINER_IMAGE | Testcontainers image | Test only |
| ENVIRONMENT | Runtime environment | No |
| TRACING_ENABLED | Enable distributed tracing | No |
| ENABLE_DEBUG_LOGS | Enable debug logging | No |
USERNAME — GitHub username for publishingUSER_TOKEN — GitHub tokenSONA_USERNAME — Sonatype usernameSONA_PASSWORD — Sonatype passwordPOSTGRES_APP_PASSWORD — PostgreSQL application passwordKEYCLOAK_ADMIN_PASSWORD — Keycloak admin passwordActivity Master follows strict documentation governance:
Forward-Only Rule: Stage 1/2 documents must be updated before Stage 3/4 code changes.
The skills submodule is the canonical source for enterprise skills and domain knowledge. Host-specific docs live at repo root and link back to the submodule.
Important: Treat the skills submodule as read-only; do not modify its contents.
Main service interface aggregating all FSDM services:
public interface IActivityMasterService {
IEnterpriseService enterprises();
IAddressService addresses();
IEventsService events();
IArrangementsService arrangements();
IResourceItemService resources();
IClassificationService classifications();
}
public interface IEnterpriseService {
Uni<Enterprise> createEnterprise(Enterprise enterprise);
Uni<Enterprise> updateEnterprise(Enterprise enterprise, SecurityToken token);
Uni<Void> deleteEnterprise(String id, SecurityToken token);
Uni<Optional<Enterprise>> getEnterprise(String id, SecurityToken token);
Uni<List<Enterprise>> listEnterprises(SecurityToken token);
Uni<List<Enterprise>> searchEnterprises(String query, SecurityToken token);
}
public interface IAddressService {
Uni<Address> createAddress(Address address, String enterpriseId);
Uni<Address> updateAddress(Address address, SecurityToken token);
Uni<Void> deleteAddress(String id, SecurityToken token);
Uni<Optional<Address>> getAddress(String id, SecurityToken token);
Uni<List<Address>> listAddresses(String enterpriseId, SecurityToken token);
Uni<Address> validateAddress(Address address);
}
public interface IEventsService {
Uni<Event> createEvent(Event event, String enterpriseId);
Uni<Event> updateEvent(Event event, SecurityToken token);
Uni<Void> cancelEvent(String id, SecurityToken token);
Uni<Optional<Event>> getEvent(String id, SecurityToken token);
Uni<List<Event>> listEvents(String enterpriseId, SecurityToken token);
Uni<List<Event>> listEventsByDateRange(LocalDate start, LocalDate end, SecurityToken token);
}
Always pass SecurityToken for access-controlled operations:
// ✅ Good
enterpriseService.getEnterprise(id, token);
// ❌ Bad
enterpriseService.getEnterprise(id, null); // No security context
Use ActiveFlag for soft deletes:
// ✅ Good - Soft delete
enterprise.setActiveFlag(ActiveFlag.Deleted);
enterpriseService.updateEnterprise(enterprise, token);
// ❌ Avoid hard deletes unless necessary
enterpriseService.deleteEnterprise(id, token);
Chain operations with Uni:
// ✅ Good - Reactive chaining
enterpriseService.createEnterprise(enterprise)
.chain(created -> addressService.createAddress(address, created.getId()))
.await().indefinitely();
// ❌ Bad - Blocking
Enterprise created = enterpriseService.createEnterprise(enterprise)
.await().indefinitely();
Address address = addressService.createAddress(address, created.getId())
.await().indefinitely();
Always open entity packages:
// ✅ Required for Hibernate + Guice
opens com.myapp.entities to org.hibernate.orm.core, com.google.guice, com.entityassist;
Re-use existing test harness for coverage:
// ✅ Good - Use JUnit 5 + Testcontainers
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MyTest {
// Use existing PostgreSQLTestDBModule
}
Check .env variables:
echo $DB_URL
echo $DB_USER
Verify PostgreSQL is running:
psql -h localhost -U postgres -d activitymaster
Verify OAuth2 configuration:
echo $OAUTH2_ISSUER_URL
echo $JWKS_URI
Check token cache:
String token = SYSTEM_TOKEN_CACHE.get();
log.info("System token: {}", token);
Enable debug logging:
export ENABLE_DEBUG_LOGS=true
Check session factory initialization:
Mutiny.SessionFactory factory = IGuiceContext.get(
Key.get(Mutiny.SessionFactory.class, Names.named("activityMaster")));
assertNotNull(factory);
<!-- BOM for version management -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.guicedee.activitymaster</groupId>
<artifactId>activitymaster-bom</artifactId>
<version>${activitymaster.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- Core module -->
<dependency>
<groupId>com.guicedee.activitymaster</groupId>
<artifactId>activity-master</artifactId>
</dependency>
<!-- Client module -->
<dependency>
<groupId>com.guicedee.activitymaster</groupId>
<artifactId>activity-master-client</artifactId>
</dependency>
com.guicedee.activitymasterFor detailed service documentation: See references/fsdm-services.md For module details: See references/feature-modules.md For configuration: See references/configuration.md For enterprise lifecycle: See references/enterprise-lifecycle.md
development
Install Codex skills into $CODEX_HOME/skills from a curated list or a GitHub repo path. Use when a user asks to list installable skills, install a curated skill, or install a skill from another repo (including private repos).
tools
Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Codex's capabilities with specialized knowledge, workflows, or tool integrations.
development
WebAwesome icon integration for JWebMP — modern, open-source icon library. Provides 1,500+ icons with solid/regular styles, sizing, rotation, animation, and CSS utilities. Drop-in FontAwesome alternative with fresh designs. Use when working with WebAwesome icons, modern icon designs, or as FontAwesome alternative in JWebMP applications.
development
WebAwesome Pro integration for JWebMP with premium icons and features. Extends jwebmp-webawesome with additional styles, premium icons, and advanced features. Use when working with WebAwesome Pro icons or premium WebAwesome features in JWebMP applications.