Azure / Azure/azure-sdk-tools

[APIView] Epic: Project-based Organization and Namespace Reviews

Open
#13,301 2 comments 0 reactions 1 assignee Claimed by @AlitzelMendez View on GitHub
APIView Epic
Dominant language
C#
Stars
135
Forks
260
Avg merge
3d 1h
Merged PRs (30d)
143

Description

From approved PR: #13048.

# APIView Project-Centric Model Proposal

## Overview

This proposal introduces a new top-level **Project** entity to APIView. A Project represents a service across all languages and is always anchored to a single TypeSpec specification. It aggregates:

* The TypeSpec Review
* All language-specific Reviews
* Namespace approval history (approved + rejected)
* Links to EngSys artifacts (tspconfig.yaml, metadata) and cross-language identifiers

---

## Problem Summary

APIView’s current unit of organization is the **Review**, which corresponds to a single package in a single language. This structure does not provide:

### 1. Cross-Language Grouping

We cannot reliably visualize all languages for a service or know which SDKs exist or are missing.

### 2. Early Namespace Approval

Namespace approval depends on uploading SDK packages for each language, even though the only authoritative namespace source is **tspconfig.yaml**. We cannot approve namespaces until after SDK generation, which is often too late in the process.

### 3. Namespace History

APIView only tracks namespace approval at a *review* level. There is no historical record of:

* Rejected namespaces
* Withdrawn or replaced proposals
* Namespace decisions tied to TypeSpec revisions

### 4. Visibility for Stakeholders

Stakeholders need one place to answer:

* "What is the status of this service across languages?"
* "Which namespaces were proposed and why were some rejected?"

---

## Goals

The new **Project** model will:

### ✓ Group all language reviews under a single entity

Bound by the same cross-language identifier for a TypeSpec-defined service (the TypeSpec namespace).

### ✓ Allow early namespace approval before any SDK is generated

Using `tspconfig.yaml` as the single source of truth.

### ✓ Track full namespace history

Including rejected, withdrawn, and superseded proposals.

### ✓ Improve stakeholder experience

Navigation, dashboards, and discussions become cross-language by default.

### ✓ Provide a stable home for TypeSpec reviews

Every Project has exactly one TypeSpec Review.

### ✓ Provide a means to group related Projects under a higher-level umbrella (future work).

Projects can manually be aggregated into service portfolios in the future. For example, KeyVault Keys, Secrets, and Certificates
could be grouped under a single KeyVault service portfolio. This is out of scope for this proposal, but is a natural extension of this model.

---

## High-Level Design

### 1. Introduce a `Project` Entity

A Project:

* Has a stable, opaque ID (a GUID generated by APIView), ensuring identity does not depend on the TypeSpec namespace.
* Owns one TypeSpec Review
* Owns zero or more language-specific Reviews
* Stores namespace history across languages

The Project’s human-facing namespace is tracked separately via TypeSpec namespace history, not the ProjectId.

```
Project → Review (TypeSpec) [required]
→ Review (Python)
→ Review (C#)
→ Review (Java)

```

---

## Project Identity & Namespace Matching

### Project Identity

Each Project is assigned a stable, opaque identifier (ProjectId), which is a GUID generated by APIView at creation time. This ensures that the Project’s identity is not tied to the TypeSpec namespace or any other mutable property. The ProjectId is used as the primary key for all cross-language grouping and review attachment logic.

### Namespace Matching

The Project’s human-facing namespace (as defined in TypeSpec) is tracked separately from the ProjectId. APIView maintains a namespace history for each Project, recording all proposed, approved, rejected, and withdrawn namespaces over time. This allows Projects to evolve their namespaces without losing historical context or breaking identity links.

When a new Review (for any language) is uploaded, APIView uses the Review’s CrossLanguagePackageId to find the correct Project. The attachment is successful if the CrossLanguagePackageId matches any namespace in the Project’s namespace history. If CrossLanguagePackageId is not provided (for example, in a manual review) but the package namespace matches one already approved, it provides a backup means to attach the revision to the review and project. This decouples identity from namespace and supports scenarios where namespaces change or are superseded.

This approach resolves several open questions about identity, namespace changes, and review attachment, and provides a robust foundation for future enhancements.

### 2. Integration Points

#### **When just a TypeSpec `tspconfig.yaml` is available**

User can manually create a Project in APIView by providing the URI to the `tspconfig.yaml` file. This is required because `tspconfig.yaml` does NOT contain any information about the TypeSpec namespace.

APIView will:

* Infer the TypeSpec namespace from the URL.
* IF a main.tsp file is present in the same directory, it will compile it enough to extract Namespace, Service Name and Decription, if available. This is optional and only used for convenience. If main.tsp is not present, the inferred namespace will be used as a fallback.
* Parse the file to extract language-specific metadata like package name and namespace.
* Create the Project
* Register the namespaces as proposals (in proposed status)

#### **When a TypeSpec Review is uploaded**

* Compile the TypeSpec to get the namespace, service name, and description from the TypeSpec file.
* Parse language-specific metadata from `tspconfig.yaml`
* Create the Project and attach the TypeSpec review as the canonical spec for that Project

#### **When a language Review is uploaded**

APIView will automatically:

* Look at `CrossLanguagePackageId`
* Find the matching Project
* Attach the Review to the Project
* Register its namespaces as proposals (if not already approved)

If the `CrossLanguagePackageId` is not provided, APIView will use the package namespace from the Review to find the matching Project. This provides a fallback mechanism for scenarios where the `CrossLanguagePackageId` is missing or incorrect.

---

## Updated Data Model

### Project Model

```tsp
/** New top-level Project entity */
model Project {
/** GUID identifier for the Project. */
Id: string;
/** Human-friendly name of the Project. Otherwise, defaults to the namespace. */
DisplayName?: string;
Description?: string;
/** Service-level contacts. */
Owners?: string[];
/** Field for the latest approved (or proposed) TypeSpec namespace. */
@convenience Namespace: string;
NamespaceInfo: ProjectNamespaceInfo;
/** Associated Review IDs. */
@convenience ReviewIds: string[];
ChangeHistory?: ProjectChangeHistory[];
CreatedOn: utcDateTime;
LastUpdatedOn: utcDateTime;
IsDeleted: boolean;
}

/** Project-level change history */
model ProjectChangeHistory extends ChangeHistoryModel {
ChangeAction: ProjectChangeAction;
}

/** Types of changes that can occur to a Project. */
enum ProjectChangeAction {
Created,
...
Deleted,
UnDeleted
}
```

### Namespace Proposal Updates

```tsp
/** Aggregated namespace information for a Project. */
model ProjectNamespaceInfo {
/** Currently approved namespaces. */
ApprovedNamespaces: NamespaceDecisionEntry[];
/** Full history of namespace proposals and decisions. */
NamespaceHistory: NamespaceDecisionEntry[];
}

/** Status of a specific namespace proposal under a Project. */
enum NamespaceDecisionStatus {
Proposed,
Approved,
Rejected,
Withdrawn
}

/** A single namespace proposal (per language & package). */
model NamespaceDecisionEntry {
Language: string;
PackageName: string;
Namespace: string;
Status: NamespaceDecisionStatus;
Notes?: string;
DecidedBy?: string;
DecidedOn?: utcDateTime;
}
```

---

## Review Model Changes

Minimal updates to link Reviews to Projects and remove namespace approval fields
from Reviews.

```diff
model Review {
... existing fields ...
- NamespaceReviewStatus: NamespaceReviewStatus;
- NamespaceApprovalRequestedBy: string;
- NamespaceApprovalRequestedOn?: utcDateTime;
+ ProjectId?: string;
}
```

We will also remove the `NamespaceReviewStatus` enum.

---

## Key Workflows

### Workflow 1 — Project Creation via TypeSpec Review

1. EngSys parses `tspconfig.yaml` from a TypeSpec Review
2. It emits Project metadata JSON
3. TypeSpec is compiled to get namespace, service name, and description
3. APIView ingests the JSON in conjunction with the TypeSpec metadata to creates/updates the Project
4. TypeSpec Review is created/linked
5. Namespace proposals are initialized

### Workflow 2 — Attaching Language Reviews

1. EngSys runs APIView parser for a given language.
2. APIView attempts to match `CrossLanguagePackageId` with Project namespace. If not found, it uses the package namespace as a fallback.
3. The Review is attached
4. Namespace proposals are registered/updated as needed

### Workflow 3 — Namespace Approval Process

1. Architect reviews namespace proposals
2. Decisions change `Status` to Approved/Rejected
3. Decision is recorded in Project change history
4. ApprovedNamespaces is updated automatically

## Alternative Workflows

### Alternative Workflow 1 — Manual Project Creation

1. User provides URL to `tspconfig.yaml`
2. APIView parses it and creates a Project
3. User uploads TypeSpec Review and language Reviews later, which will attach automatically

### Alternative Workflow 2 — Existing Reviews Migration

1. Script creates Projects for existing TypeSpec Reviews
2. Script attaches existing language Reviews
3. Script infers namespace state from existing data.
a. If any revision is approved, namespace is approved
b. Otherwise, namespace is proposed

### Alternative Workflow 3 — Manual Upload with No Metadata

1. User uploads a manual CodeFile with no cross-langauge metadata
2. If a Project exists with matching namespace, attach Review
3. Otherwise, warn user and allow them to cancel or create an "orphan" review or cancel

### Alternative Workflow 4 - Uploading a new Revision that Changes Namespace

1. New APIRevision uploaded that changes the namespace
2. If there is an approved namespace for that language, flag this as an error but allow the upload. This is considered a fatal error
3. If there is no approved namespace for that language, create a new namespace proposal in proposed status, updating the previous proposal:
a. Proposed → Withdrawn
b. Rejected → Rejected (keep the same)

---

## Open Questions

1. The namespace behavior proposed would mean that a Project could have multiple rejected namespaces, and other Projects would not be able to use those namespaces. Is that acceptable?

---

## Next Steps

* Validate with EngSys that tspconfig-derived metadata can be reliably emitted
* Create migration script for existing Reviews
* Create new endpoint in APIView for registering new Projects manually with `tspconfig.yaml`
* Implement CrossLanguagePackageId handling in language parsers

---

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.