mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-05-16 05:43:05 +08:00
Update/Add comprehensive tinystruct patterns reference documentation (#1895)
* feat: update tinystruct-patterns skill with comprehensive expert knowledge * Update skills/tinystruct-patterns/SKILL.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update skills/tinystruct-patterns/SKILL.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update skills/tinystruct-patterns/references/database.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update testing.md * Update database.md --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1,28 +1,38 @@
|
||||
---
|
||||
name: tinystruct-patterns
|
||||
description: Use when developing application modules or microservices with the tinystruct Java framework. Covers routing, context management, JSON handling with Builder, and CLI/HTTP dual-mode patterns.
|
||||
description: Expert guidance for developing with the tinystruct Java framework. Use when working on the tinystruct codebase or any project built on tinystruct — including creating Application classes, @Action-mapped routes, unit tests, ActionRegistry, HTTP/CLI dual-mode handling, the built-in HTTP server, the event system, JSON with Builder/Builders, database persistence with AbstractData, POJO generation, Server-Sent Events (SSE), file uploads, and outbound HTTP networking.
|
||||
origin: ECC
|
||||
---
|
||||
|
||||
# tinystruct Development Patterns
|
||||
|
||||
Architecture and implementation patterns for building modules with the **tinystruct** Java framework – a lightweight system where CLI and HTTP are equal citizens.
|
||||
Architecture and implementation patterns for building modules with the **tinystruct** Java framework – a lightweight, high-performance framework that treats CLI and HTTP as equal citizens, requiring no `main()` method and minimal configuration.
|
||||
|
||||
## When to Use
|
||||
## Core Principle
|
||||
|
||||
**CLI and HTTP are equal citizens.** Every method annotated with `@Action` should ideally be runnable from both a terminal and a web browser without modification. This "dual-mode" capability is the core design philosophy of tinystruct.
|
||||
|
||||
## When to Activate
|
||||
|
||||
### When to Use
|
||||
|
||||
- Creating new `Application` modules by extending `AbstractApplication`.
|
||||
- Defining routes and command-line actions using `@Action`.
|
||||
- Handling per-request state via `Context`.
|
||||
- Performing JSON serialization using the native `Builder` component.
|
||||
- Performing JSON serialization using the native `Builder` and `Builders` components.
|
||||
- Working with database persistence via `AbstractData` POJOs.
|
||||
- Generating POJOs from database tables using the `generate` command.
|
||||
- Implementing Server-Sent Events (SSE) for real-time push.
|
||||
- Handling file uploads via multipart data.
|
||||
- Making outbound HTTP requests with `URLRequest` and `HTTPHandler`.
|
||||
- Configuring database connections or system settings in `application.properties`.
|
||||
- Generating or re-generating the standard `bin/dispatcher` entry point via `ApplicationManager.init()`.
|
||||
- Debugging routing conflicts (Actions) or CLI argument parsing.
|
||||
|
||||
## How It Works
|
||||
|
||||
The tinystruct framework treats any method annotated with `@Action` as a routable endpoint for both terminal and web environments. Applications are created by extending `AbstractApplication`, which provides core lifecycle hooks like `init()` and access to the request `Context`.
|
||||
|
||||
Routing is handled by the `ActionRegistry`, which automatically maps path segments to method arguments and injects dependencies. For data-only services, the native `Builder` component should be used for JSON serialization to maintain a zero-dependency footprint. The framework also includes a utility in `ApplicationManager` to bootstrap the project's execution environment by generating the `bin/dispatcher` script.
|
||||
Routing is handled by the `ActionRegistry`, which automatically maps path segments to method arguments and injects dependencies. For data-only services, the native `Builder` and `Builders` components should be used for JSON serialization to maintain a zero-dependency footprint. The database layer uses `AbstractData` POJOs paired with XML mapping files for CRUD operations without external ORM libraries.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -40,38 +50,77 @@ public class MyService extends AbstractApplication {
|
||||
public String greet() {
|
||||
return "Hello from tinystruct!";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Parameterized Routing (getUser)
|
||||
```java
|
||||
// Handles /api/user/123 (Web) or "bin/dispatcher api/user/123" (CLI)
|
||||
@Action("api/user/(\\d+)")
|
||||
public String getUser(int userId) {
|
||||
return "User ID: " + userId;
|
||||
// Path parameter: GET /?q=greet/James OR bin/dispatcher greet/James
|
||||
@Action("greet")
|
||||
public String greet(String name) {
|
||||
return "Hello, " + name + "!";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### HTTP Mode Disambiguation (login)
|
||||
```java
|
||||
@Action(value = "login", mode = Mode.HTTP_POST)
|
||||
public boolean doLogin() {
|
||||
// Process login logic
|
||||
return true;
|
||||
public String doLogin(Request<?, ?> request) throws ApplicationException {
|
||||
request.getSession().setAttribute("userId", "42");
|
||||
return "Logged in";
|
||||
}
|
||||
```
|
||||
|
||||
### Native JSON Data Handling (getData)
|
||||
### Native JSON Data Handling (Builder + Builders)
|
||||
```java
|
||||
import org.tinystruct.data.component.Builder;
|
||||
import org.tinystruct.data.component.Builders;
|
||||
|
||||
@Action("api/data")
|
||||
public Builder getData() throws ApplicationException {
|
||||
Builder builder = new Builder();
|
||||
builder.put("status", "success");
|
||||
Builder nested = new Builder();
|
||||
nested.put("id", 1);
|
||||
nested.put("name", "James");
|
||||
builder.put("data", nested);
|
||||
return builder;
|
||||
public String getData() throws ApplicationException {
|
||||
Builders dataList = new Builders();
|
||||
Builder item = new Builder();
|
||||
item.put("id", 1);
|
||||
item.put("name", "James");
|
||||
dataList.add(item);
|
||||
|
||||
Builder response = new Builder();
|
||||
response.put("status", "success");
|
||||
response.put("data", dataList);
|
||||
return response.toString(); // {"status":"success","data":[{"id":1,"name":"James"}]}
|
||||
}
|
||||
```
|
||||
|
||||
### SSE (Server-Sent Events)
|
||||
```java
|
||||
import org.tinystruct.http.SSEPushManager;
|
||||
|
||||
@Action("sse/connect")
|
||||
public String connect() {
|
||||
return "{\"type\":\"connect\",\"message\":\"Connected to SSE\"}";
|
||||
}
|
||||
|
||||
// Push to a specific client
|
||||
String sessionId = getContext().getId();
|
||||
Builder msg = new Builder();
|
||||
msg.put("text", "Hello, user!");
|
||||
SSEPushManager.getInstance().push(sessionId, msg);
|
||||
|
||||
// Broadcast to all
|
||||
// Broadcast to all
|
||||
SSEPushManager.getInstance().broadcast(msg);
|
||||
```
|
||||
|
||||
### File Upload
|
||||
```java
|
||||
import org.tinystruct.data.FileEntity;
|
||||
|
||||
@Action(value = "upload", mode = Mode.HTTP_POST)
|
||||
public String upload(Request<?, ?> request) throws ApplicationException {
|
||||
List<FileEntity> files = request.getAttachments();
|
||||
if (files != null) {
|
||||
for (FileEntity file : files) {
|
||||
System.out.println("Uploaded: " + file.getFilename());
|
||||
}
|
||||
}
|
||||
return "Upload OK";
|
||||
}
|
||||
```
|
||||
|
||||
@@ -83,35 +132,48 @@ Settings are managed in `src/main/resources/application.properties`.
|
||||
# Database
|
||||
driver=org.h2.Driver
|
||||
database.url=jdbc:h2:~/mydb
|
||||
database.user=sa
|
||||
database.password=
|
||||
|
||||
# App specific
|
||||
my.service.endpoint=https://api.example.com
|
||||
# Server
|
||||
default.home.page=hello
|
||||
server.port=8080
|
||||
|
||||
# Locale
|
||||
default.language=en_US
|
||||
|
||||
# Session (Redis for clustered environments)
|
||||
# default.session.repository=org.tinystruct.http.RedisSessionRepository
|
||||
# redis.host=127.0.0.1
|
||||
# redis.port=6379
|
||||
```
|
||||
|
||||
## Testing Patterns
|
||||
|
||||
Use JUnit 5 to test actions by verifying they are registered in the `ActionRegistry`.
|
||||
|
||||
Access config values in your application:
|
||||
```java
|
||||
@Test
|
||||
void testActionRegistration() {
|
||||
Application app = new MyService();
|
||||
app.init();
|
||||
|
||||
ActionRegistry registry = ActionRegistry.getInstance();
|
||||
assertNotNull(registry.get("greet"));
|
||||
}
|
||||
String port = this.getConfiguration("server.port");
|
||||
```
|
||||
|
||||
## Red Flags & Anti-patterns
|
||||
|
||||
| Symptom | Correct Pattern |
|
||||
|---|---|
|
||||
| Importing `com.google.gson` or `com.fasterxml.jackson` | Use `org.tinystruct.data.component.Builder`. |
|
||||
| `FileNotFoundException` for `.view` files | Call `setTemplateRequired(false)` in `init()` for API-only apps. |
|
||||
| Importing `com.google.gson` or `com.fasterxml.jackson` | Use `org.tinystruct.data.component.Builder` / `Builders`. |
|
||||
| Using `List<Builder>` for JSON arrays | Use `Builders` to avoid generic type erasure issues. |
|
||||
| `ApplicationRuntimeException: template not found` | Call `setTemplateRequired(false)` in `init()` for API-only apps. |
|
||||
| Annotating `private` methods with `@Action` | Actions must be `public` to be registered by the framework. |
|
||||
| Hardcoding `main(String[] args)` in apps | Use `bin/dispatcher` as the entry point for all modules. |
|
||||
| Manual `ActionRegistry` registration | Prefer the `@Action` annotation for automatic discovery. |
|
||||
| Action not found at runtime | Ensure class is imported via `--import` or listed in `application.properties`. |
|
||||
| CLI arg not visible | Pass with `--key value`; access via `getContext().getAttribute("--key")`. |
|
||||
| Two methods same path, wrong one fires | Set explicit `mode` (e.g., `HTTP_GET` vs `HTTP_POST`) to disambiguate. |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Granular Applications**: Break logic into smaller, focused applications rather than one monolithic class.
|
||||
2. **Setup in `init()`**: Leverage `init()` for setup (config, DB) rather than the constructor. Do NOT call `setAction()` — use `@Action` annotation.
|
||||
3. **Mode Awareness**: Use the `Mode` parameter in `@Action` to restrict sensitive operations to `CLI` only or specific HTTP methods.
|
||||
4. **Context over Params**: For optional CLI flags, use `getContext().getAttribute("--flag")` rather than adding parameters to the method signature.
|
||||
5. **Asynchronous Events**: For heavy tasks triggered by events, use `CompletableFuture.runAsync()` inside the event handler.
|
||||
|
||||
## Technical Reference
|
||||
|
||||
@@ -119,13 +181,23 @@ Detailed guides are available in the `references/` directory:
|
||||
|
||||
- [Architecture & Config](references/architecture.md) — Abstractions, Package Map, Properties
|
||||
- [Routing & @Action](references/routing.md) — Annotation details, Modes, Parameters
|
||||
- [Data Handling](references/data-handling.md) — Using the native `Builder` for JSON
|
||||
- [System & Usage](references/system-usage.md) — Context, Sessions, Events, CLI usage
|
||||
- [Testing Patterns](references/testing.md) — JUnit 5 integration and ActionRegistry testing
|
||||
- [Data Handling](references/data-handling.md) — Builder, Builders, JSON serialization & parsing
|
||||
- [Database Persistence](references/database.md) — AbstractData POJOs, CRUD, mapping XML, POJO generation
|
||||
- [System & Usage](references/system-usage.md) — Context, Sessions, SSE, File Uploads, Events, Networking
|
||||
- [Testing Patterns](references/testing.md) — JUnit 5 unit and HTTP integration testing
|
||||
|
||||
## Reference Source Files (Internal)
|
||||
|
||||
- `src/main/java/org/tinystruct/AbstractApplication.java` — Core base class
|
||||
- `src/main/java/org/tinystruct/AbstractApplication.java` — Core base class with lifecycle hooks
|
||||
- `src/main/java/org/tinystruct/system/annotation/Action.java` — Annotation & Modes
|
||||
- `src/main/java/org/tinystruct/application/ActionRegistry.java` — Routing Engine
|
||||
- `src/main/java/org/tinystruct/data/component/Builder.java` — JSON/Data Serializer
|
||||
- `src/main/java/org/tinystruct/data/component/Builder.java` — JSON object serializer
|
||||
- `src/main/java/org/tinystruct/data/component/Builders.java` — JSON array serializer
|
||||
- `src/main/java/org/tinystruct/data/component/AbstractData.java` — Base POJO class with CRUD
|
||||
- `src/main/java/org/tinystruct/data/Mapping.java` — Mapping XML parser
|
||||
- `src/main/java/org/tinystruct/data/tools/MySQLGenerator.java` — POJO generator reference
|
||||
- `src/main/java/org/tinystruct/data/component/FieldType.java` — SQL-to-Java type mappings
|
||||
- `src/main/java/org/tinystruct/data/component/Condition.java` — Fluent SQL query builder
|
||||
- `src/main/java/org/tinystruct/http/SSEPushManager.java` — SSE connection management
|
||||
- `src/test/java/org/tinystruct/application/ActionRegistryTest.java` — Registry test examples
|
||||
- `src/test/java/org/tinystruct/system/HttpServerHttpModeTest.java` — HTTP integration test patterns
|
||||
|
||||
Reference in New Issue
Block a user