Skip to content

Serviced Account Mini Model

Purpose

This document defines the current v0 Serviced Account model for Odoo inside the DIRAC framework.

It is now the primary developer-facing design document for SA governance.

Read this document as the V0 layer in the progressive SA design.

For the intended progression of V0V1V2, see SA Design Refinement Layers.

Terminology in this document follows the repo definitions in Terminology, especially Serviced Account (SA), Portal App (PA), actor, and sa.

The SA governance kernel currently covers three data domains:

  1. Accounts
  2. People through memberships
  3. Assets through fleet/items

1. Core Principle

Governance is separate from ERP transaction mechanics.

Domain Responsibility
Odoo ERP Transactions, stock movements, serial tracking, accounting, logistics
Serviced Account (SA) Governance boundary for access, assignment, and authority
Portal App (PA) SA-governed portal form of OVApp; user flow, context establishment, filtering, and proxy execution

The SA model is a governance model, not a transaction model.

SA does not replace native Odoo transaction behavior.

Native Odoo remains the system of record for:

  • customers in res.partner
  • sales orders in sale.order
  • invoices in account.move
  • payments and accounting behavior
  • inventory execution and stock movements

The ov.* domain adds governance structure around those native objects.

2. SA Modeling Framework

The model should be read in three segments.

Segment Core Question Primary v0 Object
Accounts What governed organization context exists? ov.serviced_account
People Who may act in that context, and with what authority? ov.membership
Assets What fleet/items are governed within that context? ov.asset wrapper over native Odoo physical objects

Current design status:

  • Accounts: structurally defined for v0
  • People: structurally defined for v0 and implementation-driving
  • Assets: governance direction is now explicit through an SA asset wrapper model

This V0 layer should be understood as the minimum pattern that enables PA surfaces such as:

  • My Quotes
  • My Sales
  • My Tickets

Later layers may refine how hierarchy and durable-object visibility work, but they build on top of this base rather than replacing it.

3. PA Access Model

PA is the entry point for SA-governed operations.

In this design, PA is not separate from OVApp.

It is the OVApp surface operating under SA login governance and SA-context selection.

3.1 Login

  • login is SA-agnostic
  • a PA user is any previously registered person with at least one SA membership

3.2 Context Flow

The canonical PA flow is:

  1. Login
  2. My SAs
  3. My Apps

If the user has only one SA, that SA may be auto-selected.

3.3 Operating Context

When a user enters an app, PA establishes:

  • actor
  • sa

This {actor, sa} context is the basis for authorization, attribution, and filtering.

4. Accounts Segment

4.1 What Counts as a Serviced Account

For v0, a Serviced Account is an organization context that receives governed services, delegated access scope, or account-level operational governance.

This may include:

  • EXTC for a true external client/customer organization
  • OVAC for an affiliated or subsidiary organization that still needs governed service/account treatment

This does not mean all internal Omnivoltaic org units should automatically be modeled as Serviced Accounts.

Working rule:

  • if the organization is treated as an account subject of service/governance, it may be a Serviced Account
  • if the organization is purely an internal operating structure, it should remain in normal Odoo company/org constructs unless a later need proves otherwise

4.2 ov.serviced_account

Attribute Type Purpose v0 Guidance
name Char Human-readable account name Required
partner_id Many2one(res.partner) Canonical organization partner record Required; exactly one is_company = true partner per SA
account_class Selection Distinguish OVAC vs EXTC at minimum Required
parent_id Many2one(ov.serviced_account) Hierarchy / branch structure Required in practice; root nodes are Omnivoltaic companies
child_ids One2many(ov.serviced_account) Convenience inverse for hierarchy Derived
state Selection Governance lifecycle state Start with active, inactive
notes Text Short admin/governance note Optional; non-authoritative

4.3 Account Invariants

  • A Serviced Account is an organization context, not a person.
  • A Serviced Account is the primary governance wall.
  • Hierarchy belongs on ov.serviced_account, not on res.partner.parent_id.
  • Governance structure must not duplicate CRM, accounting, or company setup.
  • An SA is created in hierarchy context, not born without parent context.

4.4 SA Hierarchy Direction

Current rule:

  • SA_ROOT is the system root SA
  • each SA<x> is a proper SA under SA_ROOT
  • every non-root SA is created from a parent SA
  • in normal operation, the SA hierarchy should be mirrored by res.partner.parent_id on the anchor company-partner records, but that mirror is a soft-alignment rule rather than a hard invariant for now

5. People Segment

This is the most settled part of the current SA design.

5.1 Core Decision

People are anchored in res.partner, but authority never lives on res.partner alone.

Authority is carried by the relationship between the person and the Serviced Account.

That relationship is modeled as ov.membership.

5.2 Why the People Model Works This Way

The same person may appear once in Odoo but act in multiple governed contexts.

Example:

  • the person is an employee/member inside an OVAC serviced account
  • the same person is also designated as account manager or sales-facing actor for an EXTC serviced account

Therefore:

  • role meaning cannot safely live on res.partner
  • permissions must stay isolated by account context
  • authorization must be evaluated in account context, never globally by person

5.3 ov.membership

Attribute Type Purpose v0 Guidance
serviced_account_id Many2one(ov.serviced_account) Governed account context Required
person_partner_id Many2one(res.partner) Person acting in that context Required; person only
role_code Char or Selection Optional local role label in this account context Do not treat as the primary authority model
membership_state Selection Membership status Start with active, suspended, revoked
scope_policy Selection Scope of authority Keep simple in v0
effective_from Datetime Optional activation time Optional
effective_to Datetime Optional expiry time Optional

5.4 People Invariants

  • A person may have multiple memberships across multiple Serviced Accounts.
  • Role semantics belong to ov.membership, not directly to res.partner.
  • Membership is contextual.
  • Membership in one SA does not imply rights in another SA.
  • Platform/system administration is separate from SA-context authority.
  • Membership hierarchy, not semantic role labels, is now the primary authority and reporting structure inside an SA.
  • At any point in time, a person should be associated with one company only on the Odoo side. This is an accepted temporary design weakness while the Odoo company model and the SA model continue to converge.

5.5 Hierarchy Direction

The v0 shorthand role labels are no longer the primary way to understand SA authority.

Current direction:

  • authority inside one SA follows the explicit membership tree
  • the current sa_manager is the root of that membership tree
  • any member with subordinates may roll up team-level reporting inside the current SA
  • only the current sa_manager may roll up from the current SA into descendant child-SAs
  • local role labels may still exist for business description, but they should not be used as the primary authority model

5.6 People Design Already Settled

The discussions so far establish these current decisions:

  1. res.partner is the identity anchor for the person.
  2. ov.membership is the authority-bearing relationship.
  3. One person can participate in both OVAC and EXTC contexts without schema breakage.
  4. Context-specific roles are valid even when the same person appears in multiple governance contexts.
  5. Sensitive cross-company combinations must be reviewable and auditable, but should not be hard-blocked in the base schema.
  6. Proxy execution must preserve attribution to the real human actor separately from the technical Odoo user.
  7. Explicit hierarchy is now the primary authority and reporting structure; old shorthand labels such as admin, staff, and agent are no longer the semantic model of record.

5.7 Identity and Proxy Implications

Keep these layers separate:

  • identity source: Teams / Microsoft-based identity, local portal identity, or other future IdP
  • person anchor in Odoo: res.partner
  • execution identity in Odoo: proxy/internal res.users
  • governance authority: ov.membership

Proxy assumption:

  • proxy res.users performs technical execution
  • real human actor remains attributable separately
  • serviced-account context remains explicit for audit and authorization

6. Governance Stamp Pattern

PA-governed records carry a permission stamp:

  • actor
  • sa

Represented together as:

  • {actor, sa}

Interpretation:

  • {actor = null, sa = X} means shared or unassigned within SA X
  • {actor = A, sa = X} means assigned to actor A within SA X

The current implementation direction is to apply this stamp pattern to Odoo records touched through PA-proxy, including:

  • res.partner
  • quotation / sales records
  • product / asset-related records
  • SA-native governance records

7. Visibility Model

7.1 Base Rule

A record is visible in PA only when:

  • record.sa == current_sa

7.2 Actor Rule

Inside the SA boundary:

  • sa is the inclusive selector
  • actor is the exclusive selector

7.3 Policy Shapes

Visibility is defined per app.

Current policy shapes:

  • assigned_only
  • show only records where actor == current_actor
  • assigned_plus_unassigned
  • show records where actor == current_actor or actor is null
  • sa_wide
  • show all records within the current SA

7.4 Current Role Effect on Visibility

For now, visibility and reporting should be understood primarily from hierarchy position:

  • ordinary visibility remains scoped first by sa
  • actor-level visibility remains app-specific
  • any member with subordinates may get direct-report and recursive team reporting within the current SA
  • the current sa_manager may additionally get SA-level roll-up from the current SA through descendant child-SAs

Likely PA surfaces include:

  • My Team
  • My Sales by Team
  • My District Sales

These should be implemented as Odoo reporting objects surfaced through PA, not as separate SA-native aggregation logic.

8. Membership Integrity

If actor is not null, then that actor must be a valid member of the stamped SA.

Invalid example:

  • {actor = A, sa = X}
  • actor A is not a member of SA X

This is an integrity failure.

8.1 Membership Removal Rule

If membership between actor and sa is removed, integrity must be restored by:

  • setting actor = null

8.2 Reassignment Paths

Two reassignment paths are accepted:

  • direct reassignment from actor X to actor Y
  • indirect normalization to actor = null when membership removal breaks integrity

9. Assets Segment

Asset governance is now modeled through an explicit SA-native wrapper object.

9.1 Core Asset Model

Introduce:

  • ov.asset

This is the governance/application object PA should work with for assets.

It is not the raw physical Odoo object.

9.2 Wrapper Purpose

ov.asset gives business and governance meaning to an underlying physical Odoo object.

At minimum it should carry:

  • name
  • description
  • asset_class
  • asset_ref
  • serviced_account_id
  • governance/audit fields including {actor, sa} semantics

Example:

  • Name: Nairobi Swap Network 1
  • Description: a group of stations on the west part of Nairobi ...

9.3 Type-Dependent Physical Reference

asset_ref is type-dependent by asset_class:

  • FLEET -> stock.location
  • ITEM -> stock.production.lot

This means:

  • fleet / operational grouping aligns with stock.location
  • serialized item aligns with stock.production.lot

9.4 Nullability

For flexibility:

  • serviced_account_id may be null
  • asset_ref may be null

This supports limbo or revoked-affiliation states where the wrapper still exists but is not currently affiliated to an SA or bound to a current physical reference.

9.5 Governance Rule

{actor, sa} should live on the wrapper object.

This means PA primarily governs assets through ov.asset, not by stamping only the raw Odoo physical models.

9.6 Ownership Interpretation

Current interpretation:

  • a physical asset cannot belong to more than one SA at a time
  • SA affiliation reflects ownership or governed possession in the business sense
  • initial assignment of assets to an SA happens from the Odoo side, not by self-assignment from the SA side

9.7 No SA-Side Asset Tree

Do not introduce an additional SA-side parent/child asset tree.

Current rule:

  • a fleet is treated as a single governed concept
  • it is not an SA-side collection object with explicit child asset rows

9.8 Fleet and Item Membership

If the underlying Odoo location implies item membership, that membership should be inferred from Odoo structure.

Therefore:

  • an item should not maintain a separate independent SA-side membership while already bound through a fleet/location relationship
  • if a location has no fleet binding, an item may be affiliated directly as an ITEM

9.9 Wrapper Continuity

ov.asset is a governance hat placed on a physical thing.

Current direction:

  • the hat may change
  • the physical thing wearing the hat may also change

So the wrapper is allowed to persist while its current physical reference changes over time.

10. Separation of Concerns

Domain Responsibility
res.partner Identity anchor for organizations and people
Odoo core models Transaction and accounting truth
ov.serviced_account Governed service-account tree
ov.membership Authorization relationship in account context
ov.asset SA-native governance wrapper for assets
stock.location / stock.production.lot Native asset/logistics substrate
PA / proxy layer Context establishment, permission resolution, privileged execution

11. Developer Starting Point

If developers start coding now, the first prototype should prove:

  1. An organization partner can be wrapped by ov.serviced_account.
  2. A person partner can hold multiple ov.membership rows.
  3. One person can appear in both OVAC and EXTC contexts without schema breakage.
  4. Role lives on membership, not on partner.
  5. {actor, sa} can stamp PA-governed Odoo records.
  6. Asset governance can be expressed through ov.asset as a wrapper over native Odoo asset structures.
  7. Explicit hierarchy can drive team-level and SA-level reporting without depending on shorthand role labels.

12. Deferred by Design

Explicitly defer these items until after the first prototype:

  • exact field names and base-model strategy for the {actor, sa} stamp
  • exact field design for ov.asset
  • final membership-management action naming and UI sequencing
  • approval workflow engine
  • detailed SSO mapper implementation
  • advanced conflict-of-interest rule engine

13. Guiding Principle

Keep the Serviced Account model:

  • structural, not transactional
  • contextual, not person-global
  • explicit in authority boundaries
  • aligned with native Odoo primitives
  • conservative in scope

14. SAA And SAM Operating Split

Use the following table as the working division between SA Administration (SAA) and SA Management (SAM).

The main rule is:

  • SAA assigns or governs what belongs to an SA
  • SAM manages work and operations inside the already valid SA scope
Record or decision area SAA responsibility SAM responsibility Notes
SA creation and hierarchy Create SA, set parent SA, preserve hierarchy invariants Use the resulting SA structure Structural governance belongs to SAA
SA anchor partner Create and govern the canonical company-partner anchor Consume it as context Anchor integrity is not ordinary business management
SA membership Add, remove, suspend, and structurally govern membership rows Work through valid memberships Participation in SA is established by SAA
sa_manager identity Change manager through invariant-safe structural operation Operate with current manager authority Manager transition is structural, not casual reassignment
Assigning a shared structural object to an SA Decide whether the object is explicitly SA-scoped Use the object once it is in SA scope Example: service location, fleet, or other shared governed object
Removing a shared structural object from an SA De-affiliate or retire the SA assignment Stop using it operationally Structural scope changes belong to SAA
Shared SA-wide records already in scope Define the allowed boundary and lifecycle rules Read and manage them inside policy SAM manages within the structural boundary that SAA set
Actor assignment inside an SA Define permitted assignment rules and invariants Assign, reassign, and work records within those rules Example: lead owner, reservation owner, customer steward
Customer/account operational ownership Define whether the customer model is SA-scoped at all Manage customer relationships and assignments within the SA Do not collapse customer identity and customer ownership
Location or fleet operational use Govern whether the location or fleet belongs to the SA Use, monitor, reserve, issue, and coordinate service through it Shared structural assignment first, operations second
Item-level reservation or custody Usually only define invariant rules Create and manage the actual operational assignment These are typically SAM work objects
Reporting roll-up Define hierarchy and manager structure that makes roll-up possible Consume team-level and SA-level views Hierarchy from SAA, business use by SAM

SAA Versus SAM Summary

Question Primary owner
Does this record or structure belong to SA X at all? SAA
Is this person allowed to participate in SA X? SAA
Can this shared location, fleet, or governed object be used by SA X? SAA
Who is currently handling this lead, customer, reservation, or service action inside SA X? SAM
Who may see and manage work records within the current SA? SAM, subject to the structure set by SAA
Who preserves hierarchy, membership, and root-manager invariants? SAA