# Golden Path

Standardized patterns and best practices for building applications on the Forge platform.

---

## 📋 Overview

The Golden Path represents the recommended way to build applications using Forge. Following these patterns ensures consistency, maintainability, and takes advantage of platform capabilities.

---

## 🎯 Golden Path Philosophy

The Golden Path represents:

- **Standardized approaches** that work for most cases
- **Best practices** vetted by the platform team
- **Reduced cognitive load** through conventions
- **Flexibility when needed** - you can deviate, but know why

---

## 🏗️ Core Patterns

### API Layer (Experience APIs)

```csharp
// ✅ Golden Path: Use minimal APIs with service pattern
app.MapGet("/users/{id}", async (int id, IUserService service) =>
    await service.GetAsync(id) is User user
        ? Results.Ok(user)
        : Results.NotFound());

// ✅ Golden Path: Keep controllers thin
[ApiController]
public class UsersController(IUserService service) : ControllerBase
{
    [HttpGet("{id}")]
    public async Task<ActionResult<User>> Get(int id) =>
        await service.GetAsync(id) is User user ? Ok(user) : NotFound();
}

// ❌ Anti-pattern: Business logic in controller
[HttpGet("{id}")]
public async Task<ActionResult<User>> Get(int id)
{
    // Don't do database calls, complex logic here
    var user = await _context.Users
        .Include(u => u.Roles)
        .Where(u => u.Id == id)
        .FirstOrDefaultAsync();
    // ... complex processing
}
```

### Service Layer

```csharp
// ✅ Golden Path: Interface-based services
public interface IUserService
{
    Task<User?> GetAsync(int id);
    Task<User> CreateAsync(CreateUserRequest request);
}

public class UserService(IUserRepository repository) : IUserService
{
    public async Task<User?> GetAsync(int id) =>
        await repository.FindByIdAsync(id);
}

// ✅ Register in DI
builder.Services.AddScoped<IUserService, UserService>();
```

### Data Access

```csharp
// ✅ Golden Path: Repository pattern for CosmosDB
public class UserRepository(CosmosClient client) : IUserRepository
{
    private Container Container => client.GetContainer("db", "users");

    public async Task<User?> FindByIdAsync(string id)
    {
        try
        {
            var response = await Container.ReadItemAsync<User>(id, new PartitionKey(id));
            return response.Resource;
        }
        catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
        {
            return null;
        }
    }
}
```

### Authentication

```csharp
// ✅ Golden Path: Use Forge auth extensions
builder.AddOpenIdConnectServices();

// In middleware
app.UseOpenIdConnectServices();

// ❌ Anti-pattern: Custom JWT validation
builder.Services.AddAuthentication()
    .AddJwtBearer(options => { /* Custom config */ });
```

### Configuration

```yaml
# ✅ Golden Path: Use settings.yml for app settings
# infra/api/settings.yml
- name: "FeatureFlags__NewDashboard"
  value: "true"
- name: "CosmosDb__DatabaseName"
  value: "mydb"
```

```csharp
// ✅ Access via configuration
var dbName = configuration["CosmosDb:DatabaseName"];

// ❌ Anti-pattern: Hardcoded values
var dbName = "production-db";
```

### Service Discovery

```csharp
// ✅ Golden Path: Use .NET Service Discovery for service-to-service calls
builder.Services.AddServiceDiscovery();
builder.Services.ConfigureHttpClientDefaults(http =>
{
    http.AddServiceDiscovery();
});

// Reference services by name (resolved via Aspire)
builder.Services.AddHttpClient<IPaymentClient>(client =>
{
    client.BaseAddress = new Uri("https+http://payment-api");
});

// ❌ Anti-pattern: Hardcoded service URLs
builder.Services.AddHttpClient<IPaymentClient>(client =>
{
    client.BaseAddress = new Uri("https://payment-api.internal.com");
});
```

In Aspire AppHost, services are automatically discoverable:

```csharp
var paymentApi = builder.AddProject<Projects.PaymentApi>("payment-api");

builder.AddProject<Projects.MyApi>("my-api")
    .WithReference(paymentApi);  // Enables service discovery
```

### Infrastructure

```hcl
# ✅ Golden Path: Use Forge modules
module "saif-appservices" {
  source  = "app.terraform.io/SAIFCorp/saif-apiservice/azure"
  version = ">= 3.0.0, < 4.0.0"

  # Standard variables
  owner       = local.variables.owner
  project_id  = local.variables.project_id
  environment = var.environment
}

# ❌ Anti-pattern: Raw Azure resources
resource "azurerm_app_service" "api" {
  # Custom configuration
}
```

---

## 🤔 Decision Framework

### When to Follow the Golden Path

- Starting new projects
- Standard use cases (CRUD APIs, web apps)
- Team is new to the technology
- Long-term maintainability is priority

### When to Deviate

- Unique performance requirements
- Legacy system integration
- Specialized domain needs
- After discussing with platform team

---

## 📊 Pattern Recommendations

### By Use Case

| Need      | Golden Path                               |
| --------- | ----------------------------------------- |
| REST API  | Minimal APIs or Controllers with Services |
| Database  | Cosmos DB with repository pattern          |
| Auth      | Forge OIDC extensions                     |
| Secrets   | Azure Key Vault via settings.yml          |
| Messaging | Azure Service Bus with Aspire             |
| Frontend  | React with Vite                           |

### By File Type

| File           | Pattern                         |
| -------------- | ------------------------------- |
| `Program.cs`   | Builder → Configure → Run       |
| `*.csproj`     | Central package management      |
| `infra/*.tf`   | Forge modules + generated files |
| `settings.yml` | Configuration over hardcoding   |

---

## ✅ Code Review Checklist

When reviewing for Golden Path adherence:

- [ ] Uses Forge packages (not raw Azure SDKs)
- [ ] Configuration via settings.yml
- [ ] No hardcoded secrets or URLs
- [ ] Service/repository pattern for logic
- [ ] Minimal business logic in controllers
- [ ] Uses Aspire for orchestration
- [ ] Infrastructure uses Forge modules
- [ ] Tests follow Forge patterns

---

## 💬 Guidance Examples

### Gentle Guidance

> "I see you're accessing the database directly from the controller. The Golden Path pattern would be to create a repository service. This makes testing easier and keeps controllers focused on HTTP concerns."

### Explaining Trade-offs

> "The Golden Path uses Cosmos DB for most data storage. If you need relational data with complex joins, SQL might be better - but let's discuss with the platform team first to understand the trade-offs."

---

## 📚 Related Resources

- [Principles](../../about/principles.md)
- [Foundry Examples](../../foundry/index.md)
- [Version Compatibility](../version-compatibility.md)
