Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
81 changes: 57 additions & 24 deletions .agents/commands/adt/adk.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Comprehensive workflow for implementing a new ADK object type with full stack su
**Goal:** Fully understand the ABAP object type before implementation.

**Actions:**

1. Research the object type in SAP documentation
2. Identify ADT endpoint(s) for the object type:
- Discovery: `GET /sap/bc/adt/discovery` - find available endpoints
Expand All @@ -34,6 +35,7 @@ Comprehensive workflow for implementing a new ADK object type with full stack su
4. Identify if it's a repository object (transportable) or runtime object

**Output:** Object type analysis document with:

- ADT endpoint(s)
- Supported operations (CRUD + actions)
- Object relationships
Expand All @@ -46,6 +48,7 @@ Comprehensive workflow for implementing a new ADK object type with full stack su
**Goal:** Type-safe XML parsing for the object type.

**Actions:**

1. Capture sample XML responses from SAP:
- GET single object
- GET list/collection
Expand All @@ -60,6 +63,7 @@ Comprehensive workflow for implementing a new ADK object type with full stack su
5. **MANDATORY:** Create test scenario in `adt-schemas-xsd/tests/scenarios/`

**Output:**

- Schema in `adt-schemas-xsd/src/schemas/generated/` or `manual/`
- Test scenario with real SAP XML fixture
- Exported from index.ts
Expand All @@ -71,25 +75,30 @@ Comprehensive workflow for implementing a new ADK object type with full stack su
**Goal:** Type-safe API contract definition.

**Actions:**

1. Create contract in `adt-contracts/src/adt/{area}/`:

```typescript
import { contract } from '../../base';
import { mySchema } from '@abapify/adt-schemas-xsd';

export const myObject = {
get: (name: string) => contract({
method: 'GET',
path: `/sap/bc/adt/{area}/${name}`,
headers: { Accept: 'application/xml' },
responses: { 200: mySchema },
}),
get: (name: string) =>
contract({
method: 'GET',
path: `/sap/bc/adt/{area}/${name}`,
headers: { Accept: 'application/xml' },
responses: { 200: mySchema },
}),
// ... other operations
};
```

2. Export from area index and main index
3. **MANDATORY:** Create test scenario in `adt-contracts/tests/contracts/`

**Output:**

- Contract in `adt-contracts/src/adt/{area}/`
- Test scenario with contract validation
- Exported from index.ts
Expand All @@ -99,28 +108,33 @@ Comprehensive workflow for implementing a new ADK object type with full stack su
**Goal:** Business logic layer for complex operations.

**When needed:**

- Multi-step operations (create + activate + transport)
- Complex error handling
- Caching or optimization
- Cross-object coordination

**Actions:**

1. Create service in `adt-client-v2/src/services/{area}/`:

```typescript
export class MyObjectService {
constructor(private client: AdtClient) {}

async get(name: string): Promise<MyObject> {
const contract = myObjectContract.get(name);
return this.client.execute(contract);
}
// ... other methods
}
```

2. Register service in client factory
3. Add tests for service methods

**Output:**

- Service class in `adt-client-v2/src/services/`
- Service registration in client
- Unit tests
Expand All @@ -132,6 +146,7 @@ Comprehensive workflow for implementing a new ADK object type with full stack su
**Location:** `adk-v2/src/objects/{category}/{object_type}/`

**Files to create:**

1. `{type}.model.ts` - Main ADK object class
2. `{type}.types.ts` - TypeScript interfaces
3. `index.ts` - Exports
Expand Down Expand Up @@ -167,12 +182,14 @@ export type MyObjectData = MyObjectResponse;
```

**Why adt-client-v2 is the import source:**

- **Single dependency:** ADK only depends on `adt-client-v2`, not `adt-contracts` directly
- **Clean layering:** `adt-client-v2` re-exports contract types for consumers
- **Contract is still source of truth:** Types originate from contract, but flow through client
- **Simpler dependency graph:** ADK → client → contracts → schemas

**Dependency Architecture:**

```
adt-schemas-xsd (schema definitions)
Expand All @@ -184,6 +201,7 @@ adk-v2 (imports types from client only)
```

**Pattern:**

```typescript
// {type}.model.ts
import { AdkObject } from '../../../base/model';
Expand All @@ -195,39 +213,45 @@ export type MyObjectData = MyObjectResponse;

export class AdkMyObject extends AdkObject<typeof MyObjectKind, MyObjectData> {
readonly kind = MyObjectKind;
get objectUri(): string {
return `/sap/bc/adt/{area}/${encodeURIComponent(this.name)}`;

get objectUri(): string {
return `/sap/bc/adt/{area}/${encodeURIComponent(this.name)}`;
}

// Properties from schema
get description(): string { return this.dataSync.description; }

get description(): string {
return this.dataSync.description;
}

// Lazy-loaded relationships
async getRelated(): Promise<AdkRelated[]> {
return this.lazy('related', async () => {
// Load via service
});
}

// CRUD operations
async load(): Promise<this> {
const data = await this.ctx.services.myObject.get(this.name);
this.setData(data);
return this;
}

// Actions
async activate(): Promise<void> { /* ... */ }
async activate(): Promise<void> {
/* ... */
}
}
```

**Cross-object references:**

- Use `AdkContext` for accessing other object types
- Implement lazy loading for relationships
- Use `lazy()` helper for caching

**Output:**

- ADK object model with full type safety
- Lazy-loaded relationships
- CRUD + action methods
Expand All @@ -242,6 +266,7 @@ export class AdkMyObject extends AdkObject<typeof MyObjectKind, MyObjectData> {
See `/adt-command` workflow for detailed implementation guide.

**Quick summary:**

- Location: `adt-cli/src/lib/commands/{area}/`
- Uses `getAdtClientV2()` for client
- Uses router + pages for display
Expand All @@ -256,6 +281,7 @@ See `/adt-command` workflow for detailed implementation guide.
See `/adt-page` workflow for detailed implementation guide.

**Quick summary:**

- Location: `adt-cli/src/lib/ui/pages/{type}.ts`
- Self-registering via `definePage()`
- Uses ADK for data fetching
Expand All @@ -268,6 +294,7 @@ See `/adt-page` workflow for detailed implementation guide.
**Location:** `adt-tui/src/pages/{area}/`

**Pattern:**

```typescript
// pages/{area}/{type}-editor.tsx
import { useState } from 'react';
Expand All @@ -277,17 +304,17 @@ import { useNavigation } from '../../lib/context';
export function MyObjectEditor({ obj }: { obj: AdkMyObject }) {
const [description, setDescription] = useState(obj.description);
const { navigate } = useNavigation();

const save = async () => {
await obj.update({ description });
navigate('back');
};

return (
<Box flexDirection="column">
<Text>Edit {obj.name}</Text>
<TextInput
value={description}
<TextInput
value={description}
onChange={setDescription}
placeholder="Description"
/>
Expand All @@ -298,11 +325,13 @@ export function MyObjectEditor({ obj }: { obj: AdkMyObject }) {
```

**Integration:**

- Register page in TUI routes
- Connect to ADK object for save operations
- Handle validation and errors

**Output:**

- TUI editor page
- Form components for object fields
- Save/cancel actions
Expand All @@ -314,10 +343,12 @@ export function MyObjectEditor({ obj }: { obj: AdkMyObject }) {
**Location:** `plugins/abapgit/src/objects/{type}/`

**Files to create:**

1. `{type}-handler.ts` - Serialization/deserialization
2. `{type}-files.ts` - File mapping

**Pattern:**

```typescript
// objects/{type}/{type}-handler.ts
import { ObjectHandler } from '../../lib/handler';
Expand All @@ -326,22 +357,23 @@ import { AdkMyObject } from '@abapify/adk-v2';
export class MyObjectHandler implements ObjectHandler {
readonly objectType = 'MYOB';
readonly fileExtension = 'myob';

async serialize(obj: AdkMyObject): Promise<SerializedFiles> {
return {
[`${obj.name.toLowerCase()}.${this.fileExtension}.xml`]:
[`${obj.name.toLowerCase()}.${this.fileExtension}.xml`]:
this.buildMetadataXml(obj),
// Additional files (source code, etc.)
};
}

async deserialize(files: SerializedFiles): Promise<MyObjectData> {
// Parse files back to object data
}
}
```

**Register handler:**

```typescript
// objects/index.ts
import { MyObjectHandler } from './{type}/{type}-handler';
Expand All @@ -352,6 +384,7 @@ export const handlers = [
```

**Output:**

- Object handler for serialization
- File mapping for Git storage
- Round-trip tests
Expand Down
14 changes: 12 additions & 2 deletions .agents/commands/adt/command.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Create CLI commands for ADT object types.
```

**Why this order?**

- **ADK** - Encapsulates business logic, relationships, lazy loading
- **Service** - Reusable business logic, error handling
- **Contract** - Type-safe but low-level
Expand All @@ -65,6 +66,7 @@ Create CLI commands for ADT object types.
### Command Patterns

**Full CRUD cycle:**

- `get <id>` - Display single object
- `list` - List objects with filters
- `create` - Create new object
Expand All @@ -75,6 +77,7 @@ Create CLI commands for ADT object types.
### Client Initialization

**ALWAYS use shared helper:**

```typescript
import { getAdtClientV2 } from '../utils/adt-client-v2';
import { AdkTransportRequest } from '@abapify/adk-v2';
Expand All @@ -87,6 +90,7 @@ const transport = await AdkTransportRequest.get(number);
```

**Key points:**

- `getAdtClientV2()` automatically initializes ADK global context
- ADK objects can be used without passing context explicitly
- Context is optional - pass it only for testing or multi-connection scenarios
Expand All @@ -100,10 +104,11 @@ const transport = await AdkTransportRequest.get(number);
**Location:** `adt-cli/src/lib/commands/{area}/{type}.ts`

**Pattern:**

```typescript
/**
* adt {area} {type} - {Type} commands
*
*
* Uses ADK ({AdkType}) for operations.
*/

Expand Down Expand Up @@ -231,6 +236,7 @@ describe('{type} command', () => {
## Output Formatting Guidelines

### Emoji Indicators

- 🔄 - Loading/in progress
- 🔍 - Searching
- 📋 - Listing results
Expand All @@ -240,7 +246,9 @@ describe('{type} command', () => {
- 💾 - File saved

### JSON Output

**Always add `--json` flag:**

```typescript
if (options.json) {
console.log(JSON.stringify(data, null, 2));
Expand All @@ -251,6 +259,7 @@ if (options.json) {
```

### Error Handling

```typescript
try {
// Command logic
Expand All @@ -267,14 +276,15 @@ Commands should use the router for display:

```typescript
import { router } from '../../ui/router';
import '../../ui/pages/{type}'; // Trigger page registration
import '../../ui/pages/{type}'; // Trigger page registration

// In action handler:
const page = await router.navTo(client, '{TYPE_CODE}', { name: id });
page.print();
```

This separates:

- **Command** - Handles CLI args, options, auth, progress
- **Page** - Handles data fetching and rendering

Expand Down
Loading