Create an Organization, Project, and Application Specification
Turn a customer idea into a tenant-scoped, versioned contract without creating a runtime prematurely.
Run it in the public monorepo
This course is built around the public Zheta Kubernetes Lab monorepo. The excerpt below is runnable source, not pseudocode.
Source: services/control_plane/domain.py
def create(self, project_id: str, organization_id: str, name: str, actor: str, archetype: str) -> Project:
project = Project(project_id, organization_id, name, actor, blueprint={"name": name, "archetype": archetype})
project.collaborators.add(actor)
with self.repository.transaction():
self.repository.create(project)
self._audit(project, actor, "project.created")
return project
Code to reality
- Declared intent
- Create one tenant-owned project and its audit evidence as a single product operation.
- Interpreter
- Python executes the Forge domain model after the controller supplies authenticated command values.
- Software effect
- The repository durably owns the project while the event port publishes project.created evidence.
- Hardware effect
- The service process uses CPU and writes database pages to its persistent volume or managed database.
- Observable evidence
- A tenant-scoped GET plus a project.created evidence record proves both state and accountability.
Start with the people and the result they need
The source tables below remain the detailed contract. Begin with these customer paths:
- D04-UC-01
- Person: Organization owner
- Job: Create a project and submit a bounded AI application specification
- Observable result: Valid revision is immutable, tenant-scoped, and ready for generation review
- D04-UC-02
- Person: Application creator
- Job: Choose one of three archetypes and revise its requirements
- Observable result: New revision supersedes rather than overwrites prior intent
Turn each customer job into a testable story
Now turn each customer job into a story with a result that an engineer can check:
- D04-US-01
- Story: As an organization owner, I want every app specification validated and versioned, so that reviewers know exactly what generation will consume
- Observable acceptance: Response contains organization, project, app, revision, schema version, and content hash
- D04-US-02
- Story: As an application creator, I want revisions instead of in-place edits, so that audit and rollback retain the original intent
- Observable acceptance: Old revision remains readable; wrong-tenant read returns denial and trace ID
Add real state and observable proof
Finally trace each story through the system that owns its state and the evidence that proves the outcome:
- D04-FLOW-01
- Trigger: Owner submits an archetype brief
- Responsible systems: verifybearer, ForgeController, Forge, injected repository and event publisher
- Authoritative state: Local SQLite project and evidence stores; PostgreSQL is a configurable adapter target
- Owned record: OrganizationProject
- Observable evidence: Actor, organization, project, revision hash, expected/observed result, local environment, timestamp, trace ID
- Failure signal: Invalid token or tenant, duplicate project ID, or failed persistence
- D04-FLOW-02
- Trigger: Creator requests a revision under another organization
- Responsible systems: ForgeController, Forge, and deterministic generator validation later in the lifecycle
- Authoritative state: Project payload currently owns the embedded blueprint; immutable revision store is not implemented
- Owned record: ApplicationRevision
- Observable evidence: Denial rule, zero foreign writes, audit trace, and successful own-tenant read
- Failure signal: Unsupported archetype fails during generation; no standalone revision evidence exists yet
The enterprise problem and today’s slice
Enterprise problem: Free-form prompts omit ownership, data, identity, and lifecycle constraints, so generation can produce software that nobody can safely approve or retire.
Whole-course context: The service ports assign provider metadata to the control plane; today creates the first durable tenant-scoped project through those interfaces.
Today’s slice: Create the implemented organization-scoped project and embedded archetype blueprint, then specify the separate immutable application-revision record still needed for production.
End-of-day evidence: Authenticated project creation, tenant-scoped retrieval, project.created evidence, and a wrong-tenant denial are reproducible from the HTTP smoke and domain tests; revision hashes remain future evidence.
Still unsolved: No code is generated, previewed, connected, published, or deployed in this slice.
Customer use cases
An application cannot be governed when its tenant and owner are implicit. These use cases create a complete specification and deny a cross-organization reference.
| Use case ID | Actor | Customer job | Success outcome | Denial or recovery evidence |
|---|---|---|---|---|
| D04-UC-01 | Organization owner | Create a project and submit a bounded AI application specification | Valid revision is immutable, tenant-scoped, and ready for generation review | Validation returns field-level errors without creating a revision |
| D04-UC-02 | Application creator | Choose one of three archetypes and revise its requirements | New revision supersedes rather than overwrites prior intent | Cross-organization project reference is denied and audited |
Actor-centred user stories
Mutable requirements destroy reproducibility because a generation run can no longer name its input. These stories require stable revision identity and tenant denial.
| Story ID | Use case IDs | User story | Observable acceptance conditions |
|---|---|---|---|
| D04-US-01 | D04-UC-01 | As an organization owner, I want every app specification validated and versioned, so that reviewers know exactly what generation will consume | Response contains organization, project, app, revision, schema version, and content hash |
| D04-US-02 | D04-UC-02 | As an application creator, I want revisions instead of in-place edits, so that audit and rollback retain the original intent | Old revision remains readable; wrong-tenant read returns denial and trace ID |
End-to-end product flows
Creation begins at Zheta Forge Studio and terminates in a reviewable contract. The denied flow proves that knowing another project's identifier does not grant access.
| Flow ID | Use case IDs | Path | Trigger | Numbered steps | Terminal evidence |
|---|---|---|---|---|---|
| D04-FLOW-01 | D04-UC-01, D04-UC-02 | Happy | Owner submits an archetype brief | 1. Authenticate provider user.; 2. Resolve organization membership.; 3. Create project and application shell.; 4. Validate specification.; 5. Append revision. | Actor, organization, project, revision hash, expected/observed result, local environment, timestamp, trace ID |
| D04-FLOW-02 | D04-UC-01, D04-UC-02 | Denied | Creator requests a revision under another organization | 1. Resolve token organization.; 2. Compare project tenant key.; 3. Deny before write.; 4. Read own project as positive control. | Denial rule, zero foreign writes, audit trace, and successful own-tenant read |
The owner creates governed intent, not a Deployment or database. This keeps product review ahead of resource allocation.
System design derived from the flows
Tenant checks duplicated across handlers eventually disagree. Organization membership is resolved once, while Application Catalog owns project, application, and revision writes.
| Use case ID | Entry point | Responsible services | Authoritative store | Failure evidence |
|---|---|---|---|---|
| D04-UC-01 | POST /projects | verify_bearer, ForgeController, Forge, injected repository and event publisher | Local SQLite project and evidence stores; PostgreSQL is a configurable adapter target | Invalid token or tenant, duplicate project ID, or failed persistence |
| D04-UC-02 | Blueprint fields in POST /projects | ForgeController, Forge, and deterministic generator validation later in the lifecycle | Project payload currently owns the embedded blueprint; immutable revision store is not implemented | Unsupported archetype fails during generation; no standalone revision evidence exists yet |
Identity proves provider-plane membership; Application Catalog alone writes the specification revision after validation.
Data model and ownership
Tenant keys must participate in every lookup or guessed identifiers become an authorization bypass. Control-plane records remain separate from future generated-app data.
Generated-application database: Not created in this slice — only provider control-plane metadata and specification revisions are durable today.
| Record or entity | Store and owner | Primary key | Foreign key or opaque reference | Tenant key | Material constraint | Lifecycle and deletion | Use case IDs |
|---|---|---|---|---|---|---|---|
| OrganizationProject | Control-plane PostgreSQL, owned by Application Catalog | project_id | organization_id local FK | organization_id | Slug unique within organization; tenant included in access predicates | Created, archived, exported, then deleted after dependent apps retire | D04-UC-01, D04-UC-02 |
| ApplicationRevision | Control-plane PostgreSQL, owned by Application Catalog | revision_id | application_id local FK and opaque schema version | organization_id | Immutable body and hash; contiguous successor relation | Appended, superseded, retained for audit, deleted with approved lifecycle job | D04-UC-01, D04-UC-02 |
The revision hash becomes the input identity for generation; audit evidence proves acceptance or denial without gaining runtime authority.
Exercise the specification API
A 201 response is insufficient unless durable tenant-scoped state and audit evidence agree. The current implementation creates a project directly from an authenticated HTTP command; it has no separate organization service, PostgreSQL deployment, or versioned application-spec resource yet. Read the exact model operation in services/control_plane/domain.py.
def create(self, project_id: str, organization_id: str, name: str, actor: str, archetype: str) -> Project:
project = Project(project_id, organization_id, name, actor, blueprint={"name": name, "archetype": archetype})
project.collaborators.add(actor)
self.repository.create(project)
self._audit(project, actor, "project.created")
return project
| Declared intent | Interpreter | Software effect | Hardware effect | Evidence |
|---|---|---|---|---|
| Create one organization-scoped project with an archetype blueprint | The Python controller supplies JWT-derived identity to Forge.create; injected repository and event ports perform side effects | Persists one project in local SQLite and publishes project.created; there is no independent spec-revision record in this implementation | The control-plane process uses CPU, its named volume receives SQLite pages, and the event adapter uses local networking/broker storage | Authenticated POST /projects, tenant-scoped GET /projects/{id}, the project.created event, and the wrong-tenant unit test |
Decision rules
Keep specifications declarative and versioned; do not mix generated source, runtime secrets, or app-user permissions into them. A new archetype is inside the platform only when the same revision contract can describe it without adding app-specific fields to core services.