Skill: quochungto/bookforge-service-based-architecture-designer (version 1.0.0)

--- name: service-based-architecture-designer description: Design a service-based architecture with 4-12 coarse-grained domain services, including service decomposition, database partitioning strategy (shared vs domain-partitioned vs per-service), API layer design, and ACID vs BASE transaction decisions. Use this skill whenever the user is designing a service-based system, decomposing a monolith into coarse-grained services, deciding how many services to create, choosing a database topology for distributed services, deciding between shared database and per-service databases, evaluating whether to add an API layer, determining ACID vs eventual consistency needs, or comparing service-based architecture against microservices — even if they don't use the exact phrase "service-based architecture." version: 1.0.0 homepage: https://github.com/bookforge-ai/bookforge-skills/tree/main/books/fundamentals-of-software-architecture/skills/service-based-architecture-designer metadata: {"openclaw":{"emoji":"📚","homepage":"https://github.com/bookforge-ai/bookforge-skills"}} status: draft depends-on: - architecture-characteristics-identifier source-books: - id: fundamentals-of-software-architecture title: "Fundamentals of Software Architecture" authors: ["Mark Richards", "Neal Ford"] chapters: [13] tags: [software-architecture, architecture, service-based, distributed, domain-services, database-partitioning, ACID, coarse-grained] execution: tier: 1 mode: full inputs: - type: none description: "System description, domain requirements, team context, and data consistency needs — the skill guides the entire service-based architecture design process" tools-required: [Read, Write] tools-optional: [Grep, Glob] mcps-required: [] environment: "Any agent environment. If a codebase exists, can analyze current architecture." --- # Service-Based Architecture Designer ## When to Use You need to design a service-based architecture or evaluate whether service-based is the right distributed style for a system. Service-based architecture is a hybrid of microservices — it uses coarse-grained domain services (typically 4-12, averaging ~7) rather than fine-grained single-purpose services. It is considered the most pragmatic distributed architecture style. Typical situations: - New distributed system — "we need something beyond a monolith but microservices feels like overkill" - Monolith decomposition — "our deployments take hours and we want independent deployability" - Architecture comparison — "should we use service-based or microservices?" - Database topology — "should our services share a database or have separate ones?" - Transaction design — "we need ACID transactions across some of these workflows" Before starting, verify: - Has an architecture style already been selected? If the user hasn't decided on service-based yet, consider using `architecture-style-selector` first. - Are driving architecture characteristics known? If not, use [REDACTED_SECRET] — you need to know what quality attributes drive the design. - If the user explicitly asks for service-based design, proceed directly. ## Context & Input Gathering ### Input Sufficiency Check This skill designs a complete service-based architecture. You can proceed with partial information and fill gaps during the process, but certain inputs directly determine the quality of the architecture. ### Required Context (must have — ask if missing) - **System purpose and domain:** What business capabilities does this system provide? -> Check prompt for: domain description, list of features/modules, business workflows -> If missing, ask: "What does your system do? What are the main business capabilities or modules?" - **Business workflows that cross domain boundaries:** Which operations span multiple domains? -> Check prompt for: transaction descriptions, workflow dependencies, mentions of "X needs to update Y" -> If missing, ask: "Which business operations need to coordinate across multiple areas? For example, does placing an order also need to update inventory and billing atomically?" ### Important Context (strongly recommended — ask if easy to obtain) - **Team size and distributed experience:** How many developers? Have they built distributed systems before? -> Check prompt for: team mentions, experience level, current architecture -> If missing, ask: "How large is your development team, and have they built distributed systems before?" - **Current deployment pain:** What deployment problems are you trying to solve? -> Check prompt for: deployment frequency, deployment duration, risk mentions -> If missing and relevant, ask: "How long do deployments take and how often do you deploy?" - **Data consistency requirements:** Which operations require strict transactional guarantees? -> Check prompt for: ACID mentions, consistency requirements, "must be atomic" language -> If missing, ask: "Which operations require strict transactional consistency (all-or-nothing), and which can tolerate eventual consistency?" ### Observable Context (gather from environment) - **Existing architecture:** If refactoring, scan for current structure -> Look for: package structure, module boundaries, database schemas, existing service definitions -> Reveals: natural domain boundaries, current coupling patterns ### Default Assumptions - If team experience unknown -> assume moderate (can handle service-based but not full microservices) - If database strategy not specified -> default to shared database (the most common and simplest starting point) - If service count not specified -> target ~7 services (the average for service-based) - If API layer not discussed -> recommend adding one if external consumers exist ### Sufficiency Threshold ``` SUFFICIENT: system purpose + business capabilities + cross-domain workflows are known PROCEED WITH DEFAULTS: system purpose + capabilities are known, cross-domain workflows unclear MUST ASK: system purpose OR business capabilities are missing ``` ## Process ### Step 1: Identify Domain Services **ACTION:** Decompose the system into 4-12 coarse-grained domain services based on business capabilities. **WHY:** Service-based architecture uses "domain services" — coarse-grained portions of an application that encapsulate an entire business domain (like OrderService, PaymentService), NOT fine-grained single-purpose services (like OrderPlacement, OrderValidation). The coarse granularity is the defining characteristic that differentiates service-based from microservices, and it is what preserves ACID transactions and simplifies orchestration. Each domain service internally orchestrates its own sub-operations through class-level calls rather than remote service calls. **Process:** 1. List all business capabilities the system must support 2. Group related capabilities into cohesive domains (aim for 4-12 groups, ~7 average) 3. Each group becomes a domain service — name it after the domain, not the technical function 4. Verify each service is coarse enough: it should contain multiple related sub-operations, not just one **Granularity checks:** - **Too many services (>12):** You are drifting toward microservices. Merge related services. More services = more network calls, more distributed transaction complexity, less ACID safety. - **Too few services (<3):** You haven't decomposed enough. The benefits of independent deployability and fault isolation are negligible with 2-3 services. - **Right size (4-12):** Each service represents a complete business domain with multiple internal components. **IF** a service only does one thing -> merge it with a related service **IF** a service does unrelated things -> split it into separate domain services ### Step 2: Design Internal Service Structure **ACTION:** Define the internal architecture of each domain service. **WHY:** Each domain service is itself a mini-application with its own internal structure. Two design approaches exist: layered (technical partitioning with API facade, business logic, persistence layers) and domain-partitioned (API facade with internal sub-domain components, similar to modular monolith). The choice affects how easily the service can evolve. Domain-partitioned internal design is preferred when the service is complex enough to warrant sub-domain separation, because it makes future decomposition easier if a service eventually needs to be split. **For each service, define:** 1. **API facade layer:** Every domain service must have an API access facade that orchestrates business requests from the UI. This facade is responsible for receiving a single business request and breaking it into internal sub-operations. 2. **Internal structure:** Choose layered (API facade -> business logic -> persistence) for simpler services, or domain-partitioned (API facade -> sub-domain components) for complex services. 3. **Internal components:** List the key components within each service. ### Step 3: Select Database Topology **ACTION:** Choose the database partitioning strategy for the system. **WHY:** Database topology is the most consequential infrastructure decision in service-based architecture. A shared database preserves SQL joins and ACID transactions across all services — this is the primary structural advantage of service-based over microservices. However, a shared database creates coupling through schema changes: modifying a table can force redeployment of all services that use it. The database topology directly determines whether you get ACID transactions (shared) or must implement distributed transactions like SAGA (per-service). Choosing per-service databases prematurely eliminates the ACID advantage that makes service-based architecture attractive in the first place. **Decision tree:** | Strategy | When to use | Trade-offs | |----------|------------|------------| | **Single shared database** | Default choice. Multiple services need joins across domains. ACID transactions span service boundaries. Team is small. | Simple. Preserves ACID. But: schema changes can impact all services. Mitigate with logical partitioning. | | **Logically partitioned (shared DB, domain-scoped schemas)** | Want shared DB benefits but need to control schema change impact. Multiple services exist. | Best of both worlds. Services own their logical partition. Federated shared libraries match partitions. Common tables still need coordination. | | **Domain-partitioned databases** | 2-3 domain groups have clearly separate data with no cross-domain joins needed. | Partial isolation. Some services share a DB, others are separate. Moderate complexity. | | **Per-service databases** | Each service's data is truly independent. No cross-service joins needed. Team is ready for eventual consistency. | Maximum isolation. But: lose ACID across services. Need SAGA pattern for distributed transactions. Avoid unless necessary. | **IF** shared database -> implement logical partitioning through federated shared libraries (one entity library per logical domain + one common library) **IF** per-service databases -> document which workflows now require distributed transactions and plan SAGA implementation **Critical rule:** Make the logical partitioning in the database as fine-grained as possible while still maintaining well-defined data domains to better control database changes within a service-based architecture. ### Step 4: Determine UI Topology **ACTION:** Select the user interface deployment strategy. **WHY:** Service-based architecture supports three UI variants, and the choice affects the number of architecture quanta (independently deployable units with distinct characteristics). A single monolithic UI means the entire frontend shares one deployment and one set of architecture characteristics. Domain-based or service-based UIs enable independent frontend deployments, which matters when different parts of the application face different user groups with different availability, scalability, or security needs. **Options:** | UI Topology | When to use | Quanta impact | |------------|------------|---------------| | **Single monolithic UI** | One user group, simple frontend, single deployment pipeline | All services + UI = 1 quantum (if shared DB) | | **Domain-based UIs** | Different user groups (e.g., customer-facing vs internal operations) | Multiple quanta possible — each UI + its services can be a separate quantum | | **Service-based UIs** | Maximum frontend independence, micro-frontend approach | Multiple quanta — each UI is coupled only to its service | ### Step 5: Decide on API Layer **ACTION:** Determine whether to add an API layer (reverse proxy or gateway) between the UI and services. **WHY:** An API layer is optional in service-based architecture but valuable in specific scenarios. Without an API layer, the UI accesses services directly using a service locator pattern, API gateway, or proxy embedded in the UI. Adding a separate API layer creates a centralized place for cross-cutting concerns (security, metrics, auditing, rate limiting, service discovery) and is particularly important when exposing services to external consumers. However, it adds another deployment unit, network hop, and potential single point of failure. **Add an API layer when:** - External systems or third parties will consume the services - You need centralized security, auditing, or rate limiting - Service discovery is needed (services move across infrastructure) - Cross-cutting concerns are duplicated across the UI and multiple services **Skip the API layer when:** - Only internal UIs consume the services - The team is small and wants to minimize deployment units - Cross-cutting concerns are handled within each service ### Step 6: Map Transaction Boundaries **ACTION:** For each cross-domain workflow, determine whether ACID or BASE transactions are needed, and ensure the database topology supports them. **WHY:** This is where service-based architecture's core advantage materializes. Because services are coarse-grained and typically share a database, most business operations that span sub-operations (like "place order + apply payment + update inventory") happen WITHIN a single domain service using regular ACID database transactions. In microservices, this same operation would span 3 separate services requiring distributed transactions (SAGA pattern), compensating transactions, and eventual consistency. The moment you split services too fine or split the database too aggressively, you lose this advantage and must deal with all the distributed transaction complexity that service-based architecture was designed to avoid. **For each cross-domain workflow:** 1. List the domains involved 2. If all domains are within ONE service -> ACID transaction (simple, preferred) 3. If domains span MULTIPLE services with SHARED database -> ACID transaction still possible via shared DB 4. If domains span services with SEPARATE databases -> BASE transaction required (SAGA pattern needed) **IF** many workflows require cross-service ACID transactions -> reconsider service boundaries. Services that frequently transact together may belong in the same domain service. **IF** BASE transactions are unavoidable -> document the SAGA choreography/orchestration and compensating actions for each workflow. ### Step 7: Validate and Score **ACTION:** Validate the design against service-based architecture characteristic ratings and check for anti-patterns. **WHY:** Every architecture style has known strengths and weaknesses. Service-based architecture has no five-star ratings but achieves four stars in many vital areas. Validating against the ratings ensures you are not expecting the architecture to excel where it structurally cannot (like extreme elasticity at 2 stars), and checking for anti-patterns catches the most common design mistakes before they become entrenched. **Service-based architecture ratings:** | Characteristic | Rating | Notes | |---------------|:------:|-------| | Deployability | 4 | Independent service deployment without full system release | | Elasticity | 2 | Coarse services replicate more functionality than needed to scale | | Evolutionary | 3 | Good domain isolation, moderate coupling through shared DB | | Fault tolerance | 4 | One service failing does not take down others | | Modularity | 4 | Domain-partitioned, changes scoped to single service | | Overall cost | 4 | Much cheaper than microservices, event-driven, or space-based | | Performance | 3 | Fewer network calls than microservices, but still distributed | | Reliability | 4 | Less network traffic, fewer distributed transactions | | Scalability | 3 | Can scale individual services, but coarse granularity limits efficiency | | Simplicity | 3 | Simpler than other distributed styles, but still distributed | | Testability | 4 | Smaller test scope per service than monolith | **Anti-pattern checks:** - **Too many services (>12):** You have drifted into microservices territory without the operational infrastructure to support it. Merge services. - **Too few services (<3):** Not enough decomposition to gain independent deployability benefits. Consider whether service-based is the right style. - **Premature database splitting:** Splitting databases without implementing SAGA creates data inconsistency risks. Keep shared DB until you have proven you don't need cross-service ACID. - **Inter-service communication:** Domain services in service-based architecture should NOT call each other. If Service A needs to call Service B, either merge them or route through the UI/API layer. Direct inter-service calls create the coupling that service-based architecture is designed to avoid. - **Single shared entity library:** Using one monolithic shared library for all database entity objects means a table change forces redeployment of every service. Use federated domain-scoped libraries instead. ## Inputs - System description with business capabilities - Business workflows, especially those crossing domain boundaries - Team size and distributed systems experience - Data consistency requirements (which workflows need ACID) - Current architecture (if migrating from monolith) - Scalability and availability requirements per domain ## Outputs ### Service-Based Architecture Design ```markdown # Service-Based Architecture Design: {System Name} ## Design Context **System:** {what it does} **Team:** {size and experience} **Key drivers:** {why service-based was chosen} ## Domain Services ({count} services) | # | Service | Domain | Key Components | Instances | |---|---------|--------|---------------|:---------:| | 1 | {ServiceName} | {domain} | {component list} | {1 or N} | | ... | ... | ... | ... | ... | ### Service Detail: {ServiceName} **Domain:** {what business capability this covers} **Internal design:** {layered or domain-partitioned} **Components:** - {Component 1}: {responsibility} - {Component 2}: {responsibility} ## Database Topology **Strategy:** {shared / logically partitioned / domain-partitioned / per-service} **Reasoning:** {why this strategy was chosen} {If logically partitioned:} **Logical partitions:** | Partition | Tables | Used by services | |-----------|--------|-----------------| | {domain} | {tables} | {services} | | common | {shared tables} | all services | ## User Interface Topology **Strategy:** {single monolithic / domain-based / service-based} **Reasoning:** {why this topology was chosen} ## API Layer **Decision:** {include / omit} **Reasoning:** {why} ## Transaction Boundaries | Workflow | Domains involved | Services | Transaction type | Notes | |----------|-----------------|----------|:----------------:|-------| | {workflow} | {domains} | {services} | ACID / BASE | {notes} | ## Architecture Quanta **Count:** {number} **Reasoning:** {what determines the quantum boundaries} ## Characteristic Fit | Characteristic | Rating | Meets needs? | |---------------|:------:|:------------:| | Deployability | 4 | {Yes/No} | | Fault tolerance | 4 | {Yes/No} | | ... | ... | ... | ## Anti-Pattern Check - [ ] Service count in 4-12 range - [ ] No inter-service direct calls - [ ] Database topology supports required ACID transactions - [ ] Federated entity libraries (not single shared library) - [ ] No premature database splitting ## Getting Started 1. {First step} 2. {Second step} 3. {Third step} ``` ## Key Principles - **Coarse-grained is the point** — Service-based architecture uses 4-12 domain services averaging ~7, NOT dozens of fine-grained microservices. The coarse granularity is what preserves ACID transactions, simplifies orchestration (internal class calls vs remote service calls), and keeps operational cost low. If you find yourself creating more than 12 services, you are building microservices without the infrastructure to support them. - **Shared database is a feature, not a compromise** — The shared database is what enables SQL joins and ACID transactions across domains. This is the primary structural advantage over microservices. Don't split the database unless you have a proven, specific reason. Premature database splitting eliminates the core benefit of choosing service-based architecture in the first place. - **Services should NOT call each other** — In service-based architecture, domain services are self-contained and do not communicate with each other directly. All orchestration happens either within a single service (internal) or through the UI/API layer. If two services need to coordinate frequently, they probably belong together as one service. - **Internal orchestration over external orchestration** — A business request like "place an order" is received by the OrderService's API facade, which internally orchestrates all sub-operations (create order, apply payment, update inventory) through class-level calls within that single service. In microservices, this same operation would require external orchestration across multiple remote services. This internal orchestration is what makes service-based simpler and more reliable. - **Logical partitioning controls blast radius** — Even with a shared database, use federated domain-scoped entity libraries rather than a single monolithic shared library. When a table in the "invoicing" domain changes, only the invoicing entity library and the services that use it need updating — not every service in the system. This is the pragmatic middle ground between monolithic coupling and full database separation. - **Start shared, split only when proven necessary** — Begin with a shared database and logical partitioning. Only split into separate databases when you have concrete evidence that shared schema changes are causing deployment coordination problems, AND you have a plan for distributed transactions (SAGA) for any workflows that cross the split boundary. ## Examples **Scenario: Electronic device recycling system** Trigger: "We process old electronics (phones, tablets). Customers get quotes online, mail devices in, we assess them, pay the customer, then recycle or resell. We also have internal reporting." Process: Identified 7 domain services from the business flow: Quoting, Item Status, Receiving, Assessment, Accounting, Recycling, Reporting. Split UI into two quanta: customer-facing (Quoting, Item Status) and internal operations (Receiving, Assessment, Accounting, Recycling, Reporting). Used two separate databases — one for customer-facing operations (higher security, separate network zone) and one for internal operations. Only Quoting and Item Status services need to scale (customer traffic), others run as single instances. Output: **7 domain services, 2 architecture quanta, domain-partitioned databases** (2 databases split by security boundary, not by service). Customer-facing services behind a firewall separation from internal services. ACID transactions preserved within each database boundary. Assessment service changes frequently (new device rules) but is isolated, enabling high deployability. **Scenario: Insurance claims processing platform** Trigger: "We need claims intake, adjudication, payment, fraud detection, and policy verification. Team of 20 developers, currently a monolith with 4-hour deployments." Process: Identified 6 domain services: Claims Intake, Adjudication, Payment, Fraud Detection, Policy Verification, Reporting. Kept shared database because claims workflows require ACID: a claim submission must atomically create the claim record, initiate fraud check, and verify policy status. Logically partitioned the database into 6 domains + common. Added API layer because external partners (repair shops, medical providers) submit claims via API. Single monolithic UI (all internal users share the same portal). Fraud Detection needs higher throughput, so it runs multiple instances with load balancing. Output: **6 domain services, shared logically-partitioned database, API layer included.** Key win: deployment time drops from 4 hours to ~30 minutes per service. ACID preserved for claims workflows. Federated entity libraries prevent cascading redeployments from schema changes. **Scenario: E-learning platform** Trigger: "Building a learning management system with course catalog, enrollment, content delivery, progress tracking, assessments, and certificates. Team of 10, first distributed system." Process: Identified 6 domain services: Course Catalog, Enrollment, Content Delivery, Progress Tracking, Assessment, Certification. Shared database — enrollment needs ACID with progress tracking (enrolling a student must atomically create progress records). No API layer needed (internal platform only). Single UI. Default single instances per service since traffic is predictable (students access during class hours). Kept Assessment and Certification in separate services despite being related because assessment rules change frequently (high deployability need) while certification is stable. Output: **6 domain services, single shared database with logical partitioning, no API layer.** Team's first distributed system — service-based is ideal because it's the simplest distributed style (simplicity 3, cost 4) while still gaining independent deployability (4) and fault tolerance (4). If Content Delivery later needs CDN-level scaling, it can be extracted into a separate quantum. ## References - For topology variant details and decision matrices, see [references/topology-variants.md](references/topology-variants.md) - For architecture style comparison (service-based vs alternatives), use `architecture-style-selector` - For identifying driving quality attributes, use [REDACTED_SECRET] - For documenting the architecture decision, use [REDACTED_SECRET] ## License This skill is licensed under [CC-BY-SA-4.0](https://creativecommons.org/licenses/by-sa/4.0/). Source: [BookForge](https://github.com/bookforge-ai/bookforge-skills) — Fundamentals of Software Architecture by Mark Richards, Neal Ford. ## Related BookForge Skills Install related skills from ClawhHub: - `clawhub install bookforge-architecture-characteristics-identifier` Or install the full book set from GitHub: [bookforge-skills](https://github.com/bookforge-ai/bookforge-skills)

path: references/topology-variants.md
content: # Topology Variants — Service-Based Architecture

Service-based architecture is one of the most flexible architecture styles because multiple topology dimensions can be independently varied: user interface deployment, database partitioning, API layer inclusion, and service granularity. This reference covers the decision space for each dimension.

## User Interface Variants

### Single Monolithic UI

```
┌─────────────────────────────────┐
│         User Interface          │
└──┬──────┬──────┬──────┬─────────┘
   │      │      │      │
┌──▼──┐┌──▼──┐┌──▼──┐┌──▼──┐
│Svc A││Svc B││Svc C││Svc D│
└──┬──┘└──┬──┘└──┬──┘└──┬──┘
   │      │      │      │
┌──▼──────▼──────▼──────▼──┐
│         Database          │
└───────────────────────────┘
```

**When to use:**
- Single user group with uniform needs
- Small team maintaining one frontend
- Simplest deployment model

**Architecture quanta:** 1 (if shared DB) — all services share the same deployment and characteristic profile.

**Trade-offs:**
- (+) Simplest to build and deploy
- (+) Consistent UX across all domains
- (-) UI deployment blocks all domains
- (-) Cannot scale or secure frontend sections independently

### Domain-Based UIs

```
┌───────────────┐ ┌───────────────┐
│  UI: Customer │ │ UI: Internal  │
└──┬─────┬──────┘ └──┬──────┬─────┘
   │     │           │      │
┌──▼──┐┌─▼──┐  ┌────▼─┐┌───▼──┐┌────────┐
│Svc A││Svc B│  │Svc C ││Svc D ││Svc E   │
└──┬──┘└──┬──┘  └──┬───┘└──┬───┘└──┬─────┘
   │      │        │       │       │
┌──▼──────▼────────▼───────▼───────▼──┐
│             Database                 │
└──────────────────────────────────────┘
```

**When to use:**
- Different user groups (customers vs internal staff vs partners)
- Different security requirements per user group
- Different availability/scalability needs per user group

**Architecture quanta:** Can be >1 — each UI + its services can form a separate quantum, especially if databases are also split.

**Trade-offs:**
- (+) Independent deployment per user group
- (+) Different security zones (customer-facing behind DMZ)
- (+) Can scale customer-facing independently
- (-) More deployment units to manage
- (-) Potential code duplication in shared UI components

### Service-Based UIs (Micro-Frontends)

```
┌───────┐┌───────┐┌───────┐┌───────┐
│  UI A ││  UI B ││  UI C ││  UI D │
└──┬────┘└──┬────┘└──┬────┘└──┬────┘
   │        │        │        │
┌──▼──┐  ┌──▼──┐  ┌──▼──┐  ┌──▼──┐
│Svc A│  │Svc B│  │Svc C│  │Svc D│
└──┬──┘  └──┬──┘  └──┬──┘  └──┬──┘
   │        │        │        │
┌──▼────────▼────────▼────────▼──┐
│           Database              │
└─────────────────────────────────┘
```

**When to use:**
- Maximum frontend independence
- Teams organized around domain services
- Each domain needs different frontend technology or release cadence

**Architecture quanta:** Multiple — each UI-service pair is a potential quantum.

**Trade-offs:**
- (+) Maximum team autonomy per domain
- (+) Independent deployment and technology per UI
- (-) Most complex frontend orchestration
- (-) Consistent UX across domains is harder
- (-) Requires micro-frontend framework/approach

### UI Decision Matrix

| Factor | Single UI | Domain-Based | Service-Based |
|--------|:---------:|:------------:|:-------------:|
| Deployment simplicity | Best | Moderate | Most complex |
| Team autonomy | Low | Moderate | High |
| Security zoning | None | Good | Good |
| Independent scaling | No | Per-group | Per-service |
| UX consistency | Easiest | Moderate | Hardest |
| Recommended team size | <15 | 10-30 | 20+ |

## Database Variants

### Single Shared Database (Default)

```
┌──────┐┌──────┐┌──────┐┌──────┐
│Svc A ││Svc B ││Svc C ││Svc D │
└──┬───┘└──┬───┘└──┬───┘└──┬───┘
   │       │       │       │
   │  single_shared_lib    │
   │  (all entity objects) │
   │       │       │       │
┌──▼───────▼───────▼───────▼──┐
│         Database             │
│  (all tables, one schema)   │
└──────────────────────────────┘
```

**When to use:** Starting point. Multiple services need SQL joins. ACID transactions span services.

**Risk:** A table change forces a shared library update -> redeployment of ALL services, even those that don't use the changed table. This is the **single shared entity library anti-pattern**.

### Logically Partitioned Database (Recommended)

```
┌──────────┐┌──────────┐┌──────────┐┌──────────┐
│  Svc A   ││  Svc B   ││  Svc C   ││  Svc D   │
│          ││          ││          ││          │
│ a_ent_lib││ b_ent_lib││ c_ent_lib││ d_ent_lib│
│ common   ││ common   ││ a_ent_lib││ common   │
│          ││          ││ common   ││          │
└──┬───────┘└──┬───────┘└──┬───────┘└──┬───────┘
   │           │           │           │
┌──▼───────────▼───────────▼───────────▼──┐
│              Database                    │
│ ┌───────┐┌───────┐┌───────┐┌──────────┐│
│ │ dom_a ││ dom_b ││ dom_c ││  common  ││
│ └───────┘└───────┘└───────┘└──────────┘│
└──────────────────────────────────────────┘
```

**When to use:** Shared database benefits needed + want to control change blast radius.

**How it works:**
1. Database tables are logically grouped into domain partitions
2. Each domain partition has its own entity library (e.g., `invoicing_entities_lib`)
3. A `common_entities_lib` contains shared tables used by all services
4. Services include only the entity libraries they need
5. When a table changes, only the corresponding entity library is updated -> only services using that library need redeployment

**Common table management:** Lock common entity objects in version control. Restrict change access to the database team. Changes to common tables require coordination across all services.

**Best practice:** Make logical partitions as fine-grained as possible while maintaining well-defined data domains.

### Domain-Partitioned Databases

```
┌──────┐┌──────┐  ┌──────┐┌──────┐
│Svc A ││Svc B │  │Svc C ││Svc D │
└──┬───┘└──┬───┘  └──┬───┘└──┬───┘
   │       │         │       │
┌──▼───────▼──┐   ┌──▼───────▼──┐
│  Database 1 │   │  Database 2 │
│ (domain AB) │   │ (domain CD) │
└─────────────┘   └─────────────┘
```

**When to use:**
- Clear domain groups with no cross-group joins needed
- Security boundaries require separate databases (e.g., customer-facing vs internal)
- Different backup/recovery requirements per domain group

**Critical check before splitting:** Verify that NO business workflows require ACID transactions across the database boundary. If they do, you need SAGA pattern for those workflows.

### Per-Service Databases

```
┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐
│Svc A │  │Svc B │  │Svc C │  │Svc D │
└──┬───┘  └──┬───┘  └──┬───┘  └──┬───┘
   │         │         │         │
┌──▼──┐   ┌──▼──┐   ┌──▼──┐   ┌──▼──┐
│DB A │   │DB B │   │DB C │   │DB D │
└─────┘   └─────┘   └─────┘   └─────┘
```

**When to use:** Each service's data is truly independent. No cross-service queries. Team is ready for eventual consistency and SAGA pattern.

**Warning:** This approaches microservices territory. If you need per-service databases, evaluate whether you should be doing microservices instead (with the full operational investment that requires).

### Database Decision Matrix

| Factor | Single shared | Logically partitioned | Domain-partitioned | Per-service |
|--------|:------------:|:--------------------:|:------------------:|:-----------:|
| ACID across services | Yes | Yes | Partial | No |
| SQL joins across domains | Yes | Yes | Within group only | No |
| Schema change blast radius | All services | Domain-scoped | Group-scoped | Single service |
| Operational complexity | Lowest | Low | Moderate | Highest |
| Data isolation | None | Logical | Physical (partial) | Physical (full) |
| SAGA required | No | No | For cross-group ops | For cross-service ops |

## API Layer Variant

### Without API Layer (Direct Access)

```
┌─────────────────────────────┐
│       User Interface        │
│  (service locator / proxy)  │
└──┬──────┬──────┬──────┬─────┘
   │      │      │      │
┌──▼──┐┌──▼──┐┌──▼──┐┌──▼──┐
│Svc A││Svc B││Svc C││Svc D│
└─────┘└─────┘└─────┘└─────┘
```

UI embeds a service locator pattern, API gateway, or proxy to route requests to services.

### With API Layer

```
┌─────────────────────────────┐
│       User Interface        │
└─────────────┬───────────────┘
              │
┌─────────────▼───────────────┐
│   API Layer (Proxy/Gateway) │
│  (security, metrics, audit) │
└──┬──────┬──────┬──────┬─────┘
   │      │      │      │
┌──▼──┐┌──▼──┐┌──▼──┐┌──▼──┐
│Svc A││Svc B││Svc C││Svc D│
└─────┘└─────┘└─────┘└─────┘
```

**Benefits of API layer:**
- Centralized cross-cutting concerns (security, metrics, auditing, rate limiting)
- Service discovery and routing
- External consumer access management
- API versioning and transformation

**Cost of API layer:**
- Additional deployment unit
- Additional network hop (latency)
- Potential single point of failure
- More infrastructure to maintain

## ACID vs BASE Transaction Decision

### ACID (Within Service or Shared Database)

Use ACID when the business operation must be all-or-nothing and the database topology supports it.

**Example — Order Checkout (single service with shared DB):**
1. OrderService receives checkout request
2. Within a single database transaction:
   - Create order record
   - Apply payment
   - Update inventory
   - Generate invoice
3. If payment fails -> automatic rollback of all changes
4. Customer sees consistent state immediately

This is the service-based architecture advantage: the coarse-grained OrderService handles the entire workflow internally.

### BASE (Across Separate Databases)

Required when business operations cross database boundaries. Uses SAGA pattern.

**Example — Same Order Checkout if databases were split:**
1. OrderService creates order (commits to Order DB)
2. OrderService sends message to PaymentService
3. PaymentService attempts payment (commits to Payment DB)
4. If payment fails:
   - PaymentService sends "payment failed" event
   - OrderService must execute compensating transaction (delete order)
   - InventoryService must execute compensating transaction (restore inventory)
5. Customer may see temporarily inconsistent state

**Key insight:** If you find yourself implementing SAGA for many core business workflows in a service-based architecture, your services may be too fine-grained or your databases may be split prematurely. Consider merging services or consolidating databases to restore ACID.

## Service Granularity Guidelines

| Service count | Assessment | Action |
|:------------:|-----------|--------|
| 1-2 | Not service-based | Too few services; consider modular monolith instead |
| 3 | Borderline | Barely enough decomposition; validate benefits outweigh distribution costs |
| 4-7 | Sweet spot | Good balance of independence and simplicity |
| 8-12 | Acceptable upper range | Verify each service represents a distinct domain; watch for drift toward microservices |
| 13-20 | Warning zone | You may be building microservices without the infrastructure; consider merging related services |
| 20+ | Not service-based | This is microservices; invest in full microservices operational infrastructure |

## Communication Protocols

Service-based architecture typically uses synchronous communication from the UI to services:

| Protocol | When to use |
|----------|------------|
| **REST** | Default choice. Simple, well-understood, good tooling |
| **gRPC** | High-throughput internal communication, binary efficiency needed |
| **Messaging** | Asynchronous operations, event notifications between UI and services |
| **SOAP** | Legacy integration, WS-* standards required |

**Important:** Communication is UI-to-service or API-layer-to-service. Services should NOT communicate directly with each other in service-based architecture.


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)