- 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¶
- Create Project - Create new project in Factory console
- Select Template - Choose microservice template
- Configure Domain Model - Provide entities and events
- Select Integrations - Choose Identity, Audit, Config platforms
- 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:
- Review Pipeline - Check
azure-pipelines.yml - Configure Variables - Set environment-specific variables
- Deploy to Dev - Deploy to development environment
- Verify - Check health endpoints and logs
- 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¶
- Start with Factory - Use Factory for initial generation
- Extend Domain Logic - Add business-specific logic
- Integrate Platforms - Use Identity, Audit, Config platforms
- Monitor Closely - Use observability from day one
- 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
Related Documents¶
- Getting Started with Factory - Factory usage guide
- Getting Started with Platforms - Platform integration
- Factory Overview - Factory capabilities
- Agent Execution Flow - How agents work
- Microservice Template - Template structure
- Modularization - Bounded context guidance
- Clean Architecture & DDD - Architecture principles
- Observability-Driven Design - Monitoring patterns