Skip to content
Open
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
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
47 changes: 47 additions & 0 deletions components/ambient-api-server/.claude/commands/trex.db.setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Set Up Database

Start a fresh PostgreSQL container and run all migrations. If a database already exists, this will tear it down first.

## Instructions

1. Check if a PostgreSQL container is already running:
```bash
docker ps -a --filter name=ambient-api-server-postgres --format "{{.Names}} {{.Status}}"
```

2. If a container exists, tear it down first:
```bash
make db/teardown
```

3. Start a fresh PostgreSQL container:
```bash
make db/setup
```

4. Wait for PostgreSQL to be ready:
```bash
sleep 2
```

5. Build the binary if not already built:
```bash
make binary
```

6. Run migrations:
```bash
./ambient-api-server migrate
```

## When to Use This

- First-time database setup
- After generating a new Kind (new migration added)
- After pulling changes that include new migrations
- When integration tests fail with "relation does not exist" or column errors
- When the database schema is corrupted or out of sync

## Database Connection Details

Connection details are stored in the `secrets/` directory files (`db.host`, `db.port`, `db.name`, `db.user`, `db.password`).
105 changes: 105 additions & 0 deletions components/ambient-api-server/.claude/commands/trex.kind.add-field.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Add a Field to an Existing Kind

Add a new field to an existing Kind, updating all layers consistently.

## Instructions

Ask the user for:
1. **Kind name** (PascalCase): e.g., "Dinosaur"
2. **Field name** (snake_case): e.g., "habitat_type"
3. **Field type**: `string`, `int`, `int64`, `bool`, `float64`, `time.Time`
4. **Required or nullable**: required fields use base types (`string`), nullable use pointers (`*string`)

Derive the Go field name in PascalCase (e.g., `habitat_type` -> `HabitatType`).

Use the TodoWrite tool to track progress.

### Step 1: Update API Model (`pkg/api/{kind}.go`)

Add the field to the `{Kind}` struct:
```go
HabitatType string `json:"habitat_type"`
```

Add the field to `{Kind}PatchRequest` as a pointer:
```go
HabitatType *string `json:"habitat_type,omitempty"`
```

### Step 2: Create a New Migration File

**IMPORTANT**: Create a brand new migration file at `pkg/db/migrations/{YYYYMMDDHHMM}_add_{field}_to_{kindLowerPlural}.go`. Do NOT modify the Kind's existing migration.

```go
package migrations

import (
"gorm.io/gorm"
"github.com/go-gormigrate/gormigrate/v2"
)

func add{FieldPascalCase}To{KindPlural}() *gormigrate.Migration {
type {Kind} struct {
Model
{FieldPascalCase} {GoType}
}

return &gormigrate.Migration{
ID: "{YYYYMMDDHHMM}",
Migrate: func(tx *gorm.DB) error {
return tx.AutoMigrate(&{Kind}{})
},
Rollback: func(tx *gorm.DB) error {
return tx.Migrator().DropColumn(&{Kind}{}, "{field_snake_case}")
},
}
}
```

Register it in `pkg/db/migrations/migration_structs.go` by appending to `MigrationList`.

### Step 3: Update Presenter (`pkg/api/presenters/{kind}.go`)

Add the field to both `Convert{Kind}()` and `Present{Kind}()` functions, handling the type conversion between internal and OpenAPI models.

### Step 4: Update Handler (`pkg/handlers/{kind}.go`)

In the `Patch` method, add the nil-check for the new field:
```go
if patch.{FieldPascalCase} != nil {
found.{FieldPascalCase} = patch.{FieldPascalCase}
}
```

### Step 5: Update OpenAPI Spec (`openapi/openapi.{kindLowerPlural}.yaml`)

Add the field to three schema sections:
- `{Kind}` schema properties
- `{Kind}PatchRequest` schema properties
- If required: add to the `required` array

### Step 6: Regenerate OpenAPI Client

```bash
make generate
```

Wait for completion, then verify the new field appears in:
- `pkg/api/openapi/model_{kind_snake_case}.go`
- `pkg/api/openapi/model_{kind_snake_case}_patch_request.go`

### Step 7: Build and Test

```bash
make binary
make test-integration
```

### Common Pitfalls

- Forgetting to add the migration to `MigrationList`
- Type mismatch between Go model (`int`) and OpenAPI model (`int32`) in the presenter
- Missing the field in the PatchRequest struct
- Forgetting to handle nullable fields with pointer dereferencing in presenters

**Note**: Integration tests use testcontainers, which provisions a fresh PostgreSQL instance automatically. No manual `db/teardown` or `db/setup` is needed for tests. However, if running the server locally, use `/trex.db.setup` to recreate the database with the new migration.
85 changes: 85 additions & 0 deletions components/ambient-api-server/.claude/commands/trex.kind.new.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Generate a New Kind

Generate a complete CRUD entity (Kind) using the automated generator script.

## Instructions

Use the TodoWrite tool to track progress.

### Step 1: Gather Requirements

Ask the user for:
1. **Kind name** (singular, PascalCase): e.g., "Widget", "Rocket", "Customer"
2. **Fields** beyond the base Meta fields (optional):
- Name (use snake_case): e.g., "fuel_type", "max_speed"
- Type: `string`, `int`, `int64`, `bool`, `float64`, `time`
- Nullability: `:required` or `:optional` (default: nullable)

### Step 2: Run the Generator

```bash
go run ./scripts/generator.go --kind {KindName}
```

With custom fields:
```bash
go run ./scripts/generator.go --kind {KindName} --fields "{field1}:{type1}:{nullability},{field2}:{type2}"
```

Example:
```bash
go run ./scripts/generator.go --kind Rocket --fields "name:string:required,fuel_type:string,max_speed:int"
```

The generator automatically:
- Creates 11 new files (plugin, model, DAO, mock, service, presenters, handlers, migration, OpenAPI spec, test factory, integration tests)
- Modifies 3 existing files (`cmd/ambient-api-server/main.go`, `pkg/db/migrations/migration_structs.go`, `openapi/openapi.yaml`)
- Runs `make generate` to regenerate the OpenAPI client
- Formats all Go files with `gofmt`

### Step 3: Build and Verify

```bash
make binary
```

Fix any compilation errors if they occur.

### Step 4: Test

```bash
make test-integration
```

Or run just the new Kind's tests:
```bash
TESTFLAGS="-run Test{Kind}" make test-integration
```

## Field Type Reference

| User Type | Go (required) | Go (nullable) | OpenAPI type | OpenAPI format | DB Type |
|-----------|--------------|---------------|-------------|---------------|---------|
| string | `string` | `*string` | string | | varchar |
| int | `int` | `*int` | integer | int32 | integer |
| int64 | `int64` | `*int64` | integer | int64 | bigint |
| bool | `bool` | `*bool` | boolean | | boolean |
| float64 | `float64` | `*float64` | number | double | float8 |
| time | `time.Time` | `*time.Time` | string | date-time | timestamptz |

## Naming Convention Reference

| Context | Convention | Example |
|---------|-----------|---------|
| Go struct | PascalCase | `ProductCategory` |
| Go variable | camelCase | `productCategory` |
| Go package | lowercase plural | `productcategorys` |
| API path | snake_case plural | `/product_categorys` |
| JSON field | snake_case | `category_name` |
| DB table | snake_case plural | `product_categorys` |
| DB column | snake_case | `category_name` |
| Plugin registry | PascalCase plural | `ProductCategorys` |

Rules:
- Plural: always append "s" (not "es" or "ies")
- snake_case: insert `_` before each uppercase letter, then lowercase everything
96 changes: 96 additions & 0 deletions components/ambient-api-server/.claude/commands/trex.kind.remove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Remove a Kind

Completely remove a generated Kind and all its artifacts from the project.

## Instructions

Ask the user for the **Kind name** (PascalCase, e.g., "Widget").

Derive the naming variants (see `/trex.kind.new` for the full table):
- `Kind` = PascalCase (e.g., `Widget`)
- `kindLowerPlural` = camelCase plural (e.g., `widgets`)
- `kind_snake_case` = snake_case (e.g., `widget`)

Use the TodoWrite tool to track progress.

### Step 1: Verify the Kind Exists

Check that the Kind's files exist before removing:
```bash
ls plugins/{kindLowerPlural}/plugin.go
ls pkg/api/{kind}.go
ls pkg/services/{kind}.go
```

If files don't exist, inform the user and stop.

### Step 2: Remove Generated Files (11 files)

Delete all files created by the generator:

```bash
rm -rf plugins/{kindLowerPlural}/
rm -f pkg/api/{kind}.go
rm -f pkg/api/presenters/{kind}.go
rm -f pkg/handlers/{kind}.go
rm -f pkg/services/{kind}.go
rm -f pkg/dao/{kind}.go
rm -f pkg/dao/mocks/{kind}.go
rm -f pkg/db/migrations/*_add_{kindLowerPlural}.go
rm -f openapi/openapi.{kindLowerPlural}.yaml
rm -f test/integration/{kindLowerPlural}_test.go
rm -f test/factories/{kindLowerPlural}.go
```

### Step 3: Remove Generated OpenAPI Client Files

```bash
rm -f pkg/api/openapi/model_{kind_snake_case}*.go
rm -f pkg/api/openapi/docs/{Kind}*.md
```

### Step 4: Unwire from Existing Files

#### 4.1 `cmd/ambient-api-server/main.go`

Remove the blank import line for the Kind's plugin.

#### 4.2 `pkg/db/migrations/migration_structs.go`

Remove from `MigrationList`:
```go
add{Kind}s(),
```

#### 4.3 `openapi/openapi.yaml`

Remove the path `$ref` entries for this Kind (both collection and item paths).
Remove the schema `$ref` entries (`{Kind}`, `{Kind}List`, `{Kind}PatchRequest`).

### Step 5: Regenerate OpenAPI Client

```bash
make generate
```

This ensures the OpenAPI client code no longer references the removed Kind.

### Step 6: Verify Clean Removal

```bash
make binary
```

Fix any remaining references. Common issues:
- Other services importing the removed Kind's plugin
- Test files referencing the removed Kind's factory
- Stale references in OpenAPI generated code

### Step 7: Confirm

List any files that still reference the Kind name:
```bash
rg "{Kind}" --type go --type yaml -l
```

If any remain, they need manual cleanup (likely cross-references from other Kinds).
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Regenerate OpenAPI Client Code

Regenerate the Go client code from OpenAPI specifications. Run this after modifying any `openapi/*.yaml` files.

## Instructions

### Step 1: Verify Docker/Podman is Running

The generator uses a container to run the OpenAPI code generator:
```bash
podman info --format '{{.Host.RemoteSocket.Exists}}' 2>/dev/null || docker info --format '{{.ID}}' 2>/dev/null
```

If neither is running, inform the user that Docker or Podman is required.

### Step 2: Run the Generator

```bash
make generate
```

This takes 2-3 minutes. It:
1. Builds a container image from `Dockerfile.openapi`
2. Runs the OpenAPI Generator inside the container
3. Copies generated Go files back into `pkg/api/openapi/`

### Step 3: Verify Generated Files

```bash
ls -la pkg/api/openapi/model_*.go | head -20
```

Check for the expected model files for each Kind defined in the OpenAPI specs.

### Step 4: Build to Confirm

```bash
make binary
```

## When to Run This

- After creating a new Kind (part of `/trex.kind.new` workflow)
- After adding fields to an existing Kind's OpenAPI spec
- After modifying `openapi/openapi.yaml` or any `openapi/openapi.*.yaml` file
- After resolving merge conflicts in OpenAPI specs

## Troubleshooting

- **"Cannot connect to Docker daemon"**: Start Docker/Podman first
- **Build fails after generation**: Check for type mismatches between your OpenAPI schema types and the presenter code
- **Missing model files**: Verify the schema name in `openapi.yaml` matches the `$ref` target exactly
Loading
Loading