Skip to content
  • guides
  • example
  • walkthrough
  • tutorial

Example Project: From Idea to Running SaaS

This walkthrough demonstrates building a complete SaaS solution using the ConnectSoft AI Factory, templates, and platforms. It is written for architects, product leads, and engineers who want to see how the Factory works end-to-end.

We'll build a Subscription Billing & Invoicing microservice suite — a common SaaS capability that demonstrates Factory capabilities, platform integration, and real-world patterns.

Tip

Use this example as a template when proposing new customer projects. It shows the typical flow from idea to production.

1. Idea and Requirements

The Problem

A SaaS company needs to manage subscriptions, generate invoices, and process payments. They want: - Multi-tenant subscription management - Automated invoice generation - Payment processing integration - Audit trail for compliance

Initial Requirements

Core Capabilities: - Create and manage subscriptions - Generate invoices automatically - Process payments via Stripe - Track subscription lifecycle events - Provide audit trail

Non-Functional Requirements: - Multi-tenant (each customer is a tenant) - High availability (99.9% uptime) - Audit logging for compliance - Integration with existing identity system

2. Defining Bounded Contexts and Services

Bounded Context Analysis

We identify one primary bounded context: Billing & Invoicing

Entities: - Subscription (aggregate root) - Represents a customer subscription - Invoice - Generated invoice for a subscription - Payment - Payment record for an invoice - Billing Cycle - Billing period configuration

Domain Events: - SubscriptionCreated - SubscriptionActivated - InvoiceGenerated - PaymentProcessed - SubscriptionCancelled

Service Boundaries

We'll create one microservice: Subscription Billing Service

This service handles: - Subscription lifecycle - Invoice generation - Payment processing (via Stripe integration) - Audit event emission

See: Modularization and Clean Architecture & DDD for guidance.

3. Running the Factory

Preparing Factory Inputs

We prepare structured inputs for the Factory:

Product: Subscription Billing Service
Purpose: Manage subscriptions, generate invoices, process payments
Bounded Context: Billing & Invoicing
Tenants: Multi-tenant SaaS

Entities:
  - Subscription (aggregate root)
    - Properties: Id, TenantId, PlanId, Status, StartDate, EndDate
    - Methods: Activate(), Cancel(), Renew()
  - Invoice
    - Properties: Id, SubscriptionId, Amount, Status, DueDate
    - Methods: MarkPaid(), Cancel()
  - Payment
    - Properties: Id, InvoiceId, Amount, Status, ProviderTransactionId
  - Billing Cycle
    - Properties: Id, SubscriptionId, StartDate, EndDate, Amount

Domain Events:
  - SubscriptionCreated
  - SubscriptionActivated
  - InvoiceGenerated
  - PaymentProcessed

Integrations:
  - Stripe API (payment processing)
  - Identity Platform (authentication)
  - Audit Platform (audit events)
  - Config Platform (feature flags)

Factory Run Process

  1. Create Project - Create new project in Factory console
  2. Select Template - Choose microservice template
  3. Configure Domain Model - Provide entities and events
  4. Select Integrations - Choose Identity, Audit, Config platforms
  5. Start Run - Trigger Factory execution

What the Factory Generates

The Factory orchestrates agents to generate:

  • Repositories - Subscription, Invoice, Payment repositories
  • Domain Layer - Entities, aggregates, domain events
  • Application Layer - Use cases, command/query handlers
  • API Layer - REST controllers, request/response models
  • Infrastructure Layer - Stripe client, platform integrations
  • Tests - Unit tests, integration tests, BDD specs
  • Pipelines - CI/CD pipelines for build and deploy
  • Documentation - README, API docs, ADRs

See: Agent Execution Flow for details.

4. Reviewing and Extending Generated Code

Reviewing Generated Structure

The Factory generates a clean structure:

src/
  SubscriptionBilling.Api/
  SubscriptionBilling.Application/
  SubscriptionBilling.Domain/
    - Subscription.cs (aggregate root)
    - Invoice.cs
    - Payment.cs
    - BillingCycle.cs
    - DomainEvents/
  SubscriptionBilling.Infrastructure/
    - Repositories/
    - External/
      - StripeClient.cs
tests/
  SubscriptionBilling.Tests/
pipelines/
  azure-pipelines.yml
docs/
  README.md
  architecture.md
adr/
  adr-0001-subscription-aggregate-design.md

Extending Domain Logic

We add business-specific logic:

// Domain/Subscription.cs (extended)
public class Subscription : AggregateRoot
{
    // Factory-generated properties...

    // We add business logic
    public void Renew(BillingCycle newCycle)
    {
        if (Status != SubscriptionStatus.Active)
            throw new InvalidOperationException("Only active subscriptions can be renewed");

        EndDate = newCycle.EndDate;
        AddDomainEvent(new SubscriptionRenewed(Id, newCycle));
    }

    public bool IsExpired()
    {
        return Status == SubscriptionStatus.Active && EndDate < DateTime.UtcNow;
    }
}

Adding Stripe Integration

We extend the generated Stripe client:

// Infrastructure/External/StripeClient.cs (extended)
public class StripeClient : IPaymentProvider
{
    // Factory-generated base...

    public async Task<PaymentResult> ProcessPaymentAsync(PaymentRequest request)
    {
        // Custom Stripe integration logic
        var charge = await _stripeService.Charges.CreateAsync(new ChargeCreateOptions {
            Amount = request.Amount,
            Currency = "usd",
            Source = request.PaymentMethodId
        });

        return new PaymentResult {
            Success = charge.Status == "succeeded",
            TransactionId = charge.Id
        };
    }
}

See: Getting Started with Factory for extension guidance.

5. Integrating Platforms (Identity, Audit, Config)

Identity Platform Integration

We integrate with Identity Platform for authentication:

// In Program.cs
services.AddAuthentication()
    .AddOpenIdConnect(options => {
        options.Authority = "https://identity.connectsoft.io";
        options.ClientId = Configuration["Identity:ClientId"];
    });

Audit Platform Integration

We emit audit events to Audit Platform:

// Application/EventHandlers/SubscriptionCreatedHandler.cs
public class SubscriptionCreatedHandler : INotificationHandler<SubscriptionCreated>
{
    private readonly IAuditService _auditService;

    public async Task Handle(SubscriptionCreated notification, CancellationToken cancellationToken)
    {
        await _auditService.LogAsync(new AuditEvent {
            Action = "SubscriptionCreated",
            EntityId = notification.SubscriptionId.ToString(),
            TenantId = notification.TenantId.ToString(),
            Details = new { PlanId = notification.PlanId }
        });
    }
}

Config Platform Integration

We use Config Platform for feature flags:

// Application/Commands/CreateSubscriptionCommand.cs
public class CreateSubscriptionHandler
{
    private readonly IConfigService _configService;

    public async Task Handle(CreateSubscriptionCommand request)
    {
        // Check feature flag
        var enableNewPricing = await _configService.GetFeatureFlagAsync("NewPricingModel");

        if (enableNewPricing)
        {
            // Use new pricing logic
        }
        else
        {
            // Use existing pricing logic
        }
    }
}

See: Getting Started with Platforms for integration details.

6. Deploying and Observing

Deploying with Generated Pipelines

We use the generated CI/CD pipeline:

  1. Review Pipeline - Check azure-pipelines.yml
  2. Configure Variables - Set environment-specific variables
  3. Deploy to Dev - Deploy to development environment
  4. Verify - Check health endpoints and logs
  5. Deploy to Production - Deploy to production

Monitoring and Observability

We monitor the service:

  • Logs - Structured logs show subscription lifecycle
  • Metrics - Track subscription creation rate, payment success rate
  • Traces - Distributed traces show end-to-end flows
  • Dashboards - Custom dashboards show business metrics

Example Metrics: - Subscriptions created per day - Invoice generation success rate - Payment processing success rate - Average subscription value

See: Observability-Driven Design and Monitoring & Dashboards.

7. Lessons Learned

Where the Factory Shines

  • Speed - Generated complete service in hours, not weeks
  • Consistency - All services follow same patterns
  • Quality - Tests, pipelines, and docs included
  • Architecture - Clean Architecture and DDD patterns built-in

Where Human Judgment Is Essential

  • Domain Logic - Business rules need human refinement
  • Integration Details - External API specifics need customization
  • Business Decisions - Product decisions require human input
  • Edge Cases - Complex scenarios need human handling

Recommendations for Next Similar Project

  1. Start with Factory - Use Factory for initial generation
  2. Extend Domain Logic - Add business-specific logic
  3. Integrate Platforms - Use Identity, Audit, Config platforms
  4. Monitor Closely - Use observability from day one
  5. Iterate Quickly - Use Factory for subsequent features

Tip

Use this example as a template when proposing new customer projects. It demonstrates the typical flow and shows how Factory, templates, and platforms work together.

Visual Flow

The diagram below shows the end-to-end flow from idea to running SaaS:

flowchart TD
    A[Idea & Requirements] --> B[Define Bounded Contexts]
    B --> C[Prepare Factory Inputs]
    C --> D[Run Factory]
    D --> E[Agents Generate Code]
    E --> F[Code in Azure DevOps]
    F --> G[Review & Extend]
    G --> H[Integrate Platforms]
    H --> I[Deploy via Pipelines]
    I --> J[Monitor & Observe]
    J --> K[Running SaaS Service]

    style A fill:#e1f5ff
    style D fill:#fff4e1
    style F fill:#e8f5e9
    style K fill:#f3e5f5
Hold "Alt" / "Option" to enable pan & zoom