---
meta:
  version: "v1"
  source: https://superpowers.frontis.nl/conventions/project-context.yaml
  snapshotDate: 2026-05-21
  description: >
    Canonical schema defining the project-context variables used across
    FrontisRAD .NET and Nuxt projects. This file specifies variable names,
    types, casing rules, case-sensitivity, allowed mappings, examples,
    cross-variable constraints, and precedence. It is schema-only and does
    not contain concrete project values. Actual values belong in a separate
    project.json instance file.

globalDefaults:
  caseSensitive: true

precedence:
  - tier: 1
    name: crossVariableConstraints
    description: >
      Cross-variable constraints override all other rules. When a
      constraint's 'when' condition matches, its 'then' restrictions
      take absolute precedence.
  - tier: 2
    name: variableRules
    description: >
      Per-variable rules (casingRule, mappings, allowedValues,
      caseSensitive) override global defaults.
  - tier: 3
    name: globalDefaults
    description: >
      Fallback settings applied when no variable-specific rule or
      cross-variable constraint exists.

constraints:
  - id: shared-hosting-environments
    description: >
      Shared hosting permits only the production environment.
      When hosting is set to 'shared', the environments array
      must contain only 'prod'.
    when:
      hosting: "shared"
    then:
      environments:
        allowedValues: ["prod"]
        message: >
          Shared hosting supports only the production environment
          (plus local development). Use dedicated hosting for
          additional OTAP environments.

exceptions: []
# Exceptions document deviations from naming rules.
# Each entry must include: id, variable, overrides, justification.
# Example:
#   - id: legacy-company-casing
#     variable: company
#     overrides: casingRule
#     justification: "Historical brand name predates the casing standard."

variables:
  company:
    type: "string"
    required: true
    casingRule: "registered"
    caseSensitive: false
    description: >
      Owning organisation or customer. Uses registered casing as-is
      (not PascalCase-enforced). Doubles as the Azure DevOps project
      name. Any company name is valid as long as it follows the
      casing/format rules defined here.
    examplesRef: "companies"
    examples:
      valid:
        - "FrontisRAD"
        - "Van der Berg & Partners"
      invalid:
        - "frontisrad"
        - "FRONTISRAD"

  product:
    type: "string"
    required: true
    casingRule: "pascal_case"
    caseSensitive: false
    description: >
      Product or product line within the company. Must use PascalCase.
      Any product name is valid as long as it follows the casing rules.
    examplesRef: "products"
    examples:
      valid:
        - "ProjectContext"
        - "InvoicePortal"
      invalid:
        - "projectContext"
        - "project-context"
        - "project_context"

  component:
    type: "string"
    required: true
    casingRule: "pascal_case"
    caseSensitive: false
    description: >
      Specific deliverable or module within the product. Must describe
      its purpose — generic names are not allowed. Must use PascalCase.
    disallowedPatterns:
      - "Helpers"
      - "Common"
      - "Utilities"
      - "Misc"
      - "Shared"
      - "General"
    examples:
      valid:
        - "ApiGateway"
        - "CustomerOnboarding"
        - "BillingEngine"
      invalid:
        - "Helpers"
        - "Common"
        - "apiGateway"
        - "api-gateway"

  hosting:
    type: "string"
    required: true
    casingRule: "exact_match"
    caseSensitive: true
    description: >
      Determines if the project will have dedicated hosting in Azure
      or if it will use shared hosting. Dedicated hosting means an
      App Service Plan per OTAP environment. Shared hosting means an
      already-running hosting plan. Shared hosting is intended for
      smaller customers with a tight budget. For shared hosting, only
      a production environment exists (plus local development).
    mappings:
      - longForm: "dedicated hosting"
        abbreviation: "dedicated"
      - longForm: "shared hosting"
        abbreviation: "shared"
    examples:
      valid:
        - "dedicated"
        - "shared"
      invalid:
        - "Dedicated"
        - "SHARED"
        - "self-hosted"

  environments:
    type: "array"
    required: true
    casingRule: "lowercase"
    caseSensitive: true
    description: >
      Determines which OTAP (Ontwikkeling, Test, Acceptatie, Productie)
      environments are applied to the project. OTAP is the Dutch
      methodology for structured software development and deployment.
      A project may use the complete set of OTAP environments, or a
      subset (e.g., only production, or only test and production).
      The value is an array containing one or more of the allowed
      abbreviations.
    mappings:
      - longForm: "development"
        abbreviation: "dev"
      - longForm: "test"
        abbreviation: "test"
      - longForm: "acceptance"
        abbreviation: "acc"
      - longForm: "production"
        abbreviation: "prod"
    examples:
      valid:
        - "dev"
        - "test"
        - "acc"
        - "prod"
      invalid:
        - "Dev"
        - "PROD"
        - "prd"
        - "development"
        - "acceptance"

  grippNumber:
    type: "integer"
    required: true
    casingRule: "none"
    caseSensitive: false
    description: >
      The customer number in Gripp. Gripp is the internal software
      used to book hours and create invoices. The value is always a
      numeric integer.
    examples:
      valid:
        - 118899
        - 128444
      invalid: []

  team:
    type: "string"
    required: true
    casingRule: "pascal_case"
    caseSensitive: true
    description: >
      The team that implements the project. Must match one of the
      defined team abbreviations exactly (case-sensitive).
    mappings:
      - longForm: "Team Everest"
        abbreviation: "Everest"
      - longForm: "Team Quack"
        abbreviation: "Quack"
    examples:
      valid:
        - "Everest"
        - "Quack"
      invalid:
        - "everest"
        - "QUACK"
        - "Team Everest"
