# Provider Architecture (Source of Truth) This document defines the project-wide architecture and rules for generation, provider behavior, and documentation. It is the single source of truth for implementation and DevOps workflow. ## Core Principles 1) YAML per service is generated ONLY from API data. 2) The provider core is universal and must not contain service-specific logic. 3) Service-specific Go code is fully generated from YAML. No manual edits. 4) Documentation is generated from the same YAML. 5) Build artifacts for 3 OS targets are published to the registry, and docs are published to the website. ## Service Selection - The inclusion list is defined by: `devops/config/services_list.txt` (repo-relative path) - Each line starts with service_id, followed by service name/alias. - Operation timeouts source is defined by: `devops/config/operation_timeouts.json`. ## Unified YAML (Per Service) One YAML file per service. This is the only input for: - Provider code generation - Documentation generation - Validation rules Required top-level fields: - name - service_id - service_display_name - service_short_name - lifecycle - outputs - operations - service_man ### Operations: Kinds and Rules Each operation has a kind: - kind: instance (CRUD for the service instance, plus suspend/resume) - kind: subresource (CRUD for objects inside the service, e.g. users/databases) - kind: action (one-shot operations, e.g. restart/recovery/redeploy) ### Idempotency Rules - instance CRUD is idempotent via standard Terraform behavior. - subresource CRUD is idempotent by resource identity. - action operations are idempotent via a trigger field (e.g. run_id/nonce). If the trigger does not change, the action is not re-run. ### Lifecycle Behavior - For `instance` resources with `suspend`/`resume`, use explicit flags: `adopt_existing_on_create` (default `false`) and `suspend_on_destroy` (default `true`). - Apply decision matrix for suspend-capable services: - cloud status `missing` or `deleted` -> `create` - `suspend` + `adopt_existing_on_create=true` + key params match -> `resume` + `adopt` - `suspend` + `adopt_existing_on_create=false` -> error (explicitly require flag for resume/adopt) - `suspend` + key params mismatch -> error - `running` + `adopt_existing_on_create=true` -> adopt/import behavior - `running` + `adopt_existing_on_create=false` -> error - `not created` -> error, no auto-adopt/create - `creating`/`pending`/`failed` -> error - Conflict diagnostics requirement: - When `resource_name` already exists and `adopt_existing_on_create=false`, diagnostics must explicitly offer two choices: 1) change `resource_name` to create a new resource; 2) import/adopt existing one by setting `adopt_existing_on_create=true` and re-running `apply`. - Destroy behavior for suspend-capable services: - `suspend_on_destroy=true` -> call `suspend` - `suspend_on_destroy=false` -> remove from Terraform state only (no API call) ### Diagnostics Format - Lifecycle diagnostics for plan/apply must be multiline and human-readable. - Include decision reason and controlling flag in message body. - Print details as separate lines: `resource_name`, `service_id`, `instance_uid`, `status`, `status_raw`, `operation_pending`, `operation_in_progress`. ## Provider Model - Core is universal: no service-specific logic inside the core. - Generated service resources contain only schema/params and references. ### Subresource Resources Subresource operations are exposed as standard resources. Example mapping: - create_user/delete_user/modify_user => nubes__user - create_database/delete_database => nubes__database Example HCL: resource "nubes_postgres_user" "user1" { postgres_id = nubes_postgres.db.id username = "app_user" role = "app_user" } ### Action Resources Action operations are exposed as action resources with a trigger field. Example HCL: resource "nubes_postgres_restart" "restart1" { postgres_id = nubes_postgres.db.id run_id = "2026-02-20-001" } ## Concurrency and State Locking **Provider-level guarantees:** - The provider does NOT implement distributed locking for instance operations. - Two concurrent `terraform apply` with the same `resource_name` may create duplicate instances, leading to a «multiple instances found» error on subsequent applies. **User responsibility:** - Use Terraform backend with state locking (S3+DynamoDB, etc.). - Do NOT run `terraform apply` from two workspaces against the same state simultaneously. - If duplicates occur: delete extras via Cloud Console and re-apply. **API-side limitations:** - Nubes API does not enforce unique `displayName` per serviceId. - The provider cannot atomically guarantee «create-or-adopt» without API support for conditional creation or name uniqueness constraints. ## Documentation Model From the unified YAML, generate: - Resource page: CRUD params, outputs, lifecycle defaults, operations summary - MAN page: service_man + parameter man blocks - Resources index: each resource links to its page and its MAN page ## Pipeline Overview (DevOps) 1) Generate unified YAML from API for services_list.txt. 2) Generate provider code from YAML. 3) Generate documentation from YAML. 4) Build provider for linux/windows/darwin. 5) Upload provider artifacts to registry. 6) Build and publish docs to site. ## Non-Negotiable Rules - No manual edits to generated YAML or generated Go code. - Any change must come from API or generator logic updates. - The generator must enforce these rules and fail fast on drift.