/******************************************************************************
 * ITLingoCloud - Application Specification (ASL-3.2)
 *
 * The application-level twin of ITLingoCloud-System-2026.rsl. Both specifications
 * describe the same platform as it exists today, as stated in the verified
 * natural-language description ITLingoCloud-System-2026.tex (sections 1 to 12).
 * Identifiers are shared with the RSL specification wherever the concept is the
 * same, so that the two may be read side by side.
 *
 * Elements used: Stakeholder, Actor, ActorRelation, DataEnumeration, DataEntity,
 * DataEntityCluster, UseCase, SecPermission, SecRole, SecAccessPolicy,
 * SecAuthenticationScheme, SecSecret, AppModule, AppComponent, AppService,
 * AppOperation, AppEndpoint, AppEvent, AppChannel, AppIntegration, AppRule,
 * AppJob, AppNotification, UIPage, UIRoute, UIRouteSet, UIContainer,
 * UIComponent, UIAction, OpsStore, OpsRetentionPolicy, OpsObservability,
 * FunctionalRequirement, QualityRequirement, ConstraintRequirement and View.
 ******************************************************************************/

Package itlingo.cloud

System ITLingoCloud "ITLingoCloud" : Application : Application_Web [
    version "2026"
    vendor "ITLingo"
    description "Section 1. A collaborative web platform for producing, governing, and consuming rigorous specifications. Work is organised in three levels of containment: an organisation groups people and shared reference material, a workspace holds one concrete body of specification work, and a document is the unit that carries a file, a type, and a lifecycle. Around that structure sit a registry of specification languages, a mechanism for producing readable deliverables from a specification and a template, and conversational assistance that turns informal description into specification text."
]

/****************************************************
   Stakeholders (Section 2)
*****************************************************/

Stakeholder stk_Platform "ITLingoCloud Platform" : Organization : Organization_Owner [
    concern "Remaining the authority over the editor and the chatbot, and the system of record for every organisation, workspace, document, and specification language."
    responsibility "Decide who may read and write what, and hand the editor and the chatbot their working context."
    description "Section 1. The platform is the authority in all three cooperating parts of the system."
]

Stakeholder stk_PlatformAdministration "Platform Administration" : OrganizationalUnit : OrganizationalUnit_IT [
    concern "Accounts and platform profiles, language governance, platform-wide assistance settings, and the integration with the editor."
    responsibility "Operate the administrative interface, whose capabilities are delegable through no organisation or workspace role."
    description "Section 12. A small set of capabilities belongs to the platform administrator alone."
]

Stakeholder stk_Practitioner "Specification Practitioner" : Person : Person_User [
    concern "Writing, reviewing, and publishing specifications, and consuming published reference material."
    responsibility "Maintain the documents of a workspace and the version labels they carry."
    description "Section 1. One of the two audiences the platform addresses at once."
]

Stakeholder stk_ContainerManager "Organisation or Workspace Manager" : Person : Person_Manager [
    concern "The details, the membership, and, for a workspace, the progress state of one container."
    responsibility "Invite people, change and revoke roles, and govern the container."
    description "Sections 3 and 4. Governs one organisation or one workspace."
]

Stakeholder stk_LanguageCustodian "Language Custodian" : Person : Person_Technical_RequirementsEngineer [
    concern "Evolving the specification languages themselves."
    responsibility "Author grammars and custom services in the browser and prepare versions for publication, which they may not perform."
    description "Section 7. The second audience: language teams prepare and validate a version, and the platform decides what comes into force."
]

Stakeholder stk_Visitor "Unauthenticated Visitor" : Person : Person_User [
    concern "Reaching the public surface of the platform without signing in."
    responsibility "None: no page invites a visitor to request access to anything."
    isExternal
    description "Section 2. May reach the home page, the terms and conditions, the language catalogue, and the workspaces marked public."
]

Stakeholder stk_EditorProduct "ITOI Specification Editor" : System : System_External [
    concern "Language-aware editing of specification files using the grammars the platform holds."
    responsibility "Obtain its languages, its session description, and its importable documents from the platform."
    isExternal
    description "Section 8. The second of the three cooperating parts."
]

Stakeholder stk_ChatbotProduct "Conversational Assistant" : System : System_External [
    concern "Conversing beside one workspace and turning informal description into specification text."
    responsibility "Present the session statement as its credential when it asks the platform to create a document."
    isExternal
    description "Section 9. The third of the three cooperating parts."
]

Stakeholder stk_AssistanceProvider "Assistance Service Provider" : System : System_External [
    concern "Serving the engines an organisation registers in its own catalogue."
    responsibility "Answer under one of three credential arrangements: an access key, a service address, or both."
    isExternal
    description "Section 10. A named family of services, whether a commercial service or one the organisation hosts itself."
]

/****************************************************
   Actors (Section 2)
*****************************************************/

Actor a_Visitor "Visitor" : User [
    represents stk_Visitor
    responsibility "Browse the public surface and read published material in public workspaces."
    description "Section 2. May reach the home page, the terms and conditions, the catalogue of specification languages and the detail page of any language version in force, and the list of workspaces their owners have marked public. Inside a public workspace may read the summary, browse and download the published documents, reach the specifications section and open the workspace read-only in the editor, and view its conversations."
]

Actor a_RegisteredUser "Registered User" : User [
    represents stk_Practitioner
    responsibility "Hold exactly one platform profile and accept the terms and conditions at registration."
    description "Section 2. Registration asks for a name, an email address, a password, and explicit acceptance of the terms and conditions, recorded with the version accepted, the moment of acceptance, and the network address and browser identification of the request. Any authenticated user may create an organisation at any time."
]

Actor a_PlatformMember "Platform Member Profile" : User [
    isA a_RegisteredUser
    represents stk_Practitioner
    description "Section 2. The profile every newly registered portal user receives automatically. Sees only the organisations and workspaces in which the holder has an accepted role."
]

Actor a_PlatformManager "Platform Manager Profile" : User [
    isA a_PlatformMember
    represents stk_ContainerManager
    description "Section 2. A member who additionally holds write and delete authority over the organisations and workspaces of which they are an accepted member."
]

Actor a_PlatformAdministrator "Platform Administrator Profile" : User [
    isA a_RegisteredUser
    represents stk_PlatformAdministration
    description "Sections 2 and 12. Full authority over every record on the platform, irrespective of membership, and the only actor with unrestricted sight. The administrator profile is not granted automatically to anyone."
]

Actor a_OrganisationManager "Organisation Manager" : User [
    represents stk_ContainerManager
    description "Section 2. May edit the organisation details, invite people, change and revoke the roles of others, create workspaces, create and edit organisation documents, configure the organisation assistance settings, and delete the organisation."
]

Actor a_OrganisationDocumentManager "Organisation Document Manager" : User [
    represents stk_Practitioner
    description "Section 2. May create, edit, and delete organisation documents, and create workspaces, but may not alter the organisation or its membership."
]

Actor a_OrganisationMember "Organisation Member" : User [
    represents stk_Practitioner
    description "Section 2. May view the organisation and create workspaces in it, and may read and download only those organisation documents that have been published."
]

Actor a_WorkspaceManager "Workspace Manager" : User [
    represents stk_ContainerManager
    description "Section 2. May edit the workspace properties and progress state, invite people, change and revoke roles, create, edit, and delete workspace documents, and delete the workspace."
]

Actor a_WorkspaceDocumentManager "Workspace Document Manager" : User [
    represents stk_Practitioner
    description "Section 2. May create, edit, and delete workspace documents, but may not alter the workspace or its membership."
]

Actor a_WorkspaceMember "Workspace Member" : User [
    represents stk_Practitioner
    description "Section 2. May view the workspace and read and download only those workspace documents that have been published."
]

Actor a_LanguageMaintainer "Language Maintainer" : User [
    represents stk_LanguageCustodian
    description "Sections 2 and 7. Named on a language family and shared by all of its versions. Language maintainership is granted per family and is independent of platform profiles and of organisation and workspace roles. A maintainer may not publish."
]

Actor a_SpecificationEditor "ITOI Specification Editor" : ExternalSystem [
    represents stk_EditorProduct
    description "Section 8. The browser-based specification editor. Obtains languages, session descriptions, importable documents, and the specification corpus of a workspace by asking the platform for them. The platform offers it no way to write a file back, except the delivery of content a conversation has just exported."
]

Actor a_Chatbot "Conversational Assistant" : ExternalSystem [
    represents stk_ChatbotProduct
    description "Section 9. Embedded in the chat section of a workspace and in the equivalent page of a public workspace, and nowhere else. Receives a signed session statement, consults the knowledge pool, and may ask the platform to create a document in the workspace."
]

Actor a_AssistanceEngine "Assistance Engine" : ExternalSystem [
    represents stk_AssistanceProvider
    description "Section 10. An engine registered under a provider in an organisation catalogue or in the platform catalogue, addressed with one of three credential arrangements and bound to one or more of the nine assignable engine roles."
]

ActorRelation ar_EditorCollaboration "Editor collaboration" : Collaboration
    from a_WorkspaceMember to a_SpecificationEditor [
    description "Section 8. The editor is launched from the specifications section of a workspace and serves the launching user under the session description the platform hands over."
]

ActorRelation ar_ChatbotCollaboration "Chatbot collaboration" : Collaboration
    from a_WorkspaceMember to a_Chatbot [
    description "Section 9. A member converses in the context of one workspace, under a session statement valid for one hour."
]

ActorRelation ar_AssistanceDelegation "Assistance delegation" : Delegation
    from a_Chatbot to a_AssistanceEngine [
    description "Section 10. The engines an organisation registers serve the conversation through the nine assignable engine roles."
]

ActorRelation ar_EditorDelivery "Editor delivery" : Collaboration
    from a_Chatbot to a_SpecificationEditor [
    description "Section 9. After creating the document the platform attempts to deliver the same content into a live editing session; the two operations are deliberately not tied together."
]

/****************************************************
   Data enumerations, entities and clusters (Sections 2 to 12)
*****************************************************/

DataEnumeration PlatformProfile "Platform profile" values (
    ProfileMember "Member: the profile every newly registered portal user receives automatically",
    ProfileManager "Manager: a member with write and delete authority over the organisations and workspaces of which they are an accepted member",
    ProfileAdministrator "Administrator: full authority over every record on the platform, irrespective of membership"
) [
    description "Section 2. Every registered user holds exactly one platform profile. The distinction that matters most in daily use is between the administrator and everyone else."
]

DataEnumeration RoleState "Role assignment status" values (
    RolePending "Pending: invited and not yet answered",
    RoleAccepted "Accepted: the only status that grants anything or makes the container visible to the holder",
    RoleRejected "Rejected: the invitation was refused"
) [
    description "Section 2. Each role assignment carries a status of pending, accepted, or rejected, and only accepted assignments grant anything or make the container visible to the holder."
]

DataEnumeration OrganisationRoleType "Organisation role" values (
    OrgManager "Organisation manager",
    OrgDocumentManager "Document manager",
    OrgMember "Organisation member"
) [
    description "Section 2. A user holds at most one role per organisation."
]

DataEnumeration WorkspaceRoleType "Workspace role" values (
    WsManager "Workspace manager",
    WsDocumentManager "Document manager",
    WsMember "Workspace member"
) [
    description "Section 2. A user holds at most one role per workspace. The three workspace roles mirror the organisation roles."
]

DataEnumeration OrganisationState "Organisation state" values (
    OrgActive "Active",
    OrgSuspended "Suspended"
) [
    description "Section 3. Suspending an organisation and reactivating it are not offered anywhere in the portal and are performed through the administrative interface."
]

DataEnumeration OrganisationActivityType "Organisation activity type" values (
    ActivityInformationTechnology "Information technology",
    ActivityMarketing "Marketing",
    ActivityConsulting "Consulting",
    ActivityFinance "Finance",
    ActivityEducation "Education",
    ActivityOther "Other"
) [
    description "Section 3. The activity type is chosen from these six values."
]

DataEnumeration WorkspaceProgressState "Workspace progress state" values (
    ProgressNotStarted "Not started: the initial state, from which the workspace may be started or cancelled",
    ProgressExecuting "Executing: entered by starting the workspace, which records the actual start date",
    ProgressConcluded "Concluded: entered by concluding the workspace, which records the actual end date",
    ProgressCancelled "Cancelled: entered from either of the first two states"
) [
    description "Section 4. Progress is tracked by a state independent of any document lifecycle, and only a workspace manager may change it. The progression is presented rather than enforced, because no transition examines the state a workspace is in before writing the new one."
]

DataEnumeration DocumentState "Document state" values (
    DocDraft "Draft: the working state and the initial one",
    DocInReview "In review: the document has been handed to reviewers",
    DocApproved "Approved: the reviewers have accepted it",
    DocPublished "Published: the document is released, and the only state in which it is visible to ordinary members and, in a public workspace, to visitors",
    DocArchived "Archived: the document is withdrawn from use without being deleted"
) [
    description "Section 5. The states are deliberately not an enforced workflow: an editor sets the state directly and any of the five may be chosen from any other. What the state governs is visibility."
]

DataEnumeration DocumentTypeValue "Document type" values (
    TypeSpecification "Specification",
    TypeSpecificationLibrary "Specification library",
    TypeTemplate "Template: the only type the platform treats differently",
    TypeTechnicalDocument "Technical document",
    TypeDataset "Dataset",
    TypeTutorial "Tutorial",
    TypePromptTemplate "Prompt template",
    TypeOtherDocument "Other"
) [
    description "Section 5. Eight document types are available. Most of them classify and filter without altering what the document page does."
]

DataEnumeration DocumentFormatGroup "Coarse document format" values (
    FormatWordProcessor "Word-processor document",
    FormatSpreadsheet "Spreadsheet",
    FormatPortableDocument "Portable document",
    FormatText "Text",
    FormatOther "Other"
) [
    description "Section 5. The platform groups documents into a coarse format derived from the file name. An extension registered by a specification language counts as text, so specification files are treated as textual content whatever their extension."
]

DataEnumeration ContentLanguage "Content language" values (
    LangEnglish "English",
    LangPortuguese "Portuguese",
    LangSpanish "Spanish",
    LangFrench "French",
    LangGerman "German",
    LangOther "Other"
) [
    description "Section 5. The content language is declared by the author rather than detected."
]

DataEnumeration LanguageVersionState "Language version state" values (
    VersionDraft "Draft: the only state in which grammar and services files may be created, changed, or removed",
    VersionActive "Active: the version in force; at most one version of a family may be active at a time",
    VersionDeprecated "Deprecated: a version that was in force and has been superseded"
) [
    description "Section 7. Every version is created as a draft. The only transition a user performs is publication, which moves a version from draft or from deprecated to active and is reserved to the platform administrator."
]

DataEnumeration GrammarValidationState "Grammar validation state" values (
    ValidationNeverRun "Never validated",
    ValidationCurrentSuccess "Validated, current, and free of errors",
    ValidationOutOfDate "Recorded validation no longer corresponds to the current grammar text",
    ValidationFailed "The validation found errors"
) [
    description "Section 7. The result is stored with a fingerprint of the text validated and is marked out of date the moment any file of the set changes, so that a stale approval can never satisfy publication. Only errors make a grammar invalid; warnings and hints are reported without blocking."
]

DataEnumeration ServicesBuildState "Custom services build state" values (
    BuildMissing "No build of the custom services exists",
    BuildSucceeded "A current, successful build exists",
    BuildFailed "The build failed and its diagnostics are reported beside the grammar diagnostics",
    BuildOutOfDate "The build no longer corresponds to the services files"
) [
    description "Section 7. Each change to the content of a services file rebuilds them into a single artefact; failures are reported as diagnostics rather than blocking the save, and only publication insists on a successful, current build."
]

DataEnumeration ServicesAuditAction "Services audit action" values (
    AuditFileCreated "A services file was created",
    AuditContentChanged "The content of a services file was changed",
    AuditFileDeleted "A services file was deleted"
) [
    description "Section 7. Every creation, change of content, and deletion of a services file is written to an audit trail that cannot subsequently be altered or removed, whereas merely enabling or disabling one leaves no trace there."
]

DataEnumeration CredentialArrangement "Engine credential arrangement" values (
    CredentialAccessKeyOnly "An access key alone, for a hosted service authenticated by a key",
    CredentialServiceAddressOnly "A service address alone, for a service the organisation hosts",
    CredentialKeyAndAddress "Both a key and an address, for a service that requires the two together"
) [
    description "Section 10. An engine carries a display label, the identifier passed to the provider, and one of three credential arrangements."
]

DataEnumeration EngineRole "Assignable engine role" values (
    RoleDefaultEngine "The default engine",
    RoleKnowledgeAnswering "Answering from the knowledge pool",
    RoleDiagramGeneration "Generating diagrams",
    RoleImageInterpretation "Interpreting images",
    RoleSpecExtraction "Extracting the specification from the conversation",
    RoleSpecDrafting "Drafting the language text",
    RoleSpecCompletenessCheck "Checking the draft for completeness",
    RoleSpecRepair "Repairing the draft",
    RoleSpecFinalisation "Finalising the answer"
) [
    description "Section 10. Nine roles are assignable, the last five being the phases of specification generation. A manager assigns to each role one engine from the organisation catalogue; an assignment naming anything else is cleared rather than stored. A newly created organisation begins with every role unassigned."
]

DataEnumeration InstructionBlockScope "Instruction block scope" values (
    BlockPlatform "The platform block, editable only by the administrator",
    BlockOrganisation "The organisation block, editable by the organisation manager"
) [
    description "Section 10. System instructions follow a two-block arrangement. Until an organisation saves a block of its own, its page presents the platform organisation-level text as the starting point, and reverting restores that same fallback."
]

DataEnumeration NotificationEvent "Notification event" values (
    NotifyOrgInvitationCreated "An organisation invitation is created, notifying the invited user",
    NotifyOrgInvitationAccepted "An organisation invitation is accepted, notifying every accepted organisation manager",
    NotifyOrgInvitationRejected "An organisation invitation is rejected, notifying the same managers",
    NotifyWsInvitationCreated "A workspace invitation is created, notifying the invited user",
    NotifyWsInvitationAccepted "A workspace invitation is accepted, notifying every accepted workspace manager",
    NotifyWsInvitationRejected "A workspace invitation is rejected, notifying the same managers"
) [
    description "Section 11. Six events produce a notification, and all six concern membership. No document, language, editor, or conversation event produces a notification."
]

DataEnumeration SessionWriteMode "Session write mode" values (
    SessionWritable "Writable",
    SessionReadOnly "Read-only"
) [
    description "Sections 8 and 9. A single flag states whether the session may write. It is true only for a workspace manager or a workspace document manager; every other role, and any user with no accepted role, receives a read-only session, and a launch from the public view is always read-only."
]

DataEnumeration KnowledgePoolEntryKind "Knowledge pool entry kind" values (
    PoolGroundingDocument "The text of a document marked as grounding knowledge",
    PoolAssembledGrammar "The assembled grammar of a language in force, as one entry",
    PoolValidationFiles "The validation files of a language, together as one entry",
    PoolExampleFiles "The example files of a language, together as one entry",
    PoolSpecificationFile "One enabled specification file of a language, as an entry of its own"
) [
    description "Section 7 and Section 9. Only versions in force of families that have not been withdrawn are projected into the pool; when a version ceases to be in force, or its family is withdrawn, its entries are removed."
]

DataEnumeration EditorCallbackRefusal "Editor callback refusal reason" values (
    CallbackMissingDescription "A missing or unusable session description",
    CallbackNoWorkspace "A description carrying no workspace",
    CallbackWorkspaceMismatch "A workspace that does not match the one requested",
    CallbackUnknownWorkspace "A workspace that does not exist",
    CallbackNoAccess "An absence of access to the workspace"
) [
    description "Section 8. When the editor calls back to the platform and the call is rejected, the platform answers with a stated reason; how those reasons are shown to the user is the editor affair."
]

DataEnumeration ExportRefusalReason "Export refusal reason" values (
    ExportMissingCredential "A missing credential",
    ExportUnusableCredential "An unusable or expired credential",
    ExportUnreadableRequest "A request the platform cannot read",
    ExportBadWorkspaceIdentifier "A missing or invalid workspace identifier",
    ExportMismatchedWorkspace "A mismatched workspace",
    ExportAbsentContent "Absent content",
    ExportContentTooLarge "Content above one megabyte",
    ExportBadFileName "A missing or invalid file name",
    ExportUnknownLanguage "An unknown or non-current language",
    ExportUnknownWorkspace "An unknown workspace",
    ExportUnknownUser "An unknown user",
    ExportNoWriteRights "An absence of write rights",
    ExportDisallowedExtension "A disallowed extension",
    ExportNoSharedSecret "No shared secret configured, which is a fault of the platform rather than of the request"
) [
    description "Section 9. A refused export is reported with the reason named rather than left to be guessed, and each of these is distinguished."
]

DataEnumeration DeliveryOutcome "Editor delivery outcome" values (
    DeliveryMade "The delivery was made and a live session received it",
    DeliveryNoLiveSession "The delivery was made but no live session received it",
    DeliveryNotConfigured "An integration that is not configured",
    DeliveryTimeout "A timeout",
    DeliveryEditorUnreachable "An unreachable editor",
    DeliveryCapabilityMissing "An editor lacking the delivery capability",
    DeliveryUnauthorised "A delivery rejected as unauthorised",
    DeliveryEditorError "Another error returned by the editor",
    DeliveryUninterpretable "An answer that could not be interpreted"
) [
    description "Section 9. The response always names the created document and carries, beside it, whether the delivery was made, whether a live session received it, and, when it was not made, a stated reason. When the editor supplies a reason of its own, that reason is passed on."
]

DataEnumeration GenerationRefusalReason "Generation refusal reason" values (
    GenVersionNotReady "The version is neither in force nor in preparation",
    GenNoGrammar "The version carries no grammar",
    GenGrammarNotValidated "The grammar has not been validated",
    GenValidationStale "The recorded validation no longer matches the grammar",
    GenPublishedMismatch "A version in force no longer matches the grammar recorded when it was published",
    GenServicesBuildUnusable "The version declares custom services whose build is missing, failed, or out of date",
    GenUnregisteredExtension "The uploaded specification does not carry an extension the target language registers",
    GenImportUnresolved "An import that matches nothing, reported with the importing file and the line",
    GenImportAmbiguous "An import that matches more than one candidate, reported with the contested declaration and the documents that declare it"
) [
    description "Section 6. Generation is refused outright when the target language is not ready for it, and import resolution failures are reported as errors."
]

/****************************************************
   Data Entities
*****************************************************/

/*--- Accounts (Sections 2 and 12) ---*/
DataEntity e_User "User Account" : Master [
    attribute userId : String(40) [ constraints(PrimaryKey NotNull Unique)
        description "Stable identifier of the account" ]
    attribute fullName "Name" : String(150) [ constraints(NotNull)
        description "The name asked for at registration" ]
    attribute emailAddress "Email address" : Email [ constraints(NotNull Unique)
        description "The address asked for at registration, matched against pending invitations" ]
    attribute passwordSecret "Password" : String(200) [ constraints(NotNull Encrypted NotVisible)
        description "The password asked for at registration" ]
    attribute profile "Platform profile" : DataEnumeration PlatformProfile [ constraints(NotNull)
        description "Exactly one platform profile per registered user; a new account receives the member profile automatically and the administrator profile is not granted automatically to anyone" ]
    attribute termsVersion "Accepted terms version" : String(40) [
        description "The version of the terms and conditions accepted at registration" ]
    attribute termsAcceptedOn "Terms accepted at" : Datetime [
        description "The moment of acceptance" ]
    attribute termsAcceptedFrom "Acceptance network address" : String(60) [
        description "The network address of the accepting request" ]
    attribute termsAcceptedAgent "Acceptance browser identification" : String(400) [
        description "The browser identification of the accepting request" ]
    description "Section 2. Registration asks for a name, an email address, a password, and explicit acceptance of the terms and conditions, recorded against the account. No organisation is created during registration."
]

/*--- Organisations (Section 3) ---*/
DataEntity e_Organisation "Organisation" : Master [
    attribute organisationId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute organisationName "Name" : String(200) [ constraints(NotNull)
        description "Changeable from the settings page reserved to organisation managers" ]
    attribute activityType "Activity type" : DataEnumeration OrganisationActivityType [ constraints(NotNull)
        description "Chosen from information technology, marketing, consulting, finance, education, and other" ]
    attribute country : String(100) [
        description "Optional, and one of the three attributes changeable from the portal" ]
    attribute summaryText "Description" : Text [
        description "Not changeable from the portal settings page" ]
    attribute logo : Image [
        description "Not changeable from the portal settings page" ]
    attribute lifecycleState "State" : DataEnumeration OrganisationState [ constraints(NotNull)
        description "Active or suspended; suspension and reactivation are administrative acts" ]
    description "Section 3. An organisation is created from the portal by any authenticated user, who becomes its organisation manager with the accepted status at the moment of creation. Only the name, the activity type, and the country may be changed from the portal."
]

DataEntity e_OrganisationRole "Organisation Role Assignment" : Transaction [
    attribute organisationRoleId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute organisationRef : String(40) [ constraints(NotNull ForeignKey(e_Organisation onDelete CASCADE)) ]
    attribute holder "User" : String(40) [ constraints(NotNull ForeignKey(e_User onDelete CASCADE)) ]
    attribute roleKind "Role" : DataEnumeration OrganisationRoleType [ constraints(NotNull) ]
    attribute assignmentStatus "Status" : DataEnumeration RoleState [ constraints(NotNull)
        description "Only accepted assignments grant anything or make the organisation visible to the holder" ]
    attribute answeredOn "Responded at" : Datetime [
        description "Stamped when the invited user accepts or rejects" ]
    constraints( Check(ck_OneRolePerOrganisation "A user holds at most one role per organisation") )
    description "Section 2 and Section 3. Membership grows only by invitation; there is no way for a user to request admission."
]

DataEntity e_OrganisationInvitation "Organisation Invitation" : Transaction [
    attribute organisationInvitationId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute organisationRef : String(40) [ constraints(NotNull ForeignKey(e_Organisation onDelete CASCADE)) ]
    attribute invitedAddress "Email address" : Email [ constraints(NotNull) ]
    attribute offeredRole "Role" : DataEnumeration OrganisationRoleType [ constraints(NotNull) ]
    attribute issuedOn "Created at" : Datetime [ constraints(NotNull) ]
    constraints( Check(ck_InvitationNotDuplicated "Inviting the same address again resends the message rather than duplicating the record") )
    description "Section 3. When the address belongs to an existing account a pending role assignment is created instead; when it does not, the platform records this invitation, sends a message inviting the recipient to create an account, and honours it automatically at registration, producing an accepted role with no acceptance step."
]

/*--- Workspaces (Section 4) ---*/
DataEntity e_Workspace "Workspace" : Master [
    attribute workspaceId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute workspaceKey "Stable key" : String(60) [ constraints(NotNull Unique)
        description "A stable key of its own, distinct from its name, by which other parts of the system identify the workspace" ]
    attribute workspaceName "Name" : String(200) [ constraints(NotNull)
        description "Asked for in the first step of creation" ]
    attribute organisationRef "Owning organisation" : String(40) [ constraints(ForeignKey(e_Organisation onDelete SET_NULL))
        description "A workspace references at most one organisation and the reference is optional, so deleting an organisation does not destroy its workspaces" ]
    attribute isPublic "Public" : Boolean [ constraints(NotNull)
        description "Asked for in the first step of creation; a setting of the workspace itself rather than of its organisation, so one organisation may hold open and closed work side by side" ]
    attribute plannedStart "Planned start date" : Date
    attribute plannedEnd "Planned end date" : Date
    attribute actualStart "Actual start date" : Date [
        description "Recorded when the workspace is started" ]
    attribute actualEnd "Actual end date" : Date [
        description "Recorded when the workspace is concluded" ]
    attribute summaryText "Description" : Text [
        description "Asked for in the third step of creation" ]
    attribute progressState "Progress" : DataEnumeration WorkspaceProgressState [ constraints(NotNull)
        description "Independent of any document lifecycle; only a workspace manager may change it, and it is a statement about the work rather than an access control" ]
    description "Section 4. A workspace is created through a guided sequence of four steps: identity, dates, description, and review. Any user holding an accepted role of any kind in an organisation may create a workspace in it, and the creator receives the workspace manager role with the accepted status."
]

DataEntity e_WorkspaceRole "Workspace Role Assignment" : Transaction [
    attribute workspaceRoleId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute workspaceRef : String(40) [ constraints(NotNull ForeignKey(e_Workspace onDelete CASCADE)) ]
    attribute holder "User" : String(40) [ constraints(NotNull ForeignKey(e_User onDelete CASCADE)) ]
    attribute roleKind "Role" : DataEnumeration WorkspaceRoleType [ constraints(NotNull) ]
    attribute assignmentStatus "Status" : DataEnumeration RoleState [ constraints(NotNull) ]
    attribute answeredOn "Responded at" : Datetime
    constraints( Check(ck_OneRolePerWorkspace "A user holds at most one role per workspace") )
    description "Section 2 and Section 4. A user whose organisation manager role becomes accepted receives an accepted workspace manager role on every workspace the organisation holds at that moment; the rule is not applied again afterwards. A user who accepts a workspace role and has no role at all in the workspace organisation receives an accepted organisation member role there."
]

DataEntity e_WorkspaceInvitation "Workspace Invitation" : Transaction [
    attribute workspaceInvitationId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute workspaceRef : String(40) [ constraints(NotNull ForeignKey(e_Workspace onDelete CASCADE)) ]
    attribute invitedAddress "Email address" : Email [ constraints(NotNull) ]
    attribute offeredRole "Role" : DataEnumeration WorkspaceRoleType [ constraints(NotNull) ]
    attribute issuedOn "Created at" : Datetime [ constraints(NotNull) ]
    description "Section 4. Membership works as it does for organisations, with invitations by email address and role and automatic acceptance for addresses that had no account."
]

/*--- Documents (Sections 5 and 6) ---*/
DataEntity e_DocumentType "Document Type" : Reference [
    attribute documentTypeId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute typeValue "Type" : DataEnumeration DocumentTypeValue [ constraints(NotNull Unique) ]
    attribute isTreatedSpecially "Treated specially" : Boolean [ constraints(NotNull)
        description "True only for template, which is the only type the platform treats differently" ]
    description "Section 5. Eight document types are available; most of them classify and filter without altering what the document page does."
]

DataEntity e_Document "Document" : Document [
    attribute documentId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute documentName "Name" : String(250) [ constraints(NotNull)
        description "The only attribute the platform requires" ]
    attribute documentTypeRef "Type" : String(40) [ constraints(NotNull ForeignKey(e_DocumentType onDelete PROTECT)) ]
    attribute versionLabel "Version label" : String(40) [ constraints(NotNull)
        description "Free text with an initial value of 1.0, which the author maintains by hand" ]
    attribute contentLanguage "Content language" : DataEnumeration ContentLanguage [
        description "Optional and declared by the author rather than detected" ]
    attribute languageFamilyRef "Specification language family" : String(40) [ constraints(ForeignKey(e_LanguageFamily onDelete SET_NULL))
        description "Optional; naming a version without its family is refused" ]
    attribute languageVersionRef "Specification language version" : String(40) [ constraints(ForeignKey(e_LanguageVersion onDelete SET_NULL))
        description "Optional; a version belonging to a different family is refused" ]
    attribute attachedFile "File" : File [
        description "One attached file; editing a document replaces the stored file in place and the platform keeps no prior copy" ]
    attribute fileSize "File size" : Integer [
        description "Recorded with the document" ]
    attribute formatGroup "Format group" : DataEnumeration DocumentFormatGroup [
        description "Derived from the file name; an extension registered by a specification language counts as text" ]
    attribute documentState "State" : DataEnumeration DocumentState [ constraints(NotNull)
        description "Draft is the initial value; the state governs visibility rather than enforcing a workflow" ]
    attribute isGroundingKnowledge "Grounding knowledge" : Boolean [ constraints(NotNull)
        description "May be set only while the document is published and its file is textual, and is lost automatically when the document leaves the published state" ]
    attribute ownerWorkspaceRef "Owning workspace" : String(40) [ constraints(ForeignKey(e_Workspace onDelete CASCADE)) ]
    attribute ownerOrganisationRef "Owning organisation" : String(40) [ constraints(ForeignKey(e_Organisation onDelete CASCADE)) ]
    attribute createdBy "Creator" : String(40) [ constraints(NotNull ForeignKey(e_User onDelete PROTECT)) ]
    attribute createdOn "Creation date" : Datetime [ constraints(NotNull) ]
    constraints(
        Check(ck_SingleOwner "A document belongs either to a workspace or to an organisation, and the platform refuses to let it belong to both")
        Check(ck_GroundingRequiresPublished "The grounding knowledge mark may be applied only while the document is in the published state and only when its file is textual")
        Check(ck_LanguageVersionWithinFamily "Naming a version without its family, or a version belonging to a different family, is refused")
    )
    description "Section 5. A document carries a name, a type, a version label, an optional content language, an optional association with a specification language, and one attached file. Deletion is permanent and is not an archive; archiving is the separate lifecycle state."
]

DataEntity e_Template "Template Document" : Document [
    isA e_Document
    attribute templateFamilyRef "Applicable language family" : String(40) [ constraints(NotNull ForeignKey(e_LanguageFamily onDelete PROTECT))
        description "A template must name the specification language family it applies to" ]
    attribute fileNamePattern "Generated file name pattern" : String(250) [
        description "Optional pattern from which the name of the generated file is composed, discarded by the portal when the document type ceases to be template" ]
    attribute outputSections "Named output sections" : Text [
        description "A text template may declare several named output sections, in which case the run produces each of them and delivers the set as a single archive" ]
    constraints(
        Check(ck_TemplateRenderable "The file must be one the platform can render: a word-processor document, a spreadsheet, or any file whose contents are readable as text")
        Check(ck_TemplateNeverGrounding "A template may never be marked as grounding knowledge and is excluded from the documents the editor offers to import")
    )
    description "Section 6. A template is an ordinary document whose type is template, distinguished by three conditions."
]

DataEntity e_DocumentChangeEntry "Document Change History Entry" : Transaction [
    attribute changeEntryId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute documentRef : String(40) [ constraints(NotNull ForeignKey(e_Document onDelete CASCADE)) ]
    attribute changedAttribute "Changed attribute" : String(60) [ constraints(NotNull)
        description "One of name, state, version, type, and language associations" ]
    attribute changedOn : Datetime [ constraints(NotNull) ]
    attribute changedBy : String(40) [ constraints(ForeignKey(e_User onDelete SET_NULL)) ]
    description "Section 5. The change history records which of the tracked attributes changed, but not the content that was replaced and not the replacement of the file itself, so a file exchanged without any other edit leaves no entry at all."
]

DataEntity e_GenerationRun "Document Generation Run" : Transaction [
    attribute generationRunId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute templateRef : String(40) [ constraints(NotNull ForeignKey(e_Template onDelete CASCADE)) ]
    attribute uploadedSpecification "Uploaded specification" : File [ constraints(NotNull)
        description "Must carry an extension the target language registers" ]
    attribute targetVersionRef "Language version used" : String(40) [ constraints(ForeignKey(e_LanguageVersion onDelete PROTECT))
        description "The version currently in force for the template family, unless a maintainer of that family or an administrator directs the run at a particular version, including one still in draft" ]
    attribute refusalReason "Refusal reason" : DataEnumeration GenerationRefusalReason
    attribute isResultStored "Result stored" : Boolean [ constraints(NotNull)
        description "Always false: the produced file is returned directly to the browser, no document is created, and nothing is retained" ]
    description "Section 6. Generation is offered to anyone who may read the template, which is deliberately wider than the right to create or edit it. Rendering is lenient by design: a value the template asks for and the specification does not supply renders as blank rather than aborting the run."
]

DataEntity e_TemplateReference "Template Reference" : Reference [
    attribute templateReferenceId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute languageFamilyRef : String(40) [ constraints(NotNull ForeignKey(e_LanguageFamily onDelete CASCADE)) ]
    attribute entryTypeName "Entry type" : String(120) [
        description "The entry type of the language" ]
    attribute typeInventory "Types and fields" : Text [
        description "Every type with its fields, and for each field whether it holds a value, a reference, or a nested element, whether it is a list, and whether it is optional" ]
    attribute iterableTypes "Iterable types" : Text [
        description "The types a template may iterate over, distinguished from those that only ever occur inside another" ]
    attribute starterTemplate "Starter template" : File [
        description "A downloadable starter template offered alongside a ready-to-copy snippet for each type" ]
    attribute isFallbackDocumentation "Generic fallback" : Boolean [
        description "True when the description of the grammar cannot be produced, in which case generic documentation is presented rather than an empty inventory" ]
    description "Section 6. The template reference documents, per language, exactly what a template may address, and is reachable without signing in for every language the visitor may see."
]

DataEntity e_TemplateAdvisoryCheck "Template Advisory Check" : Transaction [
    attribute advisoryCheckId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute checkedFragment "Checked fragment" : Text [
        description "A pasted fragment or a stored template; the check never stores what it was given" ]
    attribute reportedFindings "Findings" : Text [
        description "Syntax errors with their positions, unknown names with the closest matching suggestion, lookups keyed on a type the language does not define, and probable field misspellings" ]
    attribute isBlocking "Blocking" : Boolean [ constraints(NotNull)
        description "Always false: the check never blocks generation" ]
    description "Section 6. An advisory check analyses a fragment or a stored template against the language inventory, compensating for the fact that lenient rendering makes a misspelled field name indistinguishable from an absent value."
]

/*--- Specification languages (Section 7) ---*/
DataEntity e_LanguageFamily "Language Family" : Master [
    attribute languageFamilyId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute familyName "Full name" : String(200) [ constraints(NotNull)
        description "Only an administrator may change the name" ]
    attribute acronymText "Acronym" : String(40) [ constraints(NotNull Unique)
        description "Unique across the platform without regard to case; only an administrator may change it" ]
    attribute isWithdrawn "Withdrawn" : Boolean [ constraints(NotNull)
        description "Withdrawing a language is done at the level of the family, which hides all of its versions at once" ]
    description "Section 7. Specification languages are platform-level entities: they are not owned by an organisation or a workspace, they are registered once, and everything else refers to them. A family carries the identity of the language."
]

DataEntity e_LanguageMaintainer "Language Maintainership" : Transaction [
    attribute maintainershipId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute languageFamilyRef : String(40) [ constraints(NotNull ForeignKey(e_LanguageFamily onDelete CASCADE)) ]
    attribute maintainerRef "Maintainer" : String(40) [ constraints(NotNull ForeignKey(e_User onDelete CASCADE)) ]
    description "Section 7. Maintainers are named on the family and are shared by all of its versions. Their assignment and removal are reserved to the platform administrator."
]

DataEntity e_LanguageVersion "Language Version" : Master [
    attribute languageVersionId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute languageFamilyRef : String(40) [ constraints(NotNull ForeignKey(e_LanguageFamily onDelete CASCADE))
        description "A version belongs to exactly one family" ]
    attribute versionLabel "Version label" : String(40) [ constraints(NotNull) ]
    attribute summaryText "Description" : Text
    attribute fileExtensions "File extensions" : String(200) [
        description "The extensions specifications in that version use" ]
    attribute documentationRef "Documentation" : URL
    attribute externalParserRef "External parser" : URL
    attribute versionState "State" : DataEnumeration LanguageVersionState [ constraints(NotNull ReadOnly)
        description "Every version is created as a draft; there is no way to set the state directly, and attempting to write it outside publication is refused with an explicit message" ]
    attribute validationState "Grammar validation" : DataEnumeration GrammarValidationState [ constraints(NotNull) ]
    attribute buildState "Services build" : DataEnumeration ServicesBuildState [ constraints(NotNull) ]
    attribute publishedBy "Publisher" : String(40) [ constraints(ForeignKey(e_User onDelete SET_NULL))
        description "The identity of the publisher is recorded" ]
    attribute publishedOn "Published at" : Datetime
    attribute publishedFingerprint "Published fingerprint" : String(120) [
        description "A fingerprint of what was published" ]
    constraints(
        Check(ck_OneActiveVersionPerFamily "At most one version of a family may be active at a time; publication deprecates the version of the same family that was active")
        Check(ck_PublicationRequiresValidation "Publication is refused for a version whose grammar was never validated, whose recorded validation no longer corresponds to the current grammar text, or whose validation found errors")
        Check(ck_PublicationRequiresBuild "A version that carries custom services must additionally have a current, successful build of those services")
    )
    description "Section 7. A version carries the particulars of one release. The platform re-runs the validation itself at publication time rather than trusting anything the browser reports."
]

DataEntity e_GrammarFile "Grammar File" : Document [
    attribute grammarFileId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute languageVersionRef : String(40) [ constraints(NotNull ForeignKey(e_LanguageVersion onDelete CASCADE)) ]
    attribute relativePath "Path" : FilePath [ constraints(NotNull)
        description "Files are constrained to plain relative paths and must carry the extension appropriate to their kind" ]
    attribute isEntryFile "Entry file" : Boolean [ constraints(NotNull)
        description "Exactly one file of the grammar set is the entry file" ]
    attribute isEnabled "Enabled" : Boolean [ constraints(NotNull)
        description "Enabling or disabling a file neither rebuilds the artefact nor leaves an audit trace" ]
    attribute contentText "Content" : Text [ constraints(NotNull)
        description "Must be valid text and is bounded in size" ]
    constraints( Check(ck_GrammarEditableInDraftOnly "A request to alter a grammar file of a version that is not in draft is refused even when it is made directly") )
    description "Section 7. A version grammar is a set of files that may import one another, edited in the browser. Validation first assembles the grammar by inlining the imports, rejecting import cycles, imports that resolve to nothing, and imports that leave the file set, and then checks the assembled text."
]

DataEntity e_ServicesFile "Custom Services File" : Document [
    attribute servicesFileId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute languageVersionRef : String(40) [ constraints(NotNull ForeignKey(e_LanguageVersion onDelete CASCADE)) ]
    attribute relativePath "Path" : FilePath [ constraints(NotNull) ]
    attribute isEntryFile "Entry file" : Boolean [ constraints(NotNull)
        description "Exactly one file of the services set is the entry file" ]
    attribute isEnabled "Enabled" : Boolean [ constraints(NotNull) ]
    attribute contentText "Content" : Text [ constraints(NotNull) ]
    constraints( Check(ck_ServicesEditableInDraftOnly "Services files may be created, changed, or removed only while the version is in draft") )
    description "Section 7. Custom language services let a version carry behaviour a grammar cannot express, such as how names are computed, how references are resolved across files, and what additional rules a specification must satisfy."
]

DataEntity e_ServicesAuditEntry "Services Audit Entry" : Transaction [
    attribute servicesAuditEntryId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute servicesFileRef : String(40) [ constraints(NotNull ForeignKey(e_ServicesFile onDelete PROTECT)) ]
    attribute auditAction "Action" : DataEnumeration ServicesAuditAction [ constraints(NotNull) ]
    attribute performedBy : String(40) [ constraints(ForeignKey(e_User onDelete PROTECT)) ]
    attribute performedOn : Datetime [ constraints(NotNull) ]
    constraints( ReadOnly Check(ck_AuditImmutable "The audit trail cannot subsequently be altered or removed") )
    description "Section 7. Every creation, change of content, and deletion of a services file is written to an immutable audit trail; merely enabling or disabling one leaves no trace there."
]

DataEntity e_GrammarValidationResult "Grammar Validation Result" : Transaction [
    attribute validationResultId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute languageVersionRef : String(40) [ constraints(NotNull ForeignKey(e_LanguageVersion onDelete CASCADE)) ]
    attribute validatedFingerprint "Fingerprint of the text validated" : String(120) [ constraints(NotNull) ]
    attribute errorCount "Errors" : Integer [ constraints(NotNull)
        description "Only errors make a grammar invalid" ]
    attribute warningCount "Warnings" : Integer [
        description "Warnings are reported without blocking" ]
    attribute hintCount "Hints" : Integer [
        description "Hints are reported without blocking" ]
    attribute validatedOn : Datetime [ constraints(NotNull) ]
    attribute isCurrent "Current" : Boolean [ constraints(NotNull)
        description "Marked out of date the moment any file of the set changes, so that a stale approval can never satisfy publication" ]
    description "Section 7. The result of assembling and checking the grammar, stored with a fingerprint of the text validated."
]

DataEntity e_LanguageSelection "Language Availability Selection" : Parameter [
    attribute languageSelectionId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute organisationRef : String(40) [ constraints(ForeignKey(e_Organisation onDelete CASCADE)) ]
    attribute workspaceRef : String(40) [ constraints(ForeignKey(e_Workspace onDelete CASCADE)) ]
    attribute languageFamilyRef : String(40) [ constraints(NotNull ForeignKey(e_LanguageFamily onDelete CASCADE)) ]
    attribute isWorkspaceDefault "Default for the workspace" : Boolean
    constraints(
        Check(ck_WorkspaceSelectionWithinOrganisation "The platform refuses a workspace selection that falls outside the organisation selection")
        Check(ck_DefaultWithinAvailable "The platform refuses a default that is not among the workspace available languages")
    )
    description "Section 7. Organisations and workspaces may narrow the choice of languages: an organisation declares which languages are available to it, and a workspace narrows that set further and nominates a default."
]

DataEntity e_KnowledgePoolEntry "Knowledge Pool Entry" : Reference [
    attribute knowledgePoolEntryId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute entryKind "Kind" : DataEnumeration KnowledgePoolEntryKind [ constraints(NotNull) ]
    attribute sourceDocumentRef "Source document" : String(40) [ constraints(ForeignKey(e_Document onDelete CASCADE)) ]
    attribute sourceVersionRef "Source language version" : String(40) [ constraints(ForeignKey(e_LanguageVersion onDelete CASCADE)) ]
    attribute scopeOrganisationRef "Scope organisation" : String(40) [ constraints(ForeignKey(e_Organisation onDelete CASCADE)) ]
    attribute scopeWorkspaceRef "Scope workspace" : String(40) [ constraints(ForeignKey(e_Workspace onDelete CASCADE)) ]
    description "Sections 5, 7, and 9. The pool the chatbot consults: the text of documents marked as grounding knowledge, scoped to their owner, and the grammars, validation files, examples, and specification files of the languages currently in force. Entries are removed when a document leaves the published state, when a version ceases to be in force, or when a family is withdrawn."
]

/*--- Editor and chatbot sessions (Sections 8 and 9) ---*/
DataEntity e_EditorSession "Editor Session Description" : Transaction [
    attribute editorSessionId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute subjectUserRef "User" : String(40) [ constraints(NotNull ForeignKey(e_User onDelete CASCADE)) ]
    attribute workspaceRef : String(40) [ constraints(NotNull ForeignKey(e_Workspace onDelete CASCADE)) ]
    attribute workspaceLabel "Workspace name" : String(200) [ constraints(NotNull) ]
    attribute organisationLabel "Owning organisation name" : String(200)
    attribute writeMode "Write mode" : DataEnumeration SessionWriteMode [ constraints(NotNull)
        description "True only for a workspace manager or a workspace document manager; a launch from the public view of a public workspace is always read-only, whoever performs it" ]
    attribute isEncrypted_ "Encrypted" : Boolean [ constraints(NotNull)
        description "The description is encrypted under a secret the platform shares with the editor" ]
    description "Section 8. What the platform hands over is a short description of the session: the identity of the user, the name and identifier of the workspace, the name of the owning organisation, and a single flag stating whether the session may write."
]

DataEntity e_ChatSession "Chat Session Statement" : Transaction [
    attribute chatSessionId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute workspaceRef : String(40) [ constraints(NotNull ForeignKey(e_Workspace onDelete CASCADE)) ]
    attribute workspaceKey "Stable key" : String(60) [ constraints(NotNull) ]
    attribute subjectUserRef "User" : String(40) [ constraints(ForeignKey(e_User onDelete CASCADE)) ]
    attribute organisationRef "Owning organisation" : String(40) [ constraints(ForeignKey(e_Organisation onDelete CASCADE)) ]
    attribute writeMode "Write mode" : DataEnumeration SessionWriteMode [ constraints(NotNull)
        description "Marked read-only unless the user holds an accepted workspace manager or document manager role" ]
    attribute issuedOn : Datetime [ constraints(NotNull) ]
    attribute validForMinutes "Validity in minutes" : Integer [ constraints(NotNull)
        description "The statement is valid for one hour" ]
    description "Section 9. The session is passed when the page is rendered and is the credential the chatbot presents when it asks the platform to create a document. If no shared secret has been configured, the page renders without any session statement."
]

DataEntity e_ExportRequest "Specification Export Request" : Transaction [
    attribute exportRequestId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute chatSessionRef "Presented credential" : String(40) [ constraints(ForeignKey(e_ChatSession onDelete PROTECT)) ]
    attribute targetWorkspaceRef "Workspace named" : String(40) [ constraints(ForeignKey(e_Workspace onDelete PROTECT)) ]
    attribute contentText "Content" : Text [
        description "Refused above one megabyte and refused when absent" ]
    attribute proposedFileName "Proposed file name" : String(250)
    attribute namedLanguageRef "Named language" : String(40) [ constraints(ForeignKey(e_LanguageVersion onDelete PROTECT))
        description "Optional; a language that is not currently in force is refused, and when a language is named the file receives that language registered extension whatever the conversation proposed" ]
    description "Section 9. The chatbot asks the platform to create a document in the workspace, presenting the session statement as its credential. The platform verifies the statement, checks that the workspace named matches the one the statement was issued for, and then re-derives the user write permission from their current workspace role rather than relying on the read-only flag the statement carries."
]

DataEntity e_ExportResult "Specification Export Result" : Transaction [
    attribute exportResultId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute exportRequestRef : String(40) [ constraints(NotNull ForeignKey(e_ExportRequest onDelete CASCADE)) ]
    attribute createdDocumentRef "Created document" : String(40) [ constraints(ForeignKey(e_Document onDelete SET_NULL))
        description "An accepted request creates an ordinary workspace document in the draft state, attributed to the user as its creator, with its file name made unique against the existing documents by appending a counter" ]
    attribute refusalReason "Refusal reason" : DataEnumeration ExportRefusalReason
    attribute deliveryOutcome "Delivery outcome" : DataEnumeration DeliveryOutcome [
        description "Reported separately from the creation of the document" ]
    constraints( Check(ck_DocumentSurvivesDelivery "The document is the system of record and survives a failed delivery; the two operations are deliberately not tied together") )
    description "Section 9. The response always names the created document and carries, beside it, whether the delivery was made, whether a live session received it, and, when it was not made, a stated reason."
]

/*--- Assistance configuration (Section 10) ---*/
DataEntity e_Provider "Assistance Provider" : Master [
    attribute providerId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute providerName "Name" : String(150) [ constraints(NotNull) ]
    attribute organisationRef "Owning organisation" : String(40) [ constraints(ForeignKey(e_Organisation onDelete CASCADE))
        description "Empty for the platform-wide catalogue the administrator maintains; the entries an organisation registers are its own" ]
    description "Section 10. A catalogue is a set of providers, each grouping one or more engines. A provider is a named family of services, whether a commercial service or one the organisation hosts itself."
]

DataEntity e_Engine "Assistance Engine" : Master [
    attribute engineId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute providerRef : String(40) [ constraints(NotNull ForeignKey(e_Provider onDelete CASCADE)) ]
    attribute displayLabel "Label" : String(150) [ constraints(NotNull) ]
    attribute providerIdentifier "Identifier passed to the provider" : String(200) [ constraints(NotNull) ]
    attribute arrangement "Credential arrangement" : DataEnumeration CredentialArrangement [ constraints(NotNull) ]
    attribute accessKeyName "Access key name" : String(250) [ constraints(NotVisible)
        description "Credentials are held under names the platform composes from the organisation, the provider, and the engine, so two organisations configuring the same provider can never collide" ]
    attribute serviceAddress "Service address" : URL
    constraints(
        Check(ck_CredentialsClearedOnArrangementChange "Changing an engine arrangement clears the credentials belonging to the arrangement abandoned, so a stale key cannot linger behind an engine that no longer uses it")
        Check(ck_EmptyKeyKeepsStored "Editing an engine with the key field left empty keeps the key already stored, so a manager may change a label or an identifier without re-entering, or ever redisplaying, the secret")
    )
    description "Section 10. Credentials are handled in three ways that favour safety over convenience, and the values themselves are held in the platform own storage without further encryption."
]

DataEntity e_EngineRoleAssignment "Engine Role Assignment" : Parameter [
    attribute engineRoleAssignmentId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute organisationRef : String(40) [ constraints(ForeignKey(e_Organisation onDelete CASCADE))
        description "Empty for the platform default assignment the administrator maintains" ]
    attribute assignedRole "Role" : DataEnumeration EngineRole [ constraints(NotNull) ]
    attribute engineRef "Engine" : String(40) [ constraints(ForeignKey(e_Engine onDelete SET_NULL)) ]
    constraints( Check(ck_AssignmentWithinOwnCatalogue "A selection is only ever validated against the organisation own catalogue, never against another organisation or the platform; an assignment naming anything else is cleared rather than stored") )
    description "Section 10. Engine roles decide what each registered engine is used for. A newly created organisation begins with every role unassigned, and nothing on the platform requires them to be filled before conversation is possible."
]

DataEntity e_InstructionBlock "System Instruction Block" : Parameter [
    attribute instructionBlockId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute blockScope "Scope" : DataEnumeration InstructionBlockScope [ constraints(NotNull) ]
    attribute organisationRef : String(40) [ constraints(ForeignKey(e_Organisation onDelete CASCADE)) ]
    attribute blockText "Text" : Text
    description "Section 10. The platform block is editable only by the administrator and precedes every organisation own block. The organisation block is editable by the organisation manager, and a revert action discards the organisation text entirely, restoring the platform organisation-level text as the fallback."
]

/*--- Notifications and activity (Section 11) ---*/
DataEntity e_Notification "Notification" : Transaction [
    attribute notificationId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute recipientRef "Recipient" : String(40) [ constraints(NotNull ForeignKey(e_User onDelete CASCADE)) ]
    attribute eventKind "Event" : DataEnumeration NotificationEvent [ constraints(NotNull) ]
    attribute isRead "Read" : Boolean [ constraints(NotNull) ]
    attribute raisedOn : Datetime [ constraints(NotNull) ]
    attribute relatedOrganisationRef : String(40) [ constraints(ForeignKey(e_Organisation onDelete CASCADE)) ]
    attribute relatedWorkspaceRef : String(40) [ constraints(ForeignKey(e_Workspace onDelete CASCADE)) ]
    attribute isEmailQueued "Email queued" : Boolean [
        description "Email accompanies only the two events that create an invitation, and only when the invited user has an email address on record; the message is queued rather than sent at once" ]
    constraints( Check(ck_OwnNotificationsOnly "Every action is restricted to the notifications of the user performing it, and a user sees only their own notifications; the administrator sees all of them") )
    description "Section 11. Users read their notifications in a bell in the site header, which shows the number of unread notifications and the ten most recent of them, and in a full list page with paging."
]

DataEntity e_ActivityMessage "Activity Message" : Transaction [
    attribute activityMessageId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute organisationRef : String(40) [ constraints(ForeignKey(e_Organisation onDelete CASCADE)) ]
    attribute workspaceRef : String(40) [ constraints(ForeignKey(e_Workspace onDelete CASCADE)) ]
    attribute messageText "Message" : Text [ constraints(NotNull) ]
    attribute postedOn : Datetime [ constraints(NotNull) ]
    attribute postedBy : String(40) [ constraints(ForeignKey(e_User onDelete SET_NULL)) ]
    description "Section 11. Beyond notifications the platform keeps an activity record: organisations, workspaces, and documents each carry a history of the changes made to their tracked attributes, and accepting or rejecting an invitation posts a corresponding message on the organisation or workspace concerned. Creating an invitation also schedules a task for the invited user."
]

/*--- Platform administration (Section 12) ---*/
DataEntity e_EditorIntegrationSetting "Editor Integration Setting" : Parameter [
    attribute integrationSettingId : String(40) [ constraints(PrimaryKey NotNull Unique) ]
    attribute editorAddress "Editor address" : URL [
        description "The address at which the editor is reached" ]
    attribute sharedSecret "Shared secret" : String(250) [ constraints(Encrypted NotVisible)
        description "The secret shared with the editor; when none is configured an export fails as a fault of the platform and the chat page renders without a session statement" ]
    attribute credentialLifetime "Access credential lifetime" : Integer [
        description "The lifetime of the separately issued access credentials" ]
    attribute genericExtensions "General-purpose file extensions" : String(400) [
        description "The extensions the platform admits for import in addition to those the registered languages contribute" ]
    constraints( Check(ck_LanguageExtensionsAutomatic "The extensions of every language version in force or in preparation are admitted automatically and are not listed here, a draft under its distinguishing suffix; a superseded version contributes its extension as well, but only for as long as its family holds no version in force and none in preparation") )
    description "Section 12. The setting is consequential beyond administration, because the admitted extensions determine which documents the editor is offered and which files a conversation may deposit in a workspace."
]

/****************************************************
   Data Entity Clusters
*****************************************************/
DataEntityCluster ec_Organisation "Organisation Cluster" : Master [
    main e_Organisation
    child e_OrganisationRole [uses e_User]
    child e_OrganisationInvitation
    uses e_User
    description "Section 3. The organisation, its role assignments, and the invitations recorded for addresses that hold no account."
]

DataEntityCluster ec_Workspace "Workspace Cluster" : Master [
    main e_Workspace
    child e_WorkspaceRole [uses e_User]
    child e_WorkspaceInvitation
    uses e_Organisation, e_User
    description "Section 4. The workspace, its role assignments, and its invitations. A workspace references at most one organisation and the reference is optional."
]

DataEntityCluster ec_Document "Document Cluster" : Document [
    main e_Document
    child e_Template
    child e_DocumentChangeEntry
    child e_GenerationRun
    uses e_Workspace, e_Organisation, e_DocumentType, e_LanguageFamily, e_LanguageVersion, e_User
    description "Sections 5 and 6. The document, its change history, the template specialisation, and the generation runs it feeds."
]

DataEntityCluster ec_Language "Specification Language Cluster" : Master [
    main e_LanguageFamily
    child e_LanguageVersion
    child e_LanguageMaintainer [uses e_User]
    child e_GrammarFile
    child e_ServicesFile
    child e_ServicesAuditEntry
    child e_GrammarValidationResult
    child e_TemplateReference
    uses e_User
    description "Section 7. The two-layer registry: the family that carries the identity of the language and the versions that carry the particulars of each release, with their files, validations, and audit trail."
]

DataEntityCluster ec_Assistance "Assistance Configuration Cluster" : Master [
    main e_Provider
    child e_Engine
    child e_EngineRoleAssignment
    child e_InstructionBlock
    uses e_Organisation
    description "Section 10. The per-organisation catalogue of providers and engines, the nine engine role assignments, and the two-block system instructions."
]

DataEntityCluster ec_Interaction "Editor and Conversation Cluster" : Transaction [
    main e_ChatSession
    child e_ExportRequest
    child e_ExportResult
    child e_EditorSession
    child e_KnowledgePoolEntry
    uses e_Workspace, e_User, e_Document
    description "Sections 8 and 9. The session statements the platform hands to the editor and the chatbot, the knowledge pool the chatbot consults, and the export of a generated specification into a workspace."
]

DataEntityCluster ec_Notification "Notification and Activity Cluster" : Transaction [
    main e_Notification
    child e_ActivityMessage
    uses e_User, e_Organisation, e_Workspace
    description "Section 11. The six membership notifications and the activity record kept beside them."
]

DataEntityCluster ec_Administration "Platform Administration Cluster" : Parameter [
    main e_EditorIntegrationSetting
    child e_DocumentType
    child e_LanguageSelection
    uses e_Organisation, e_Workspace, e_LanguageFamily
    description "Section 12. The platform-level settings the administrator maintains, together with the reference data they govern."
]

/****************************************************
   Security: secrets and authentication (Sections 8, 9, 10 and 12)
*****************************************************/

SecSecret sec_EditorSharedSecret "Editor shared secret" : Credential [
    provider "Platform administration"
    locator "editor integration setting"
    description "Section 8 and Section 12. The secret shared with the editor, under which the session description is encrypted. When none is configured an export fails as a fault of the platform and the chat page renders without any session statement."
]

SecSecret sec_EngineAccessKey "Engine access key" : ApiKey [
    provider "Organisation assistance catalogue"
    locator "organisation, provider, and engine"
    description "Section 10. Credentials are held under names the platform composes from the organisation, the provider, and the engine, so two organisations configuring the same provider can never collide. The values themselves are held in the platform own storage without further encryption."
]

SecSecret sec_EngineServiceAddress "Engine service address" : ConnectionString [
    provider "Organisation assistance catalogue"
    locator "organisation, provider, and engine"
    description "Section 10. The address of a service the organisation hosts itself, used alone or together with an access key."
]

SecAuthenticationScheme as_PortalSignIn "Portal sign-in" : Local [
    issuer "ITLingoCloud"
    description "Section 2. A registered user signs in to the authenticated portal and sees the organisations and workspaces in which they hold an accepted role."
]

SecAuthenticationScheme as_EditorSession "Editor session description" : Other [
    issuer "ITLingoCloud"
    secret sec_EditorSharedSecret
    description "Section 8. A short description of the session, encrypted under the secret the platform shares with the editor: the identity of the user, the name and identifier of the workspace, the name of the owning organisation, and a single flag stating whether the session may write."
]

SecAuthenticationScheme as_ChatSession "Chat session statement" : Other [
    issuer "ITLingoCloud"
    sessionDuration 1 h
    secret sec_EditorSharedSecret
    description "Section 9. A signed statement of who the user is, which organisation the workspace belongs to, and whether the session is read-only. It is valid for one hour and is the credential the chatbot presents when it asks the platform to create a document."
]

/****************************************************
   Security: permissions (Sections 2 to 5, 7, 10 and 12)
*****************************************************/

SecPermission p_BrowsePublicSurface : Read [
    resource uc_BrowsePublicSurface
    resource e_LanguageFamily
    description "Section 2. The home page, the terms and conditions, the catalogue of specification languages and the detail page of any version in force, and the list of public workspaces are reachable without signing in."
]

SecPermission p_ViewPublicWorkspace : Read [
    resource uc_ViewPublicWorkspace
    condition "workspace.isPublic == true and document.documentState == 'DocPublished'"
    description "Section 4. A visitor to a public workspace sees the summary, the published documents, the specifications section, and the conversations, and no control that changes anything."
]

SecPermission p_RegisterAccount : Create [
    resource e_User
    description "Section 2. Registration is open and creates an account holding the member profile."
]

SecPermission p_CreateOrganisation : Create [
    resource ec_Organisation
    description "Section 2 and Section 3. Creating an organisation is not a privilege of any profile: any authenticated user may create one at any time, and becomes its accepted organisation manager."
]

SecPermission p_ViewOrganisation : Read [
    resource ec_Organisation
    condition "organisationRole.assignmentStatus == 'RoleAccepted'"
    description "Section 3. Only accepted assignments make the organisation visible to the holder."
]

SecPermission p_EditOrganisation : Update [
    resource e_Organisation
    description "Section 3. Only the name, the activity type, and the country may be changed from the portal, on a settings page reserved to organisation managers."
]

SecPermission p_DeleteOrganisation : Delete [
    resource e_Organisation
    condition "organisation.referencingWorkspaces == 0"
    description "Section 3. Deleting the organisation outright is reserved to an organisation manager and is refused while workspaces still reference it."
]

SecPermission p_InviteOrganisationMember : Create [
    resource e_OrganisationRole
    resource e_OrganisationInvitation
    description "Section 3. An organisation manager invites by supplying an email address and one of the three organisation roles. Membership grows only by invitation."
]

SecPermission p_ChangeOrganisationRole : Update [
    resource e_OrganisationRole
    condition "target.isLastAcceptedOrganisationManager == false"
    description "Section 3. A manager may change any member role, including that of a fellow manager, except that of the last accepted organisation manager."
]

SecPermission p_RemoveOrganisationMember : Delete [
    resource e_OrganisationRole
    condition "target.isLastAcceptedOrganisationManager == false"
    description "Section 3. A manager may remove any member, subject to the same last-manager invariant."
]

SecPermission p_ManageOrganisationDocuments : Manage [
    resource ec_Document
    condition "document.ownerOrganisationRef != null"
    description "Section 5. For an organisation document the organisation manager and the organisation document manager may create, edit, and delete it, and see it in every state."
]

SecPermission p_ReadPublishedOrganisationDocuments : Read [
    resource e_Document
    condition "document.ownerOrganisationRef != null and document.documentState == 'DocPublished'"
    description "Section 3 and Section 5. Every other accepted member of the organisation sees, opens, and downloads only documents in the published state, including inside the workspaces the organisation holds."
]

SecPermission p_ConfigureAssistance : Manage [
    resource ec_Assistance
    description "Section 10. The configuration section is reserved to organisation managers: every action on it refuses a user holding any other role, and a selection is only ever validated against the organisation own catalogue."
]

SecPermission p_CreateWorkspace : Create [
    resource ec_Workspace
    condition "organisationRole.assignmentStatus == 'RoleAccepted'"
    description "Section 4. Any user holding an accepted role of any kind in an organisation may create a workspace in it, and the creator receives the accepted workspace manager role."
]

SecPermission p_ViewWorkspace : Read [
    resource ec_Workspace
    condition "workspaceRole.assignmentStatus == 'RoleAccepted' or workspace.isPublic == true"
    description "Section 4. A workspace is visible to its accepted members, and, in reduced form, to anyone when it is marked public."
]

SecPermission p_EditWorkspace : Update [
    resource e_Workspace
    description "Section 4. The settings section, reserved to a workspace manager, reuses the four steps of creation to edit the workspace in place."
]

SecPermission p_ChangeWorkspaceProgress : Update [
    resource e_Workspace
    description "Section 4. Only a workspace manager may change the progress state; the workspace home offers starting, concluding, and cancelling."
]

SecPermission p_ResetWorkspaceProgress : Update [
    resource e_Workspace
    description "Section 4. Returning a concluded or cancelled workspace to not started has no control in the portal and is performed from the administrative interface."
]

SecPermission p_DeleteWorkspace : Delete [
    resource e_Workspace
    description "Section 4. Deleting the workspace is one of the rights of the workspace manager."
]

SecPermission p_InviteWorkspaceMember : Create [
    resource e_WorkspaceRole
    resource e_WorkspaceInvitation
    description "Section 4. Inviting is restricted to the workspace manager and works as it does for organisations."
]

SecPermission p_ChangeWorkspaceRole : Update [
    resource e_WorkspaceRole
    condition "target.isLastAcceptedWorkspaceManager == false"
    description "Section 4. The last accepted workspace manager may be neither demoted nor removed."
]

SecPermission p_RemoveWorkspaceMember : Delete [
    resource e_WorkspaceRole
    condition "target.isLastAcceptedWorkspaceManager == false"
    description "Section 4. Removing a member is restricted to the workspace manager and obeys the last-manager invariant."
]

SecPermission p_ManageWorkspaceDocuments : Manage [
    resource ec_Document
    condition "document.ownerWorkspaceRef != null"
    description "Section 5. For a workspace document the workspace manager and the workspace document manager may create, edit, and delete it, and see it in every state."
]

SecPermission p_ReadPublishedWorkspaceDocuments : Read [
    resource e_Document
    condition "document.ownerWorkspaceRef != null and document.documentState == 'DocPublished'"
    description "Section 5. A draft is invisible to a member holding no editing role rather than merely unopenable, because the listings, the counts, and the document pages are all restricted."
]

SecPermission p_SetDocumentState : Update [
    resource e_Document
    description "Section 5. On the document editing page an editor sets the state directly, and any of the five values may be chosen from any other."
]

SecPermission p_MarkGroundingKnowledge : Update [
    resource e_Document
    condition "document.documentState == 'DocPublished' and document.formatGroup == 'FormatText' and document.documentTypeRef != 'TypeTemplate'"
    description "Section 5. The mark may be applied only while the document is published and only when its file is textual; templates may never be marked."
]

SecPermission p_GenerateFromTemplate : Execute [
    resource e_GenerationRun
    resource e_Template
    description "Section 6. Generation is offered to anyone who may read the template, which is deliberately wider than the right to create or edit it."
]

SecPermission p_ConsultTemplateReference : Read [
    resource e_TemplateReference
    description "Section 6. The template reference is reachable without signing in for every language the visitor may see."
]

SecPermission p_WriteInEditorSession : Execute [
    resource e_EditorSession
    condition "workspaceRole.roleKind in ['WsManager', 'WsDocumentManager'] and workspaceRole.assignmentStatus == 'RoleAccepted'"
    description "Section 2 and Section 8. Write access to the editor is granted to the workspace manager and the workspace document manager, and to no one else. A launch from the public view of a public workspace is always read-only, whoever performs it."
]

SecPermission p_ExportIntoWorkspace : Create [
    resource ec_Interaction
    condition "workspaceRole.roleKind in ['WsManager', 'WsDocumentManager'] and workspaceRole.assignmentStatus == 'RoleAccepted'"
    description "Section 2 and Section 9. The right to export a generated specification into a workspace follows the same rule as write access to the editor, and is re-derived from the current workspace role at the moment of the request."
]

SecPermission p_BrowseLanguageCatalogue : Read [
    resource ec_Language
    condition "languageVersion.versionState == 'VersionActive' and languageFamily.isWithdrawn == false"
    description "Section 7. A visitor and an ordinary user see the versions in force of families that have not been withdrawn; a maintainer additionally sees the versions of the families they maintain, including drafts; an administrator sees everything."
]

SecPermission p_EditLanguageMetadata : Update [
    resource e_LanguageVersion
    condition "changedFields not_in ['familyName', 'acronymText']"
    description "Section 7. A maintainer may edit the metadata of the versions of the family, except the name and the acronym, which only an administrator may change."
]

SecPermission p_EditGrammarFiles : Update [
    resource e_GrammarFile
    condition "languageVersion.versionState == 'VersionDraft'"
    description "Section 7. Draft is the only state in which grammar files may be created, changed, or removed, and a request to alter one in any other state is refused even when it is made directly."
]

SecPermission p_EditServicesFiles : Update [
    resource e_ServicesFile
    condition "languageVersion.versionState == 'VersionDraft'"
    description "Section 7. Custom services files are edited in the same editor, by the same maintainers, and only while the version is in draft."
]

SecPermission p_ValidateGrammar : Execute [
    resource e_GrammarValidationResult
    description "Section 7. A maintainer may run a validation without changing the state of the version."
]

SecPermission p_CreateDraftVersion : Create [
    resource e_LanguageVersion
    description "Section 7. Iteration happens by creating a new draft from an existing version, which copies the metadata and every file of its source and leaves the source untouched."
]

SecPermission p_ExchangeLanguageFiles : Execute [
    resource e_LanguageVersion
    description "Section 7. A maintainer may export and re-import the grammar and services files as a set; the remaining kinds are replaced one at a time."
]

SecPermission p_DownloadLanguageFiles : Read [
    resource e_GrammarFile
    resource e_ServicesFile
    description "Section 7. The grammar and services files are not public merely because the metadata is: downloading them, individually or as a set, is restricted to the administrator and the family maintainers."
]

SecPermission p_PublishLanguageVersion : Execute [
    resource e_LanguageVersion
    condition "languageVersion.validationState == 'ValidationCurrentSuccess' and languageVersion.buildState != 'BuildFailed'"
    description "Section 7. Publication is the only transition a user performs, is reserved to the platform administrator, and is conditional on a current, successful validation the platform re-runs itself."
]

SecPermission p_RegisterLanguageFamily : Create [
    resource e_LanguageFamily
    description "Section 7 and Section 12. Creating a language is reserved to the platform administrator."
]

SecPermission p_DeleteLanguageFamily : Delete [
    resource e_LanguageFamily
    description "Section 7. Deleting a language, and withdrawing a family so that all of its versions are hidden at once, are the administrator."
]

SecPermission p_AssignLanguageMaintainer : Manage [
    resource e_LanguageMaintainer
    description "Section 7. The assignment and removal of maintainers are reserved to the platform administrator."
]

SecPermission p_SelectAvailableLanguages : Update [
    resource e_LanguageSelection
    description "Section 7. An organisation may declare which languages are available to it, and a workspace may narrow that set further and nominate a default."
]

SecPermission p_ReadOwnNotifications : Read [
    resource e_Notification
    condition "notification.recipientRef == currentUser"
    description "Section 11. Every action is restricted to the notifications of the user performing it, and a user sees only their own; the administrator sees all of them."
]

SecPermission p_ManageUserAccounts : Manage [
    resource e_User
    description "Section 12. Viewing and editing every user, deleting users, and assigning the platform profile each user holds, through the administrative interface."
]

SecPermission p_SuspendOrganisation : Update [
    resource e_Organisation
    description "Section 12. Suspending an organisation and reactivating it are not offered anywhere in the portal."
]

SecPermission p_OverseeEveryRecord : Read [
    resource ITLingoCloud
    description "Section 12. Every organisation, workspace, membership, document, language version, and notification is visible and actionable to the administrator irrespective of membership."
]

SecPermission p_ConfigureEditorIntegration : Manage [
    resource e_EditorIntegrationSetting
    description "Section 12. The address at which the editor is reached, the secret shared with it, the lifetime of the separately issued access credentials, and the general-purpose file extensions admitted for import."
]

SecPermission p_MaintainPlatformAssistanceDefaults : Manage [
    resource e_Provider
    resource e_EngineRoleAssignment
    resource e_InstructionBlock
    description "Section 10 and Section 12. The platform-wide catalogue, the platform defaults, and the platform instruction block that precedes every organisation own, edited through the administrative interface."
]

/****************************************************
   Security: roles and access policies (Sections 2 to 5, 7 and 12)
*****************************************************/

SecRole r_Visitor "Visitor" : External [
    permission p_BrowsePublicSurface
    permission p_ViewPublicWorkspace
    permission p_RegisterAccount
    permission p_BrowseLanguageCatalogue
    permission p_ConsultTemplateReference
    description "Section 2. What an unauthenticated visitor may reach. No page invites a visitor to request access to anything."
]

SecRole r_PlatformMember "Platform member profile" : System [
    permission p_CreateOrganisation
    permission p_ReadOwnNotifications
    permission p_BrowseLanguageCatalogue
    permission p_ConsultTemplateReference
    description "Section 2. The profile every newly registered portal user receives automatically. It confers nothing inside any container: everything else is granted by an organisation or workspace role."
]

SecRole r_PlatformManager "Platform manager profile" : System [
    inherits r_PlatformMember
    description "Section 2. A member who additionally holds write and delete authority over the organisations and workspaces of which they are an accepted member."
]

SecRole r_PlatformAdministrator "Platform administrator profile" : System [
    inherits r_PlatformManager
    permission p_OverseeEveryRecord
    permission p_ManageUserAccounts
    permission p_SuspendOrganisation
    permission p_ResetWorkspaceProgress
    permission p_RegisterLanguageFamily
    permission p_DeleteLanguageFamily
    permission p_AssignLanguageMaintainer
    permission p_PublishLanguageVersion
    permission p_DownloadLanguageFiles
    permission p_ConfigureEditorIntegration
    permission p_MaintainPlatformAssistanceDefaults
    description "Sections 2 and 12. Full authority over every record on the platform, irrespective of membership. None of these capabilities is delegable through an organisation or workspace role."
]

SecRole r_OrganisationMember "Organisation member" : Business [
    permission p_ViewOrganisation
    permission p_CreateWorkspace
    permission p_ReadPublishedOrganisationDocuments
    permission p_GenerateFromTemplate
    description "Section 2. May view the organisation and create workspaces in it, and may read and download only those organisation documents that have been published."
]

SecRole r_OrganisationDocumentManager "Organisation document manager" : Business [
    inherits r_OrganisationMember
    permission p_ManageOrganisationDocuments
    description "Section 2. May create, edit, and delete organisation documents, and create workspaces, but may not alter the organisation or its membership."
]

SecRole r_OrganisationManager "Organisation manager" : Business [
    inherits r_OrganisationDocumentManager
    permission p_EditOrganisation
    permission p_InviteOrganisationMember
    permission p_ChangeOrganisationRole
    permission p_RemoveOrganisationMember
    permission p_DeleteOrganisation
    permission p_ConfigureAssistance
    permission p_SelectAvailableLanguages
    description "Section 2. May edit the organisation details, invite people, change and revoke the roles of others, create workspaces, create and edit organisation documents, configure the organisation assistance settings, and delete the organisation."
]

SecRole r_WorkspaceMember "Workspace member" : Business [
    permission p_ViewWorkspace
    permission p_ReadPublishedWorkspaceDocuments
    permission p_ReadPublishedOrganisationDocuments
    permission p_GenerateFromTemplate
    description "Section 2. May view the workspace and read and download only those workspace documents that have been published. Receives a read-only editor session."
]

SecRole r_WorkspaceDocumentManager "Workspace document manager" : Business [
    inherits r_WorkspaceMember
    permission p_ManageWorkspaceDocuments
    permission p_SetDocumentState
    permission p_MarkGroundingKnowledge
    permission p_WriteInEditorSession
    permission p_ExportIntoWorkspace
    description "Section 2. May create, edit, and delete workspace documents, but may not alter the workspace or its membership. Holds write access to the editor and the right to export a generated specification into the workspace."
]

SecRole r_WorkspaceManager "Workspace manager" : Business [
    inherits r_WorkspaceDocumentManager
    permission p_EditWorkspace
    permission p_ChangeWorkspaceProgress
    permission p_InviteWorkspaceMember
    permission p_ChangeWorkspaceRole
    permission p_RemoveWorkspaceMember
    permission p_DeleteWorkspace
    permission p_SelectAvailableLanguages
    description "Section 2. May edit the workspace properties and progress state, invite people, change and revoke roles, create, edit, and delete workspace documents, and delete the workspace."
]

SecRole r_LanguageMaintainer "Language maintainer" : Business [
    permission p_EditLanguageMetadata
    permission p_EditGrammarFiles
    permission p_EditServicesFiles
    permission p_ValidateGrammar
    permission p_CreateDraftVersion
    permission p_ExchangeLanguageFiles
    permission p_DownloadLanguageFiles
    permission p_GenerateFromTemplate
    description "Section 2 and Section 7. Granted per language family and independent of every other level: holding an organisation or workspace role grants no rights over any language, and maintaining a language grants no rights in any organisation or workspace. A maintainer may not publish."
]

SecRole r_SpecificationEditor "Editor integration" : External [
    permission p_ReadPublishedWorkspaceDocuments
    permission p_ReadPublishedOrganisationDocuments
    description "Section 8. The editor acts under the session description the platform issued, and the platform offers it no way to write a file back."
]

SecRole r_Chatbot "Chatbot integration" : External [
    permission p_ExportIntoWorkspace
    description "Section 9. The chatbot acts under the session statement, and the platform re-derives the user write permission from their current workspace role rather than relying on the read-only flag the statement carries."
]

SecAccessPolicy ap_PublicAccess "Public surface policy" : RBAC [
    role r_Visitor
    permission p_BrowsePublicSurface
    permission p_ViewPublicWorkspace
    permission p_RegisterAccount
    permission p_BrowseLanguageCatalogue
    permission p_ConsultTemplateReference
    effect Allow
    description "Section 2 and Section 4. The pages reachable without signing in."
]

SecAccessPolicy ap_PlatformProfiles "Platform profile policy" : RBAC [
    role r_PlatformMember
    role r_PlatformManager
    role r_PlatformAdministrator
    permission p_CreateOrganisation
    permission p_ReadOwnNotifications
    permission p_OverseeEveryRecord
    permission p_ManageUserAccounts
    permission p_SuspendOrganisation
    permission p_ResetWorkspaceProgress
    permission p_ConfigureEditorIntegration
    permission p_MaintainPlatformAssistanceDefaults
    effect Allow
    description "Sections 2 and 12. A platform profile establishes what a person may do to the platform as a whole. The distinction that matters most in daily use is between the administrator and everyone else."
]

SecAccessPolicy ap_OrganisationRBAC "Organisation role policy" : RBAC [
    role r_OrganisationManager
    role r_OrganisationDocumentManager
    role r_OrganisationMember
    permission p_ViewOrganisation
    permission p_EditOrganisation
    permission p_DeleteOrganisation
    permission p_InviteOrganisationMember
    permission p_ChangeOrganisationRole
    permission p_RemoveOrganisationMember
    permission p_ManageOrganisationDocuments
    permission p_ReadPublishedOrganisationDocuments
    permission p_CreateWorkspace
    permission p_ConfigureAssistance
    condition "organisationRole.assignmentStatus == 'RoleAccepted'"
    effect Allow
    description "Section 2 and Section 3. A user holds at most one role per organisation, and only accepted assignments grant anything or make the organisation visible."
]

SecAccessPolicy ap_WorkspaceRBAC "Workspace role policy" : RBAC [
    role r_WorkspaceManager
    role r_WorkspaceDocumentManager
    role r_WorkspaceMember
    permission p_ViewWorkspace
    permission p_EditWorkspace
    permission p_ChangeWorkspaceProgress
    permission p_DeleteWorkspace
    permission p_InviteWorkspaceMember
    permission p_ChangeWorkspaceRole
    permission p_RemoveWorkspaceMember
    permission p_ManageWorkspaceDocuments
    permission p_ReadPublishedWorkspaceDocuments
    permission p_SetDocumentState
    permission p_MarkGroundingKnowledge
    permission p_WriteInEditorSession
    permission p_ExportIntoWorkspace
    condition "workspaceRole.assignmentStatus == 'RoleAccepted'"
    effect Allow
    description "Section 2 and Section 4. The three workspace roles mirror the organisation roles, and only accepted assignments grant anything."
]

SecAccessPolicy ap_LanguageGovernance "Language governance policy" : RBAC [
    role r_LanguageMaintainer
    role r_PlatformAdministrator
    permission p_EditLanguageMetadata
    permission p_EditGrammarFiles
    permission p_EditServicesFiles
    permission p_ValidateGrammar
    permission p_CreateDraftVersion
    permission p_ExchangeLanguageFiles
    permission p_DownloadLanguageFiles
    permission p_PublishLanguageVersion
    permission p_RegisterLanguageFamily
    permission p_DeleteLanguageFamily
    permission p_AssignLanguageMaintainer
    effect Allow
    description "Section 7. A language team prepares and validates a version, and the platform decides what comes into force, because a version in force changes the behaviour of the editor, of generation, and of the chatbot for every user."
]

SecAccessPolicy ap_PublishedOnlyVisibility "Published-only visibility policy" : ABAC [
    role r_OrganisationMember
    role r_WorkspaceMember
    role r_Visitor
    permission p_ReadPublishedWorkspaceDocuments
    permission p_ReadPublishedOrganisationDocuments
    condition "document.documentState != 'DocPublished'"
    effect Deny
    description "Section 5. A document in any state other than published is seen only by the roles that may edit it, so that a draft is invisible to an ordinary member rather than merely unopenable."
]

SecAccessPolicy ap_AssistanceConfiguration "Assistance configuration policy" : RBAC [
    role r_OrganisationManager
    permission p_ConfigureAssistance
    effect Allow
    description "Section 10. The configuration section appears in the organisation hub only when the conversational part of the system is present, and every action on it refuses a user holding any other role."
]

SecAccessPolicy ap_IntegrationSessions "Integration session policy" : ABAC [
    role r_SpecificationEditor
    role r_Chatbot
    permission p_WriteInEditorSession
    permission p_ExportIntoWorkspace
    condition "session.workspaceRef == request.workspaceRef"
    effect Allow
    description "Sections 8 and 9. Both integrations act under a session the platform issued, and both are checked against the workspace the session was issued for."
]

/****************************************************
   Use cases (Sections 2 to 12)
*****************************************************/

UseCase uc_BrowsePublicSurface "Browse the public surface" : EntitiesBrowse [
    stakeholder stk_Visitor
    primaryActor a_Visitor
    dataEntity e_LanguageFamily
    precondition "None: the pages are reachable without signing in."
    postcondition "No record is created or changed."
    priority High
    description "Section 2. An unauthenticated visitor may reach the home page, the terms and conditions, the catalogue of specification languages and the detail page of any language version in force, and the list of workspaces their owners have marked public. No other part of the platform is reachable without signing in, and no page invites a visitor to request access to anything."
]

UseCase uc_ViewPublicWorkspace "View a public workspace" : EntityRead [
    stakeholder stk_Visitor
    primaryActor a_Visitor
    dataEntity ec_Workspace
    precondition "The workspace is marked public; the public page refuses a workspace that is not public."
    postcondition "Nothing changes: no control that changes anything is offered."
    priority High
    description "Section 4. An anonymous visitor sees a reduced version of the hub: the summary with counts of documents by type and by specification language family but not of members, the documents that are in the published state, the specifications section from which the workspace can be opened read-only in the editor, and the conversations. A signed-in user who holds an accepted role on a public workspace is redirected from the public view to their own."
]

UseCase uc_RegisterAccount "Register an account" : EntityCreate [
    stakeholder stk_Visitor
    primaryActor a_Visitor
    dataEntity e_User
    precondition "The visitor has no account."
    postcondition "An account exists with the member profile, the acceptance of the terms recorded with its version, moment, network address, and browser identification, and no organisation created."
    priority High
    description "Section 2. If the address used to register matches an invitation issued earlier, the corresponding memberships are created immediately and in the accepted status, and the user lands in the portal already belonging to the organisations and workspaces that invited them."
    extensionPoints epNoPriorInvitation ["No invitation matched the address, so the first successful sign-in offers to create an organisation and the offer is not repeated if skipped."]
]

UseCase uc_SignIn "Sign in" : Login [
    stakeholder stk_Practitioner
    primaryActor a_RegisteredUser
    dataEntity e_User
    precondition "The user holds an account."
    postcondition "The user reaches the authenticated portal and sees the organisations and workspaces in which they hold an accepted role."
    priority High
    description "Section 2. A member or manager sees only the organisations and workspaces in which they hold an accepted role, whereas an administrator sees and may act on every record."
]

UseCase uc_CreateOrganisation "Create an organisation" : EntityCreate [
    stakeholder stk_Practitioner
    primaryActor a_RegisteredUser
    dataEntity ec_Organisation
    precondition "The user is authenticated. Creating an organisation is not a privilege of any profile: any authenticated user may create one at any time."
    postcondition "The organisation exists in the active state and the creator holds the organisation manager role with the accepted status."
    priority High
    description "Section 3. An organisation carries a name, an activity type chosen from information technology, marketing, consulting, finance, education, and other, an optional country, a description, and a logo."
]

UseCase uc_EditOrganisationSettings "Edit the organisation settings" : EntityUpdate [
    stakeholder stk_ContainerManager
    primaryActor a_OrganisationManager
    dataEntity e_Organisation
    precondition "The viewer holds the accepted organisation manager role; the settings page is reserved to organisation managers."
    postcondition "The name, the activity type, or the country is changed. No other attribute may be changed from the portal."
    priority Medium
    description "Section 3. Only the name, the activity type, and the country may be changed from the portal."
]

UseCase uc_InviteOrganisationMember "Invite a person to an organisation" : EntityCreate [
    stakeholder stk_ContainerManager
    primaryActor a_OrganisationManager
    dataEntity ec_Organisation
    precondition "The inviter holds the accepted organisation manager role."
    postcondition "Either a pending role assignment exists for an existing account, or a pending invitation is recorded for an address that holds none."
    priority High
    description "Section 3. Membership grows only by invitation: organisations are not listed publicly and no page anywhere offers to apply. A manager is told nothing beyond the confirmation that the invitation was sent, and no page in the portal shows outstanding invitations."
    extensionPoints epInviteeHasNoAccount ["The address belongs to no account: the pending invitation is recorded, a message inviting the recipient to create an account is sent and resent rather than duplicated, and the invitation is honoured automatically at registration."]
]

UseCase uc_AnswerOrganisationInvitation "Accept or reject an organisation invitation" : EntityUpdate [
    stakeholder stk_Practitioner
    primaryActor a_RegisteredUser
    dataEntity e_OrganisationRole
    precondition "A role assignment in the pending status exists for the answering user."
    postcondition "The assignment becomes accepted or rejected, the response time is stamped, and a message is posted on the organisation history."
    priority High
    description "Section 3. An invited user answers from their notifications. Acceptance of the organisation manager role additionally cascades workspace management across every workspace the organisation holds at that moment."
]

UseCase uc_ChangeOrganisationRole "Change the role of an organisation member" : EntityUpdate [
    stakeholder stk_ContainerManager
    primaryActor a_OrganisationManager
    dataEntity e_OrganisationRole
    precondition "The target holds an accepted role, and the target is not the last accepted organisation manager."
    postcondition "The member holds the new role."
    priority Medium
    description "Section 3. A manager may change any member role, including that of a fellow manager, subject to one invariant: the last accepted organisation manager can neither be demoted nor removed."
]

UseCase uc_RemoveOrganisationMember "Remove an organisation member" : EntityDelete [
    stakeholder stk_ContainerManager
    primaryActor a_OrganisationManager
    dataEntity e_OrganisationRole
    precondition "The target holds an accepted role and is not the last accepted organisation manager."
    postcondition "The membership no longer exists."
    priority Medium
    description "Section 3. A manager may remove any member, including a fellow manager, subject to the last-manager invariant."
]

UseCase uc_LeaveOrganisation "Leave an organisation" : EntityUpdate [
    stakeholder stk_Practitioner
    primaryActor a_OrganisationMember
    dataEntity ec_Organisation
    precondition "The departing user holds an accepted role. Leaving is available to every accepted member."
    postcondition "Either the organisation is deleted, or a successor is promoted and the departure carried out together with the promotion, or the membership is simply removed."
    priority Medium
    description "Section 3. Three outcomes are possible. A member who is the only accepted member deletes the organisation by leaving, unless workspaces still reference it, in which case the departure is refused and the workspaces must be removed or reassigned first. A member who is the last accepted manager while other members remain chooses a successor among the other accepted members, and the promotion and the departure are then carried out together. In every other case the membership is simply removed."
]

UseCase uc_PromoteOrganisationSuccessor "Promote a successor before leaving an organisation" : EntityUpdate [
    stakeholder stk_ContainerManager
    primaryActor a_OrganisationManager
    dataEntity e_OrganisationRole
    precondition "The departing user is the last accepted organisation manager while other accepted members remain."
    postcondition "Another accepted member holds the organisation manager role and the departure is carried out together with the promotion."
    priority Medium
    description "Section 3. A member who is the last accepted manager while other members remain is redirected to a page on which they choose a successor among the other accepted members; the promotion and the departure are then carried out together."
]

UseCase uc_DeleteOrganisation "Delete an organisation" : EntityDelete [
    stakeholder stk_ContainerManager
    primaryActor a_OrganisationManager
    dataEntity e_Organisation
    precondition "No workspace still references the organisation."
    postcondition "The organisation no longer exists."
    priority Low
    description "Section 3. Deleting the organisation outright follows the same workspace restriction as leaving and is reserved to an organisation manager. Deleting an organisation one does not belong to is an administrative act."
]

UseCase uc_ViewOrganisationHub "View the organisation hub" : EntityDashboard [
    stakeholder stk_Practitioner
    primaryActor a_OrganisationMember
    dataEntity ec_Organisation
    precondition "The viewer holds an accepted role in the organisation."
    postcondition "Nothing changes."
    priority Medium
    description "Section 3. The hub presents the organisation through a fixed set of sections reached from a sidebar. Its home summarises the organisation in grouped counts: its workspaces by progress state, its documents by type and by specification language family, its members by role, and its registered assistance engines, each count linking to the corresponding filtered list. The workspaces section is restricted to those in which the viewer holds an accepted workspace role. Counts of documents and the documents listed are restricted to the published state for members who do not hold an editing role. The assistance configuration and the general settings are visible only to organisation managers."
]

UseCase uc_ListOrganisationUsers "List the organisation users" : EntitiesBrowse [
    stakeholder stk_Practitioner
    primaryActor a_OrganisationMember
    dataEntity e_OrganisationRole
    precondition "The viewer holds an accepted role in the organisation."
    postcondition "Nothing changes."
    priority Medium
    description "Section 3. An organisation manager sees every accepted member, with filters and paging, together with the controls for changing a role and removing a member. Every other accepted role sees only their own row, with the organisation total member count but no filters and no paging, and supplying filter parameters in the address does not widen that view. The users page lists only members whose role is accepted."
]

UseCase uc_ReadSharedOrganisationDocument "Read an organisation document inside a workspace" : EntityRead [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceMember
    dataEntity e_Document
    precondition "The document belongs to the workspace organisation and is in the published state."
    postcondition "Nothing changes; editing requires an organisation editing role."
    priority Medium
    description "Section 3. Organisation documents are shared into the organisation workspaces rather than copied. Editing one of those documents from inside the workspace requires an organisation editing role, not a workspace one: a workspace manager who is only an organisation member may read the shared document but not change it."
]

UseCase uc_CreateWorkspace "Create a workspace" : EntityCreate [
    stakeholder stk_Practitioner
    primaryActor a_OrganisationMember
    dataEntity ec_Workspace
    precondition "The creator holds an accepted role of any kind in the organisation."
    postcondition "The workspace exists in the not started state with its own stable key, and the creator holds the workspace manager role with the accepted status."
    priority High
    description "Section 4. A workspace is created through a guided sequence of four steps."
]

UseCase uc_EditWorkspaceSettings "Edit the workspace settings" : EntityUpdate [
    stakeholder stk_ContainerManager
    primaryActor a_WorkspaceManager
    dataEntity e_Workspace
    precondition "The viewer holds the accepted workspace manager role; the settings section is reserved to a workspace manager."
    postcondition "The edited attributes are saved."
    priority Medium
    description "Section 4. The settings section reuses the four steps of creation to edit the workspace in place, each step saving as it is left."
]

UseCase uc_ChangeWorkspaceProgress "Change the workspace progress" : EntityUpdate [
    stakeholder stk_ContainerManager
    primaryActor a_WorkspaceManager
    dataEntity e_Workspace
    precondition "The actor holds the accepted workspace manager role. No transition examines the state a workspace is in before writing the new one."
    postcondition "The progress state is written; starting records the actual start date and concluding records the actual end date."
    priority Medium
    description "Section 4. The workspace home offers the first three transitions: starting, concluding, and cancelling. The progression is presented rather than enforced, and the state is a statement about the work rather than an access control, so a concluded workspace remains fully usable by its members."
]

UseCase uc_ResetWorkspaceProgress "Reset the workspace progress" : EntityUpdate [
    stakeholder stk_PlatformAdministration
    primaryActor a_PlatformAdministrator
    dataEntity e_Workspace
    precondition "The workspace is concluded or cancelled."
    postcondition "The workspace is back in the not started state."
    priority Low
    description "Section 4. Returning a concluded or cancelled workspace to not started is accepted by the platform but has no control on the workspace home and is performed from the administrative interface."
]

UseCase uc_InviteWorkspaceMember "Invite a person to a workspace" : EntityCreate [
    stakeholder stk_ContainerManager
    primaryActor a_WorkspaceManager
    dataEntity ec_Workspace
    precondition "The inviter holds the accepted workspace manager role."
    postcondition "A pending role assignment exists, or a pending invitation is recorded for an address that holds no account."
    priority High
    description "Section 4. Membership works as it does for organisations, with invitations by email address and role, automatic acceptance for addresses that had no account, and notification of the invitee."
]

UseCase uc_AnswerWorkspaceInvitation "Accept or reject a workspace invitation" : EntityUpdate [
    stakeholder stk_Practitioner
    primaryActor a_RegisteredUser
    dataEntity e_WorkspaceRole
    precondition "A workspace role assignment in the pending status exists for the answering user."
    postcondition "The assignment becomes accepted or rejected, the response time is stamped, and a message is posted on the workspace history."
    priority High
    description "Sections 2 and 4. A user who accepts a workspace role and has no role at all in the workspace organisation receives an accepted organisation member role there, so that a workspace collaborator can always see the organisational context of the work."
]

UseCase uc_ChangeWorkspaceRole "Change the role of a workspace member" : EntityUpdate [
    stakeholder stk_ContainerManager
    primaryActor a_WorkspaceManager
    dataEntity e_WorkspaceRole
    precondition "The target holds an accepted role and is not the last accepted workspace manager."
    postcondition "The member holds the new role."
    priority Medium
    description "Section 4. The last accepted workspace manager may be neither demoted nor removed."
]

UseCase uc_RemoveWorkspaceMember "Remove a workspace member" : EntityDelete [
    stakeholder stk_ContainerManager
    primaryActor a_WorkspaceManager
    dataEntity e_WorkspaceRole
    precondition "The target holds an accepted role and is not the last accepted workspace manager."
    postcondition "The membership no longer exists."
    priority Medium
    description "Section 4. Inviting, changing a role, and removing are restricted to the workspace manager."
]

UseCase uc_LeaveWorkspace "Leave a workspace" : EntityUpdate [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceMember
    dataEntity ec_Workspace
    precondition "The departing user holds an accepted role in the workspace."
    postcondition "Either the workspace is deleted together with whatever it still contains, or a successor is promoted and the departure carried out together with the promotion, or the membership is simply removed."
    priority Medium
    description "Section 4. Leaving behaves as it does for an organisation, with one deliberate difference: a workspace is never left without members, so when its sole accepted member leaves, the workspace is deleted together with whatever it still contains, and the last manager among others must promote a successor first."
]

UseCase uc_PromoteWorkspaceSuccessor "Promote a successor before leaving a workspace" : EntityUpdate [
    stakeholder stk_ContainerManager
    primaryActor a_WorkspaceManager
    dataEntity e_WorkspaceRole
    precondition "The departing user is the last accepted workspace manager while other accepted members remain."
    postcondition "Another accepted member holds the workspace manager role and the departure is carried out together with the promotion."
    priority Medium
    description "Section 4. As in an organisation, the last manager among others must promote a successor first; only the sole accepted member of a workspace leaves without one, which deletes the workspace."
]

UseCase uc_DeleteWorkspace "Delete a workspace" : EntityDelete [
    stakeholder stk_ContainerManager
    primaryActor a_WorkspaceManager
    dataEntity e_Workspace
    precondition "The actor holds the accepted workspace manager role."
    postcondition "The workspace and its contents no longer exist."
    priority Low
    description "Section 4. Deleting the workspace is one of the rights of the workspace manager."
]

UseCase uc_ViewWorkspaceHub "View the workspace hub" : EntityDashboard [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceMember
    dataEntity ec_Workspace
    precondition "The viewer holds an accepted role in the workspace, or the workspace is public and the viewer is a visitor."
    postcondition "Nothing changes."
    priority Medium
    description "Section 4. The workspace hub offers six sections: the home with the summary and, for a workspace manager, the progress transitions; the documents section, which lists the workspace documents together with a second list of the published documents of its organisation; the specifications section, which is the launching point for the editor; the chat section, which embeds the chatbot; the users section; and the settings section, reserved to a workspace manager."
]

UseCase uc_ListWorkspaceUsers "List the workspace users" : EntitiesBrowse [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceMember
    dataEntity e_WorkspaceRole
    precondition "The viewer holds an accepted role in the workspace."
    postcondition "Nothing changes."
    priority Medium
    description "Section 4. On the workspace users page every accepted role sees the full member list with its filters and paging, unlike the organisation users page, and only the actions of inviting, changing a role, and removing are restricted to the workspace manager."
]

UseCase uc_CreateDocument "Create a document" : EntityCreate [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceDocumentManager
    supportingActor a_WorkspaceManager
    supportingActor a_OrganisationManager
    supportingActor a_OrganisationDocumentManager
    dataEntity ec_Document
    precondition "The actor holds an editing role in the containing scope: for an organisation document the organisation manager or the organisation document manager, and for a workspace document the workspace manager or the workspace document manager."
    postcondition "The document exists in the draft state, belonging to a workspace or to an organisation but not to both, with its creator, its creation date, and the size of its file recorded."
    priority High
    description "Section 5. The name is the only attribute the platform requires. The version label is free text with an initial value of 1.0. The association with a specification language is made in two parts, a language family and, optionally, the particular version; naming a version without its family, or a version belonging to a different family, is refused."
]

UseCase uc_EditDocument "Edit a document" : EntityUpdate [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceDocumentManager
    supportingActor a_WorkspaceManager
    supportingActor a_OrganisationManager
    supportingActor a_OrganisationDocumentManager
    dataEntity ec_Document
    precondition "The actor holds an editing role in the containing scope."
    postcondition "The stored file and the version label are replaced in place, and an entry is written to the change history for each tracked attribute that changed."
    priority High
    description "Section 5. Versioning is deliberately light: the platform keeps no prior copy, so a new version of a specification is either a new version label on the same document or a separate document, at the author discretion. A file exchanged without any other edit leaves no history entry at all."
]

UseCase uc_DeleteDocument "Delete a document" : EntityDelete [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceDocumentManager
    supportingActor a_WorkspaceManager
    supportingActor a_OrganisationManager
    supportingActor a_OrganisationDocumentManager
    dataEntity e_Document
    precondition "The actor holds an editing role in the containing scope."
    postcondition "The document no longer exists."
    priority Medium
    description "Section 5. Deletion is permanent and is not an archive; archiving is the separate lifecycle state."
]

UseCase uc_SetDocumentState "Set the document state" : EntityUpdate [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceDocumentManager
    supportingActor a_WorkspaceManager
    supportingActor a_OrganisationManager
    supportingActor a_OrganisationDocumentManager
    dataEntity e_Document
    precondition "The actor holds an editing role in the containing scope. No prior state is required: any of the five values may be chosen from any other."
    postcondition "The new state is written; if the document leaves the published state, any grounding knowledge mark is withdrawn together with its text from the pool."
    priority High
    description "Section 5. On the document editing page an editor sets the state directly. The platform does not require a document to pass through review and approval before it is published, nor does it prevent a published document from returning to draft. What the state governs is visibility: a document in any state other than published is seen only by the roles that may edit it."
]

UseCase uc_MarkGroundingKnowledge "Mark a document as grounding knowledge" : EntityUpdate [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceDocumentManager
    supportingActor a_WorkspaceManager
    supportingActor a_OrganisationManager
    supportingActor a_OrganisationDocumentManager
    dataEntity e_Document
    precondition "The document is in the published state and its file is textual, either a generic text format or a format registered by a specification language. Templates may never be marked."
    postcondition "The text of the document joins the pool the chatbot consults, scoped to the workspace or the organisation that owns the document."
    priority Medium
    description "Section 5. A document that leaves published loses the mark automatically, and its text is withdrawn from the pool at the same moment, so that content which informs assisted answers is always content the platform currently publishes."
]

UseCase uc_BrowseDocuments "Browse and download documents" : EntitiesBrowse [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceMember
    supportingActor a_OrganisationMember
    supportingActor a_Visitor
    dataEntity ec_Document
    precondition "The viewer holds an accepted role in the scope, or the workspace is public."
    postcondition "Nothing changes."
    priority High
    description "Section 5. Every accepted member of the scope who holds no editing role sees, opens, and downloads only documents in the published state, and the listings, the counts, and the document pages are all restricted accordingly, so that a draft is invisible to them rather than merely unopenable."
]

UseCase uc_ViewDocumentHistory "View the document change history" : EntityRead [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceDocumentManager
    dataEntity e_DocumentChangeEntry
    precondition "The viewer may see the document."
    postcondition "Nothing changes."
    priority Low
    description "Section 5 and Section 11. The history covers alterations to the document name, state, version, type, and language associations, but not the content that was replaced and not the replacement of the file itself."
]

UseCase uc_UploadTemplate "Upload a template" : EntityCreate [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceDocumentManager
    supportingActor a_OrganisationDocumentManager
    dataEntity e_Template
    precondition "The actor holds an editing role in the containing scope, the document type is template, the template names the specification language family it applies to, and its file is one the platform can render."
    postcondition "A template document exists, excluded from grounding knowledge and from the documents the editor offers to import."
    priority Medium
    description "Section 6. A template may additionally carry a pattern from which the name of the generated file is composed, which the portal discards when the document type ceases to be template."
]

UseCase uc_GenerateFromTemplate "Generate a document from a template" : EntitiesInteropExport [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceMember
    supportingActor a_OrganisationMember
    supportingActor a_LanguageMaintainer
    supportingActor a_PlatformAdministrator
    dataEntity e_GenerationRun
    precondition "The user may read the template, which is deliberately wider than the right to create or edit it. The uploaded file carries an extension the target language registers, and the target language is ready: a version in force or in preparation, carrying a grammar, validated currently and successfully, matching the grammar recorded at publication, and with a current successful build of any custom services."
    postcondition "The produced file is returned directly to the browser. The result is not stored: no document is created and nothing is retained, so generation leaves the workspace unchanged."
    priority High
    description "Section 6. The generation panel appears on the template own page, in the workspace hub, in the organisation hub, and on the view of an organisation template surfaced inside a workspace. The language version used is the one currently in force for the template family; a maintainer of that family, and an administrator, may instead direct the run at a particular version, including one still in draft."
    extensionPoints epImportUnresolved ["An import matches nothing and is reported as an error naming the importing file and the line."],
        epImportAmbiguous ["An import matches more than one candidate and is reported as an error naming the contested declaration and the documents that declare it."]
]

UseCase uc_ConsultTemplateReference "Consult the template reference" : EntityRead [
    stakeholder stk_Practitioner
    primaryActor a_Visitor
    supportingActor a_RegisteredUser
    dataEntity e_TemplateReference
    precondition "The visitor may see the language."
    postcondition "Nothing changes."
    priority Medium
    description "Section 6. The template reference documents, per language, exactly what a template may address: the entry type of the language, every type with its fields, and for each field whether it holds a value, a reference, or a nested element, whether it is a list, and whether it is optional. It distinguishes the types a template may iterate over from those that only ever occur inside another, and offers a ready-to-copy snippet for each, together with a downloadable starter template. It falls back to generic documentation, rather than presenting an empty inventory, when the description of the grammar cannot be produced."
]

UseCase uc_CheckTemplateFragment "Check a template against a language inventory" : EntityOther [
    stakeholder stk_Practitioner
    primaryActor a_RegisteredUser
    dataEntity e_TemplateAdvisoryCheck
    precondition "A fragment is pasted or a stored template is chosen."
    postcondition "Findings are reported. The check never blocks generation and never stores what it was given."
    priority Low
    description "Section 6. The advisory check reports syntax errors with their positions, unknown names with the closest matching suggestion, lookups keyed on a type the language does not define, and probable field misspellings. It exists largely to compensate for lenient rendering, which makes a misspelled field name indistinguishable from an absent value."
]

UseCase uc_RegisterLanguageFamily "Register a language family" : EntityCreate [
    stakeholder stk_PlatformAdministration
    primaryActor a_PlatformAdministrator
    dataEntity e_LanguageFamily
    precondition "The actor holds the administrator profile. Creating a language is reserved to the platform administrator."
    postcondition "The family exists with a full name and an acronym unique across the platform without regard to case."
    priority High
    description "Section 7. Specification languages are platform-level entities: they are not owned by an organisation or a workspace, they are registered once, and everything else refers to them."
]

UseCase uc_AssignLanguageMaintainer "Name or remove a language maintainer" : EntityUpdate [
    stakeholder stk_PlatformAdministration
    primaryActor a_PlatformAdministrator
    dataEntity e_LanguageMaintainer
    precondition "The actor holds the administrator profile."
    postcondition "The set of maintainers of the family is changed; maintainers are shared by all of its versions."
    priority Medium
    description "Section 7. The assignment and removal of maintainers are reserved to the platform administrator."
]

UseCase uc_RegisterLanguageVersion "Register a language version" : EntityCreate [
    stakeholder stk_LanguageCustodian
    primaryActor a_LanguageMaintainer
    supportingActor a_PlatformAdministrator
    dataEntity e_LanguageVersion
    precondition "The actor maintains the family or holds the administrator profile."
    postcondition "The version exists in the draft state, belonging to exactly one family, with a version label, a description, the file extensions its specifications use, and references to the documentation, the grammar, and any external parser."
    priority High
    description "Section 7. Every version is created as a draft."
]

UseCase uc_EditLanguageVersionMetadata "Edit the metadata of a language version" : EntityUpdate [
    stakeholder stk_LanguageCustodian
    primaryActor a_LanguageMaintainer
    supportingActor a_PlatformAdministrator
    dataEntity e_LanguageVersion
    precondition "The actor maintains the family. The name and the acronym are excluded: only an administrator may change those."
    postcondition "The metadata is changed; the state is untouched, because there is no way to set a version state directly."
    priority Medium
    description "Section 7. Attempting to write the state outside publication is refused with an explicit message."
]

UseCase uc_EditGrammarFile "Author the grammar of a version" : EntityUpdate [
    stakeholder stk_LanguageCustodian
    primaryActor a_LanguageMaintainer
    dataEntity e_GrammarFile
    precondition "The version is in the draft state. A request to alter a grammar file of a version that is not in draft is refused even when it is made directly, and the same applies to every mutating action of the grammar editor."
    postcondition "The grammar file set is changed and any recorded validation is marked out of date."
    priority High
    description "Section 7. A version grammar is a set of files that may import one another, edited in the browser. Exactly one of them is the entry file. Files are constrained to plain relative paths, must carry the extension appropriate to their kind, must be valid text, and are bounded in size."
]

UseCase uc_ValidateGrammar "Validate the grammar of a version" : EntityOther [
    stakeholder stk_LanguageCustodian
    primaryActor a_LanguageMaintainer
    dataEntity e_GrammarValidationResult
    precondition "The version carries a grammar."
    postcondition "A result is stored with a fingerprint of the text validated; the version state is unchanged."
    priority High
    description "Section 7. Validation first assembles the grammar by inlining the imports, rejecting import cycles, imports that resolve to nothing, and imports that leave the file set, and then checks the assembled text. Only errors make a grammar invalid; warnings and hints are reported without blocking. The result is marked out of date the moment any file of the set changes."
]

UseCase uc_EditServicesFile "Author the custom services of a version" : EntityUpdate [
    stakeholder stk_LanguageCustodian
    primaryActor a_LanguageMaintainer
    dataEntity e_ServicesFile
    precondition "The version is in the draft state."
    postcondition "The services file set is changed, the artefact is rebuilt, and every creation, change of content, and deletion is written to the immutable audit trail."
    priority Medium
    description "Section 7. Custom language services let a version carry behaviour a grammar cannot express, such as how names are computed, how references are resolved across files, and what additional rules a specification must satisfy. Failures are reported as diagnostics beside the grammar own rather than blocking the save; only publication insists on a successful, current build. Merely enabling or disabling a services file neither rebuilds the artefact nor leaves a trace in the audit trail. Exactly one services file is the entry file."
]

UseCase uc_ExchangeLanguageFiles "Export and re-import the files of a version" : EntitiesInteropSync [
    stakeholder stk_LanguageCustodian
    primaryActor a_LanguageMaintainer
    supportingActor a_PlatformAdministrator
    dataEntity e_LanguageVersion
    precondition "The actor maintains the family or holds the administrator profile. Downloading the grammar and services files, individually or as a set, is restricted to the administrator and the family maintainers."
    postcondition "The grammar and services files are exported as a set, or replaced from a set."
    priority Low
    description "Section 7. Every file of a version may also be downloaded together, but the remaining kinds are replaced one at a time. The grammar and services files themselves are not public merely because the metadata is."
]

UseCase uc_PublishLanguageVersion "Publish a language version" : EntityUpdate [
    stakeholder stk_PlatformAdministration
    primaryActor a_PlatformAdministrator
    dataEntity e_LanguageVersion
    precondition "The version is in draft or in the deprecated state, its grammar carries a current and successful validation that the platform re-runs itself at publication time, and any custom services have a current successful build."
    postcondition "The version is in force, the version of the same family that was active becomes deprecated, and the identity of the publisher, the moment of publication, and a fingerprint of what was published are recorded."
    priority High
    description "Section 7. The only transition a user performs is publication, reserved to the platform administrator. There is no separate action for deprecating a version. The division is deliberate: a language team prepares and validates a version, and the platform decides what comes into force, because a version in force changes the behaviour of the editor, of generation, and of the chatbot for every user of the platform."
]

UseCase uc_CreateDraftFromVersion "Create a new draft from an existing version" : EntityCreate [
    stakeholder stk_LanguageCustodian
    primaryActor a_LanguageMaintainer
    dataEntity e_LanguageVersion
    precondition "A source version of the family exists."
    postcondition "A new draft version exists, copying the metadata and every file of its source, leaving the source untouched, and proposed a version label derived from the source."
    priority Medium
    description "Section 7. Iteration happens by creating a new draft from an existing version."
]

UseCase uc_WithdrawLanguageFamily "Withdraw a language family" : EntityUpdate [
    stakeholder stk_PlatformAdministration
    primaryActor a_PlatformAdministrator
    dataEntity e_LanguageFamily
    precondition "The actor holds the administrator profile."
    postcondition "All versions of the family are hidden at once and their entries leave the knowledge pool."
    priority Low
    description "Section 7. Withdrawing a language altogether is done at the level of the family; there is no way to archive a single version."
]

UseCase uc_BrowseLanguageCatalogue "Browse the language catalogue" : EntitiesBrowse [
    stakeholder stk_Visitor
    primaryActor a_Visitor
    supportingActor a_RegisteredUser
    supportingActor a_LanguageMaintainer
    supportingActor a_PlatformAdministrator
    dataEntity ec_Language
    precondition "None: the catalogue of languages is public."
    postcondition "Nothing changes."
    priority Medium
    description "Section 7. A visitor and an ordinary user see the versions in force of families that have not been withdrawn; a maintainer additionally sees the versions of the families they maintain, including drafts; an administrator sees everything."
]

UseCase uc_SelectAvailableLanguages "Declare the available languages" : EntityUpdate [
    stakeholder stk_ContainerManager
    primaryActor a_OrganisationManager
    supportingActor a_WorkspaceManager
    dataEntity e_LanguageSelection
    precondition "The actor manages the organisation or the workspace concerned."
    postcondition "The set of available languages is recorded; the platform refuses a workspace selection that falls outside its organisation selection or a default that is not among the workspace available languages."
    priority Low
    description "Section 7. An organisation may declare which languages are available to it, and a workspace may narrow that set further and nominate a default."
]

UseCase uc_LaunchEditor "Launch the editor from a workspace" : EntitiesInteropExport [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceMember
    supportingActor a_WorkspaceManager
    supportingActor a_WorkspaceDocumentManager
    supportingActor a_Visitor
    supportingActor a_SpecificationEditor
    dataEntity e_EditorSession
    precondition "The actor holds an accepted role in the workspace, or the workspace is public. A user who holds no accepted role never reaches the launch action at all, because the specifications page itself refuses access before rendering. A launch naming a workspace that does not exist, and a public launch naming a workspace that is not public, both end in a not-found response."
    postcondition "The editor opens in a new browser tab with an encrypted session description stating the identity of the user, the name and identifier of the workspace, the name of the owning organisation, and whether the session may write."
    priority High
    description "Section 8. The page states, before the user commits to anything, whether the session that will open is writable or read-only. The write flag is set from the user workspace role and is true only for a workspace manager or a workspace document manager; a launch from the public view of a public workspace is always read-only, whoever performs it. The platform does not contact the editor when launching; it merely redirects, so an editor that is unavailable produces the new tab own connection error and the platform says nothing about it."
]

UseCase uc_ImportDocumentsIntoEditor "Import platform documents into the editor" : EntitiesInteropImport [
    stakeholder stk_EditorProduct
    primaryActor a_SpecificationEditor
    supportingActor a_WorkspaceMember
    dataEntity ec_Document
    precondition "The editor presents a valid session description for the workspace."
    postcondition "The selected documents are downloaded into the editing workspace."
    priority Medium
    description "Section 8. The editor asks the platform for the documents of the workspace and of its organisation, receiving for each the file name, the display title, and whether it comes from the workspace or the organisation. Three kinds of document are withheld: templates, documents whose extension is not among those the platform admits for import, and documents that carry no file at all."
]

UseCase uc_RequestSpecificationCorpus "Request the specification corpus of a workspace" : EntitiesInteropExport [
    stakeholder stk_EditorProduct
    primaryActor a_SpecificationEditor
    dataEntity ec_Document
    precondition "The editor presents a valid session description and names one language family within the workspace it is serving."
    postcondition "The corpus is returned together with a report of any duplicate package names it contains."
    priority Low
    description "Section 8. The corpus lets imports between specification files resolve during editing."
]

UseCase uc_ValidateEditorCallback "Validate a call back from the editor" : EntitiesInteropServiceInvocation [
    stakeholder stk_Platform
    primaryActor a_SpecificationEditor
    dataEntity e_EditorSession
    precondition "The editor calls back to the platform presenting a session description."
    postcondition "The call is accepted, or refused with a stated reason distinguishing a missing or unusable session description, a description carrying no workspace, a workspace that does not match the one requested, a workspace that does not exist, and an absence of access to it."
    priority Medium
    description "Section 8. How those reasons are shown to the user is the editor affair."
]

UseCase uc_SupplyLanguagesToEditor "Supply the languages to the editor" : EntitiesInteropExport [
    stakeholder stk_Platform
    primaryActor a_SpecificationEditor
    dataEntity ec_Language
    precondition "The editor asks the platform for the languages whenever it needs them, rather than receiving a deployment."
    postcondition "For each supplied language the editor receives the assembled grammar text, the registered file extensions, a fingerprint of the content, and the built services artefact."
    priority High
    description "Section 7. Only versions that carry a grammar are supplied, and of those the versions in force, the versions in preparation, and the superseded versions whose family has neither. Because the catalogue is read at the moment it is needed, a newly published version reaches the editor without any redeployment."
]

UseCase uc_ConverseInWorkspace "Converse in a workspace" : EntitiesInteropSendMessage [
    stakeholder stk_Practitioner
    primaryActor a_WorkspaceMember
    supportingActor a_Visitor
    supportingActor a_Chatbot
    dataEntity e_ChatSession
    precondition "The user is on the chat section of a workspace hub or on the equivalent page of a public workspace. The public page refuses a workspace that is not public, and a signed-in member arriving at the public page is redirected to their own view of the workspace."
    postcondition "A conversation proceeds in the context of that one workspace, governed by a session statement valid for one hour and marked read-only unless the user holds an accepted workspace manager or document manager role."
    priority High
    description "Section 9. Conversation happens beside the work it concerns: there is no organisation-level and no platform-level conversation. The member page does not itself check membership; what a signed-in user may do there is decided by the session statement. The chatbot consults the knowledge pool rather than receiving it: the text of every document marked as grounding knowledge, scoped to its owner, and the grammars, validation files, examples, and specification files of the languages currently in force. When the chatbot cannot be reached, the platform reports nothing, because it never probes the chatbot before rendering."
]

UseCase uc_ExportGeneratedSpecification "Export a generated specification into a workspace" : EntitiesInteropImport [
    stakeholder stk_ChatbotProduct
    primaryActor a_Chatbot
    supportingActor a_WorkspaceManager
    supportingActor a_WorkspaceDocumentManager
    dataEntity ec_Interaction
    precondition "The chatbot presents the session statement as its credential, the workspace named matches the one the statement was issued for, the content is present and not above one megabyte, the file name is present and valid, any named language is currently in force, the extension is one the platform admits for import, and the user write permission re-derived from their current workspace role allows writing."
    postcondition "An ordinary workspace document is created in the draft state, attributed to that user as its creator, with its file name made unique against the workspace existing documents by appending a counter."
    priority High
    description "Section 9. The platform re-derives the user write permission from their current workspace role rather than relying on the read-only flag the statement carries. When a language is named, the file receives that language registered extension whatever the conversation proposed. From that point the exported content is indistinguishable from an uploaded document: it enters the lifecycle at draft, obeys the same roles and visibility, and becomes available to the editor import on the next launch of that workspace. A refused export is reported with the reason named rather than left to be guessed."
    extensionPoints epExportRefused ["The request is refused and the reason is named, or a fault of the platform is reported when no shared secret has been configured."]
]

UseCase uc_DeliverToEditorSession "Deliver exported content to a live editing session" : EntitiesInteropSendMessage [
    stakeholder stk_Platform
    primaryActor a_SpecificationEditor
    supportingActor a_Chatbot
    dataEntity e_ExportResult
    precondition "A document has just been created by an accepted export."
    postcondition "The delivery is made, or not made with a stated reason; either way the document survives, because the two operations are deliberately not tied together."
    priority Medium
    description "Section 9. The platform additionally attempts to deliver the same content into a live editing session, so that refinement can begin without relaunching the editor and importing the file. The document is the system of record. The reasons distinguish an integration that is not configured, a timeout, an unreachable editor, an editor lacking the delivery capability, a delivery rejected as unauthorised, another error returned by the editor, and an answer that could not be interpreted; when the editor supplies a reason of its own, that reason is passed on in place of the last but one."
    extensionPoints epDeliveryNotMade ["The delivery is not made and a stated reason is carried beside the created document."]
]

UseCase uc_ConfigureAssistanceCatalogue "Configure the organisation assistance catalogue" : EntitiesManage [
    stakeholder stk_ContainerManager
    primaryActor a_OrganisationManager
    supportingActor a_AssistanceEngine
    dataEntity ec_Assistance
    precondition "The actor holds the accepted organisation manager role: every action on the configuration section refuses a user holding any other role. The section appears in the organisation hub only when the conversational part of the system is present."
    postcondition "The organisation own catalogue of providers and engines is changed; the entries an organisation registers are its own."
    priority Medium
    description "Section 10. Assistance is governed per organisation because organisations differ in which providers their policies and budgets permit, in whether they may send content to a hosted service at all, and in the vocabulary and instructions appropriate to their work. Credentials are held under names the platform composes from the organisation, the provider, and the engine, so two organisations configuring the same provider can never collide. Changing an engine arrangement clears the credentials belonging to the arrangement abandoned. Editing an engine with the key field left empty keeps the key already stored."
]

UseCase uc_AssignEngineRoles "Assign the engine roles" : EntityUpdate [
    stakeholder stk_ContainerManager
    primaryActor a_OrganisationManager
    dataEntity e_EngineRoleAssignment
    precondition "The actor holds the accepted organisation manager role, and the engine belongs to the organisation own catalogue."
    postcondition "Each of the nine roles holds one engine of the organisation catalogue, or remains unassigned; an assignment naming anything else is cleared rather than stored."
    priority Medium
    description "Section 10. Nine roles are assignable: a default, an engine for answering from the knowledge pool, one for generating diagrams, one for interpreting images, and one for each of the five phases of specification generation. A newly created organisation begins with every role unassigned, and nothing on the platform requires them to be filled before conversation is possible."
]

UseCase uc_EditInstructionBlock "Edit the organisation instruction block" : EntityUpdate [
    stakeholder stk_ContainerManager
    primaryActor a_OrganisationManager
    dataEntity e_InstructionBlock
    precondition "The actor holds the accepted organisation manager role."
    postcondition "The organisation block holds the saved text, or, after a revert, no text of its own, so that the platform organisation-level text serves as the fallback again."
    priority Low
    description "Section 10. The platform block is editable only by the administrator. Until an organisation saves a block of its own, its page presents the platform organisation-level text as the starting point, and reverting restores that same fallback."
]

UseCase uc_MaintainPlatformAssistanceDefaults "Maintain the platform assistance defaults" : EntitiesManage [
    stakeholder stk_PlatformAdministration
    primaryActor a_PlatformAdministrator
    dataEntity ec_Assistance
    precondition "The actor holds the administrator profile and works through the administrative interface."
    postcondition "The platform-wide catalogue, the platform defaults, and the platform instruction block are changed."
    priority Low
    description "Sections 10 and 12. The administrator owns the platform-wide assistance settings: the catalogue of providers and engines that serves as the platform default, the default assignment of each engine role, and the platform instruction block that precedes every organisation own. These are edited through the administrative interface rather than through any organisation configuration page."
]

UseCase uc_ReadNotifications "Read the notifications" : EntitiesBrowse [
    stakeholder stk_Practitioner
    primaryActor a_RegisteredUser
    dataEntity ec_Notification
    precondition "The actor is signed in. Every action is restricted to the notifications of the user performing it."
    postcondition "Notifications are read, marked read, or answered; a user sees only their own notifications, and the administrator sees all of them."
    priority Medium
    description "Section 11. A bell in the site header shows the number of unread notifications and the ten most recent of them, and offers to answer an invitation or mark a notification read without leaving the page. A full list page shows every notification, newest first, with paging, an action to mark all of them read, and, for an invitation still awaiting an answer, the accept and reject actions themselves."
]

UseCase uc_NotifyMembershipEvent "Notify a membership event" : EntityOther [
    stakeholder stk_Platform
    primaryActor a_RegisteredUser
    dataEntity e_Notification
    precondition "One of the six membership events occurs."
    postcondition "A notification reaches the invited user, or every accepted manager of the affected container, and, for the two events that create an invitation, an email is queued when the invited user has an email address on record."
    priority Medium
    description "Section 11. No document, language, editor, or conversation event produces a notification. Ordinary members and document managers are not told when someone accepts or rejects an invitation; only the managers of the affected container are. The message is queued rather than sent at once, so its arrival is not simultaneous with the in-platform notification, and acceptances and rejections produce no email at all."
]

UseCase uc_ViewActivityRecord "View the activity record" : EntityRead [
    stakeholder stk_Practitioner
    primaryActor a_OrganisationMember
    supportingActor a_WorkspaceMember
    dataEntity e_ActivityMessage
    precondition "The viewer may see the container."
    postcondition "Nothing changes."
    priority Low
    description "Section 11. Organisations, workspaces, and documents each carry a history of the changes made to their tracked attributes, and accepting or rejecting an invitation posts a corresponding message on the organisation or workspace concerned, so the membership history of a container can be read from the container itself. Creating an invitation also schedules a task for the invited user, which reaches them through the platform own activity mechanism in addition to the notification."
]

UseCase uc_ManageUserAccounts "Manage the user accounts" : EntitiesManage [
    stakeholder stk_PlatformAdministration
    primaryActor a_PlatformAdministrator
    dataEntity e_User
    precondition "The actor reaches the administrative interface and holds the general settings permission of the underlying account system, which the administrator profile does not itself confer, although in practice the same accounts hold both."
    postcondition "Users are viewed, edited, or deleted, and the platform profile each user holds is assigned."
    priority Medium
    description "Section 12. Account management is the one item of platform administration the platform own access rules do not govern."
]

UseCase uc_SuspendOrganisation "Suspend or reactivate an organisation" : EntityUpdate [
    stakeholder stk_PlatformAdministration
    primaryActor a_PlatformAdministrator
    dataEntity e_Organisation
    precondition "The actor holds the administrator profile and works through the administrative interface."
    postcondition "The organisation is suspended or active again."
    priority Low
    description "Sections 2, 3, and 12. Suspending an organisation and reactivating it are not offered anywhere in the portal and are performed through the administrative interface."
]

UseCase uc_OverseeEveryRecord "Oversee every record on the platform" : EntitiesBrowse [
    stakeholder stk_PlatformAdministration
    primaryActor a_PlatformAdministrator
    dataEntity ec_Organisation
    precondition "The actor holds the administrator profile."
    postcondition "Nothing is hidden: every organisation, workspace, membership, document, language version, and notification is visible and actionable."
    priority Medium
    description "Section 12. The administrator is the only actor with unrestricted sight, whereas every other profile sees only the containers in which it holds an accepted role. None of the administrator capabilities is delegable through an organisation or workspace role."
]

UseCase uc_ConfigureEditorIntegration "Configure the integration with the editor" : EntityUpdate [
    stakeholder stk_PlatformAdministration
    primaryActor a_PlatformAdministrator
    dataEntity e_EditorIntegrationSetting
    precondition "The actor holds the administrator profile and works through the administrative interface."
    postcondition "The editor address, the shared secret, the lifetime of the separately issued access credentials, and the general-purpose file extensions admitted for import are recorded."
    priority Medium
    description "Section 12. The extensions of every language version in force or in preparation are admitted automatically and are not listed there, a draft under its distinguishing suffix; a superseded version contributes its extension as well, but only for as long as its family holds no version in force and none in preparation. The setting is consequential beyond administration, because the admitted extensions determine which documents the editor is offered and which files a conversation may deposit in a workspace."
]

/****************************************************
   Application structure (Sections 1 to 12)
*****************************************************/

AppModule m_PublicWebsite "Public website" : Application [
    contains c_PublicWeb
    feature f_PublicSurface [ realizes uc_BrowsePublicSurface description "Section 2. The home page, the terms and conditions, the catalogue of specification languages, and the list of public workspaces." ]
    feature f_PublicWorkspaceView [ realizes uc_ViewPublicWorkspace description "Section 4. A reduced workspace hub offering no control that changes anything." ]
    description "Section 1. The platform is reached through a public website and an authenticated portal."
]

AppModule m_Portal "Authenticated portal" : Application [
    contains c_PortalWeb
    dependsOn m_OrganisationDomain
    dependsOn m_WorkspaceDomain
    dependsOn m_DocumentDomain
    feature f_OrganisationHub [ realizes uc_ViewOrganisationHub description "Section 3. A fixed set of sections reached from a sidebar: home, workspaces, documents, users, assistance configuration, and settings." ]
    feature f_WorkspaceHub [ realizes uc_ViewWorkspaceHub description "Section 4. Six sections: home, documents, specifications, chat, users, and settings." ]
    description "Section 1. Where organisations, workspaces, documents, and languages live for a signed-in user."
]

AppModule m_OrganisationDomain "Organisations" : Domain [
    contains c_PlatformBackend
    feature f_OrganisationMembership [ realizes uc_InviteOrganisationMember description "Section 3. Membership grows only by invitation; there is no way for a user to request admission." ]
    feature f_RoleCascade [ realizes uc_AnswerOrganisationInvitation description "Section 2. An accepted organisation manager role grants workspace management across every workspace the organisation holds at that moment, and is not applied again afterwards." ]
    description "Section 3. Organisations, their role assignments, and the invitations recorded for addresses that hold no account."
]

AppModule m_WorkspaceDomain "Workspaces" : Domain [
    contains c_PlatformBackend
    dependsOn m_OrganisationDomain
    feature f_WorkspaceCreation [ realizes uc_CreateWorkspace description "Section 4. A guided sequence of four steps: identity, dates, description, and review." ]
    feature f_WorkspaceProgress [ realizes uc_ChangeWorkspaceProgress description "Section 4. A progress state independent of any document lifecycle, presented rather than enforced." ]
    description "Section 4. Workspaces, their membership, their progress, and their public listing."
]

AppModule m_DocumentDomain "Specification documents" : Domain [
    contains c_PlatformBackend
    dependsOn m_WorkspaceDomain
    feature f_DocumentLifecycle [ realizes uc_SetDocumentState description "Section 5. Five states that govern visibility rather than enforcing a workflow." ]
    feature f_GroundingKnowledge [ realizes uc_MarkGroundingKnowledge description "Section 5. A published, textual document may be marked as grounding knowledge and loses the mark automatically when it leaves published." ]
    description "Section 5. Documents belonging to a workspace or to an organisation, but never to both."
]

AppModule m_TemplateGeneration "Templates and generation" : Application [
    contains c_GenerationEngine
    dependsOn m_DocumentDomain
    dependsOn m_LanguageRegistry
    feature f_Generation [ realizes uc_GenerateFromTemplate description "Section 6. The produced file is returned directly to the browser and nothing is retained." ]
    feature f_TemplateAuthoringAids [ realizes uc_ConsultTemplateReference description "Section 6. The template reference and the advisory check compensate for lenient rendering." ]
    description "Section 6. A template is an ordinary document whose type is template, and generation is offered to anyone who may read it."
]

AppModule m_LanguageRegistry "Specification languages" : Domain [
    contains c_GrammarWorkbench
    feature f_VersionGovernance [ realizes uc_PublishLanguageVersion description "Section 7. Publication is the only transition a user performs and is reserved to the platform administrator." ]
    feature f_GrammarAuthoring [ realizes uc_EditGrammarFile description "Section 7. Grammar and services files are edited in the browser while the version is in draft." ]
    description "Section 7. Platform-level entities organised in two layers: a family carries the identity of the language, and a version carries the particulars of one release."
]

AppModule m_EditorIntegration "Editor integration" : Integration [
    contains c_PlatformBackend
    dependsOn m_LanguageRegistry
    dependsOn m_DocumentDomain
    feature f_EditorLaunch [ realizes uc_LaunchEditor description "Section 8. The platform merely redirects, carrying an encrypted session description." ]
    feature f_EditorCallbacks [ realizes uc_ValidateEditorCallback description "Section 8. Every interface carries content outward; none accepts content inward except the delivery of an exported specification." ]
    description "Section 8. The editor obtains its context by asking the platform for it, rather than receiving a deployment."
]

AppModule m_ChatbotIntegration "Chatbot integration" : Integration [
    contains c_PlatformBackend
    dependsOn m_DocumentDomain
    dependsOn m_AssistanceConfiguration
    feature f_ChatSession [ realizes uc_ConverseInWorkspace description "Section 9. Conversation happens beside one workspace, under a statement valid for one hour." ]
    feature f_SpecificationExport [ realizes uc_ExportGeneratedSpecification description "Section 9. An accepted export creates an ordinary workspace document in the draft state." ]
    description "Section 9. The chatbot is embedded in the chat section of a workspace and in the equivalent page of a public workspace, and nowhere else."
]

AppModule m_AssistanceConfiguration "Assistance configuration" : Application [
    contains c_PlatformBackend
    feature f_OrganisationCatalogue [ realizes uc_ConfigureAssistanceCatalogue description "Section 10. Each organisation maintains its own catalogue of providers and engines." ]
    feature f_EngineRoles [ realizes uc_AssignEngineRoles description "Section 10. Nine assignable roles, unassigned in a newly created organisation." ]
    description "Section 10. Assistance is governed per organisation, beside membership and documents, rather than being fixed once for the whole platform."
]

AppModule m_NotificationsAndActivity "Notifications and activity" : Application [
    contains c_NotificationWorker
    feature f_MembershipNotifications [ realizes uc_NotifyMembershipEvent description "Section 11. Six events produce a notification, and all six concern membership." ]
    description "Section 11. Notifications in the site header and in a full list page, beside an activity record kept on each container."
]

AppModule m_Administration "Platform administration" : Application [
    contains c_AdministrativeInterface
    feature f_AdministrativeOversight [ realizes uc_OverseeEveryRecord description "Section 12. The administrator is the only actor with unrestricted sight." ]
    description "Section 12. A small set of capabilities belonging to the platform administrator alone, none of them delegable through an organisation or workspace role."
]

AppModule m_KnowledgePool "Knowledge pool" : Shared [
    contains c_KnowledgePoolWorker
    dependsOn m_LanguageRegistry
    dependsOn m_DocumentDomain
    description "Sections 5, 7 and 9. The pool the chatbot consults rather than receives: the text of documents marked as grounding knowledge and the files of the languages currently in force."
]

AppComponent c_PublicWeb "Public website" : Web [
    provides s_WorkspaceService
    provides s_LanguageService
    description "Section 2 and Section 4. Serves the home page, the terms and conditions, the language catalogue, the public workspace listing, and the reduced public workspace hub."
]

AppComponent c_PortalWeb "Authenticated portal" : Web [
    provides s_OrganisationService
    provides s_WorkspaceService
    provides s_DocumentService
    provides s_NotificationService
    dependsOn c_PlatformBackend
    description "Sections 3 to 5 and 11. The organisation hub, the workspace hub, the document pages, and the notifications."
]

AppComponent c_AdministrativeInterface "Administrative interface" : Web [
    provides s_AdministrationService
    dependsOn c_PlatformBackend
    description "Section 12. Account management, organisation suspension, workspace progress reset, language publication, the platform assistance defaults, and the editor integration setting."
]

AppComponent c_PlatformBackend "Platform backend" : Backend [
    provides s_OrganisationService
    provides s_WorkspaceService
    provides s_DocumentService
    provides s_EditorIntegrationService
    provides s_ChatIntegrationService
    provides s_AssistanceConfigurationService
    config editorAddress : URL [ required False description "Section 12. The address at which the editor is reached." ]
    config credentialLifetime : Integer [ required False description "Section 12. The lifetime of the separately issued access credentials." ]
    config genericExtensions : String [ required False description "Section 12. The general-purpose file extensions admitted for import in addition to those the registered languages contribute." ]
    description "Section 1. The platform is the authority: it decides who may read and write what, and both the editor and the chatbot receive their working context from it."
]

AppComponent c_GenerationEngine "Generation engine" : Backend [
    provides s_TemplateService
    dependsOn c_GrammarWorkbench
    description "Section 6. Resolves imports, parses the assembled specification, exposes it through a uniform structure, and renders leniently."
]

AppComponent c_GrammarWorkbench "Grammar workbench" : Backend [
    provides s_LanguageService
    description "Section 7. Assembles a grammar by inlining its imports, checks the assembled text, and rebuilds the custom services artefact on every change of content."
]

AppComponent c_KnowledgePoolWorker "Knowledge pool worker" : Worker [
    dependsOn c_PlatformBackend
    description "Sections 5, 7 and 9. Adds and withdraws pool entries as documents leave the published state and as language versions come into and out of force."
]

AppComponent c_NotificationWorker "Notification worker" : Worker [
    provides s_NotificationService
    dependsOn c_PlatformBackend
    description "Section 11. Raises the six membership notifications and queues the two invitation emails rather than sending them at once."
]

AppService s_OrganisationService "Organisation service" : Application [
    interface "OrganisationApplicationService"
    transaction Required
    authorization ap_OrganisationRBAC
    realizes uc_CreateOrganisation
    operation createOrganisation "Create an organisation" : Command [
        parameter organisationName : String [ location Input required True ]
        parameter activityType : enum OrganisationActivityType [ location Input required True ]
        parameter country : String [ location Input required False ]
        returns entity e_Organisation
        postcondition "creator holds an accepted organisation manager role"
        description "Section 3. Any authenticated user may create an organisation at any time and becomes its accepted organisation manager at the moment of creation."
    ]
    operation editOrganisationSettings "Edit the organisation settings" : Command [
        parameter organisationRef : entity e_Organisation [ location Input required True ]
        returns entity e_Organisation
        authorization ap_OrganisationRBAC
        description "Section 3. Only the name, the activity type, and the country may be changed from the portal."
    ]
    operation inviteOrganisationMember "Invite a person" : Command [
        parameter invitedAddress : Email [ location Input required True ]
        parameter offeredRole : enum OrganisationRoleType [ location Input required True ]
        returns entity e_OrganisationRole
        idempotent True
        description "Section 3. When the address belongs to an existing account a pending role assignment is created; when it does not, the invitation is recorded and the message resent rather than the record duplicated."
    ]
    operation answerOrganisationInvitation "Answer an invitation" : Command [
        parameter organisationRoleRef : entity e_OrganisationRole [ location Input required True ]
        parameter accepted : Boolean [ location Input required True ]
        returns entity e_OrganisationRole
        postcondition "response time stamped and a message posted on the organisation history"
        description "Section 3. Acceptance of the organisation manager role cascades workspace management across the organisation."
    ]
    operation changeOrganisationRole "Change a member role" : Command [
        parameter organisationRoleRef : entity e_OrganisationRole [ location Input required True ]
        parameter newRole : enum OrganisationRoleType [ location Input required True ]
        returns entity e_OrganisationRole
        error LastManagerProtected status 409 description "The last accepted organisation manager can neither be demoted nor removed."
    ]
    operation removeOrganisationMember "Remove a member" : Command [
        parameter organisationRoleRef : entity e_OrganisationRole [ location Input required True ]
        returns Boolean
        error LastManagerProtected status 409 description "The last accepted organisation manager can neither be demoted nor removed."
    ]
    operation leaveOrganisation "Leave the organisation" : Command [
        parameter organisationRef : entity e_Organisation [ location Input required True ]
        returns Boolean
        error WorkspacesStillReference status 409 description "A sole member cannot delete the organisation by leaving while workspaces still reference it."
        error SuccessorRequired status 409 description "The last accepted manager among other members must promote a successor first."
        description "Section 3. Three outcomes are possible: the organisation is deleted, a successor is promoted and the departure carried out together with the promotion, or the membership is simply removed."
    ]
    operation deleteOrganisation "Delete the organisation" : Command [
        parameter organisationRef : entity e_Organisation [ location Input required True ]
        returns Boolean
        error WorkspacesStillReference status 409 description "Deletion follows the same workspace restriction as leaving."
    ]
    operation viewOrganisationHub "View the organisation hub" : Query [
        parameter organisationRef : entity e_Organisation [ location Input required True ]
        returns entity ec_Organisation
        transaction ReadOnly
        description "Section 3. The home summarises the organisation in grouped counts, each count linking to the corresponding filtered list; document counts are restricted to the published state for members who hold no editing role."
    ]
]

AppService s_WorkspaceService "Workspace service" : Application [
    interface "WorkspaceApplicationService"
    transaction Required
    authorization ap_WorkspaceRBAC
    realizes uc_CreateWorkspace
    operation createWorkspace "Create a workspace" : Command [
        parameter workspaceName : String [ location Input required True ]
        parameter organisationRef : entity e_Organisation [ location Input required False ]
        parameter isPublic : Boolean [ location Input required True ]
        returns entity e_Workspace
        postcondition "the workspace holds a stable key of its own and the creator an accepted workspace manager role"
        description "Section 4. A guided sequence of four steps: identity, dates, description, and review. A workspace references at most one organisation and the reference is optional."
    ]
    operation editWorkspaceSettings "Edit the workspace settings" : Command [
        parameter workspaceRef : entity e_Workspace [ location Input required True ]
        returns entity e_Workspace
        description "Section 4. The settings section reuses the four steps of creation, each step saving as it is left."
    ]
    operation changeWorkspaceProgress "Change the progress" : Command [
        parameter workspaceRef : entity e_Workspace [ location Input required True ]
        parameter newProgress : enum WorkspaceProgressState [ location Input required True ]
        returns entity e_Workspace
        description "Section 4. Starting records the actual start date and concluding records the actual end date. No transition examines the state a workspace is in before writing the new one."
    ]
    operation listPublicWorkspaces "List the public workspaces" : Query [
        returns entity e_Workspace
        transaction ReadOnly
        description "Section 4. A public listing anyone may browse and filter by name, organisation, and progress state."
    ]
    operation inviteWorkspaceMember "Invite a person" : Command [
        parameter invitedAddress : Email [ location Input required True ]
        parameter offeredRole : enum WorkspaceRoleType [ location Input required True ]
        returns entity e_WorkspaceRole
        idempotent True
    ]
    operation answerWorkspaceInvitation "Answer an invitation" : Command [
        parameter workspaceRoleRef : entity e_WorkspaceRole [ location Input required True ]
        parameter accepted : Boolean [ location Input required True ]
        returns entity e_WorkspaceRole
        description "Section 2. A user who accepts a workspace role and has no role at all in the workspace organisation receives an accepted organisation member role there."
    ]
    operation leaveWorkspace "Leave the workspace" : Command [
        parameter workspaceRef : entity e_Workspace [ location Input required True ]
        returns Boolean
        error SuccessorRequired status 409 description "The last accepted manager among other members must promote a successor first."
        description "Section 4. A workspace is never left without members: when its sole accepted member leaves, the workspace is deleted together with whatever it still contains."
    ]
    operation deleteWorkspace "Delete the workspace" : Command [
        parameter workspaceRef : entity e_Workspace [ location Input required True ]
        returns Boolean
    ]
]

AppService s_DocumentService "Document service" : Application [
    interface "DocumentApplicationService"
    transaction Required
    realizes uc_CreateDocument
    operation createDocument "Create a document" : Command [
        parameter documentName : String [ location Input required True ]
        parameter documentTypeRef : enum DocumentTypeValue [ location Input required True ]
        parameter attachedFile : File [ location Input required False ]
        returns entity e_Document
        error BelongsToBothScopes status 400 description "A document belongs either to a workspace or to an organisation, and the platform refuses to let it belong to both."
        error LanguageVersionWithoutFamily status 400 description "Naming a version without its family, or a version belonging to a different family, is refused."
        description "Section 5. The name is the only attribute the platform requires; the version label is free text with an initial value of 1.0."
    ]
    operation editDocument "Edit a document" : Command [
        parameter documentRef : entity e_Document [ location Input required True ]
        returns entity e_Document
        description "Section 5. Editing replaces the stored file and the version label in place, and the platform keeps no prior copy. A file exchanged without any other edit leaves no history entry at all."
    ]
    operation deleteDocument "Delete a document" : Command [
        parameter documentRef : entity e_Document [ location Input required True ]
        returns Boolean
        description "Section 5. Deletion is permanent and is not an archive."
    ]
    operation setDocumentState "Set the document state" : Command [
        parameter documentRef : entity e_Document [ location Input required True ]
        parameter newState : enum DocumentState [ location Input required True ]
        returns entity e_Document
        postcondition "a document leaving the published state loses any grounding knowledge mark and its text leaves the pool"
        description "Section 5. Any of the five values may be chosen from any other; the state governs visibility rather than enforcing a workflow."
    ]
    operation markGroundingKnowledge "Mark as grounding knowledge" : Command [
        parameter documentRef : entity e_Document [ location Input required True ]
        parameter marked : Boolean [ location Input required True ]
        returns entity e_Document
        precondition "the document is published and its file is textual and is not a template"
        error NotPublished status 409 description "The mark may be applied only while the document is in the published state."
        error NotTextual status 409 description "The mark may be applied only when the file is a generic text format or a format registered by a specification language."
        error TemplateNeverMarked status 409 description "Templates may never be marked."
    ]
    operation browseDocuments "Browse and download documents" : Query [
        parameter scopeRef : String [ location Input required True ]
        returns entity ec_Document
        transaction ReadOnly
        authorization ap_PublishedOnlyVisibility
        description "Section 5. The listings, the counts, and the document pages are all restricted to the published state for members holding no editing role."
    ]
    operation viewDocumentHistory "View the change history" : Query [
        parameter documentRef : entity e_Document [ location Input required True ]
        returns entity e_DocumentChangeEntry
        transaction ReadOnly
        description "Section 5. The history covers alterations to the name, state, version, type, and language associations, but not the content that was replaced and not the replacement of the file itself."
    ]
]

AppService s_TemplateService "Template and generation service" : Application [
    interface "TemplateGenerationService"
    realizes uc_GenerateFromTemplate
    operation generateDocument "Generate from a template" : Command [
        parameter templateRef : entity e_Template [ location Input required True ]
        parameter uploadedSpecification : File [ location Input required True ]
        parameter targetVersionRef : entity e_LanguageVersion [ location Input required False ]
        returns File
        transaction ReadOnly
        error VersionNotReady status 409 description "The version is neither in force nor in preparation."
        error NoGrammar status 409 description "The version carries no grammar."
        error GrammarNotValidated status 409 description "The grammar has not been validated."
        error ValidationStale status 409 description "The recorded validation no longer matches the grammar."
        error PublishedMismatch status 409 description "A version in force no longer matches the grammar recorded when it was published."
        error ServicesBuildUnusable status 409 description "The version declares custom services whose build is missing, failed, or out of date."
        error UnregisteredExtension status 400 description "The upload must carry an extension the target language registers."
        error ImportUnresolved status 400 description "An import matched nothing; the importing file and the line are named."
        error ImportAmbiguous status 400 description "An import matched more than one candidate; the contested declaration and the documents that declare it are named."
        description "Section 6. The produced file is returned directly to the browser: no document is created and nothing is retained, so generation leaves the workspace unchanged. A text template declaring several named output sections produces each of them and delivers the set as a single archive."
    ]
    operation resolveImports "Resolve the declared imports" : Query [
        parameter uploadedSpecification : File [ location Input required True ]
        returns Text
        transaction ReadOnly
        description "Section 6. The platform searches the documents of the same language family in the same workspace or organisation, whatever their type apart from templates, and appends what it finds."
    ]
    operation consultTemplateReference "Consult the template reference" : Query [
        parameter languageFamilyRef : entity e_LanguageFamily [ location Input required True ]
        returns entity e_TemplateReference
        transaction ReadOnly
        description "Section 6. Records the entry type, every type with its fields, which types a template may iterate over, a ready-to-copy snippet for each, and a downloadable starter template, falling back to generic documentation when the description of the grammar cannot be produced."
    ]
    operation checkTemplateFragment "Check a template fragment" : Query [
        parameter checkedFragment : Text [ location Input required True ]
        returns entity e_TemplateAdvisoryCheck
        transaction ReadOnly
        description "Section 6. Reports syntax errors with their positions, unknown names with the closest matching suggestion, lookups keyed on a type the language does not define, and probable field misspellings. The check never blocks generation and never stores what it was given."
    ]
]

AppService s_LanguageService "Specification language service" : Domain [
    interface "LanguageRegistryService"
    authorization ap_LanguageGovernance
    realizes uc_PublishLanguageVersion
    operation editGrammarFile "Author a grammar file" : Command [
        parameter grammarFileRef : entity e_GrammarFile [ location Input required True ]
        returns entity e_GrammarFile
        precondition "the version is in the draft state"
        error NotDraft status 403 description "A request to alter a grammar or services file of a version that is not in draft is refused even when it is made directly."
        postcondition "any recorded validation is marked out of date"
    ]
    operation editServicesFile "Author a custom services file" : Command [
        parameter servicesFileRef : entity e_ServicesFile [ location Input required True ]
        returns entity e_ServicesFile
        precondition "the version is in the draft state"
        postcondition "the artefact is rebuilt and the creation, change of content, or deletion is written to the immutable audit trail"
        description "Section 7. Failures are reported as diagnostics beside the grammar own rather than blocking the save. Merely enabling or disabling a services file neither rebuilds the artefact nor leaves a trace."
    ]
    operation validateGrammar "Validate the grammar" : Command [
        parameter languageVersionRef : entity e_LanguageVersion [ location Input required True ]
        returns entity e_GrammarValidationResult
        error ImportCycle status 400 description "Validation rejects import cycles, imports that resolve to nothing, and imports that leave the file set."
        description "Section 7. Only errors make a grammar invalid; warnings and hints are reported without blocking. The result is stored with a fingerprint of the text validated."
    ]
    operation publishLanguageVersion "Publish a version" : Command [
        parameter languageVersionRef : entity e_LanguageVersion [ location Input required True ]
        returns entity e_LanguageVersion
        precondition "the version is in draft or deprecated and carries a current successful validation"
        postcondition "the version of the same family that was active becomes deprecated"
        error ValidationMissingOrStale status 409 description "Publication is refused for a version whose grammar was never validated, whose recorded validation no longer corresponds to the current grammar text, or whose validation found errors."
        error ServicesBuildUnusable status 409 description "A version carrying custom services must have a current, successful build of them."
        error StateWrittenDirectly status 403 description "There is no way to set a version state directly; attempting to write it outside publication is refused with an explicit message."
        description "Section 7. The platform re-runs the validation itself at publication time rather than trusting anything the browser reports, and records the identity of the publisher, the moment of publication, and a fingerprint of what was published."
    ]
    operation createDraftFromVersion "Create a draft from a version" : Command [
        parameter languageVersionRef : entity e_LanguageVersion [ location Input required True ]
        returns entity e_LanguageVersion
        description "Section 7. The new version copies the metadata and every file of its source, leaves the source untouched, and is proposed a version label derived from the source."
    ]
    operation exchangeLanguageFiles "Export and re-import the files" : Command [
        parameter languageVersionRef : entity e_LanguageVersion [ location Input required True ]
        returns File
        description "Section 7. The grammar and services files are exported and re-imported as a set; every file of a version may be downloaded together, but the remaining kinds are replaced one at a time."
    ]
    operation withdrawLanguageFamily "Withdraw a family" : Command [
        parameter languageFamilyRef : entity e_LanguageFamily [ location Input required True ]
        returns Boolean
        postcondition "all versions of the family are hidden at once and their entries leave the knowledge pool"
    ]
    operation browseLanguageCatalogue "Browse the catalogue" : Query [
        returns entity ec_Language
        transaction ReadOnly
        description "Section 7. The catalogue is public; the grammar and services files themselves are not."
    ]
    operation selectAvailableLanguages "Declare the available languages" : Command [
        parameter scopeRef : String [ location Input required True ]
        returns entity e_LanguageSelection
        error SelectionOutsideOrganisation status 400 description "The platform refuses a workspace selection that falls outside its organisation selection."
        error DefaultNotAvailable status 400 description "The platform refuses a default that is not among the workspace available languages."
    ]
    operation refreshKnowledgePool "Refresh the language knowledge" : Command [
        parameter languageVersionRef : entity e_LanguageVersion [ location Input required True ]
        returns entity e_KnowledgePoolEntry
        description "Section 7. Any change to a version or to its files refreshes the pool, and only versions in force of families that have not been withdrawn are projected into it."
    ]
]

AppService s_EditorIntegrationService "Editor integration service" : External [
    interface "EditorIntegrationService"
    authorization ap_IntegrationSessions
    realizes uc_LaunchEditor
    operation launchEditorSession "Launch the editor" : Command [
        parameter workspaceRef : entity e_Workspace [ location Input required True ]
        returns entity e_EditorSession
        error UnknownWorkspace status 404 description "A launch naming a workspace that does not exist ends in a not-found response."
        error WorkspaceNotPublic status 404 description "A public launch naming a workspace that is not public ends in a not-found response."
        description "Section 8. The page states, before the user commits to anything, whether the session that will open is writable or read-only, and the launch action opens the editor in a new browser tab. The platform does not contact the editor when launching; it merely redirects."
    ]
    operation listImportableDocuments "List the importable documents" : Query [
        parameter workspaceRef : entity e_Workspace [ location Input required True ]
        returns entity ec_Document
        transaction ReadOnly
        description "Section 8. For each document the editor receives the file name, the display title, and whether it comes from the workspace or the organisation. Templates, documents whose extension is not admitted for import, and documents that carry no file at all are withheld."
    ]
    operation requestSpecificationCorpus "Request the specification corpus" : Query [
        parameter workspaceRef : entity e_Workspace [ location Input required True ]
        parameter languageFamilyRef : entity e_LanguageFamily [ location Input required True ]
        returns Text
        transaction ReadOnly
        description "Section 8. The corpus is returned together with a report of any duplicate package names it contains, so that imports between specification files resolve during editing."
    ]
    operation validateEditorCallback "Validate a call back" : Query [
        parameter workspaceRef : entity e_Workspace [ location Input required True ]
        returns enum EditorCallbackRefusal
        transaction ReadOnly
        error MissingDescription status 401 description "A missing or unusable session description."
        error NoWorkspace status 400 description "A description carrying no workspace."
        error WorkspaceMismatch status 403 description "A workspace that does not match the one requested."
        error UnknownWorkspace status 404 description "A workspace that does not exist."
        error NoAccess status 403 description "An absence of access to the workspace."
        description "Section 8. How those reasons are shown to the user is the editor affair."
    ]
    operation supplyLanguages "Supply the languages" : Query [
        returns entity ec_Language
        transaction ReadOnly
        description "Section 7. For each language the editor receives the assembled grammar text, the registered file extensions, a fingerprint of the content, and the built services artefact. Only versions that carry a grammar are supplied, and of those the versions in force, the versions in preparation, and the superseded versions whose family has neither. Because the catalogue is read at the moment it is needed, a newly published version reaches the editor without any redeployment."
    ]
    operation deliverToLiveSession "Deliver into a live session" : Command [
        parameter workspaceRef : entity e_Workspace [ location Input required True ]
        parameter contentText : Text [ location Input required True ]
        returns enum DeliveryOutcome
        timeout 30 s
        description "Section 9. The platform attempts to deliver the exported content into a live editing session so that refinement can begin without relaunching the editor. The document is the system of record and survives a failed delivery."
    ]
]

AppService s_ChatIntegrationService "Chatbot integration service" : External [
    interface "ChatIntegrationService"
    authorization ap_IntegrationSessions
    realizes uc_ExportGeneratedSpecification
    operation issueChatSession "Issue the session statement" : Command [
        parameter workspaceRef : entity e_Workspace [ location Input required True ]
        returns entity e_ChatSession
        description "Section 9. Passed when the page is rendered: the workspace identifier and its stable key, together with a signed statement of who the user is, which organisation the workspace belongs to, and whether the session is read-only. If no shared secret has been configured, the page renders without any session statement."
    ]
    operation exportGeneratedSpecification "Export a generated specification" : Command [
        parameter chatSessionRef : entity e_ChatSession [ location Input required True ]
        parameter targetWorkspaceRef : entity e_Workspace [ location Input required True ]
        parameter contentText : Text [ location Input required True ]
        parameter proposedFileName : String [ location Input required True ]
        parameter namedLanguageRef : entity e_LanguageVersion [ location Input required False ]
        returns entity e_ExportResult
        precondition "the workspace named matches the one the statement was issued for and the write permission re-derived from the current workspace role allows writing"
        postcondition "an ordinary workspace document exists in the draft state with a file name made unique by appending a counter"
        error MissingCredential status 401 description "A missing credential."
        error UnusableCredential status 401 description "An unusable or expired credential."
        error UnreadableRequest status 400 description "A request the platform cannot read."
        error BadWorkspaceIdentifier status 400 description "A missing or invalid workspace identifier."
        error MismatchedWorkspace status 403 description "A mismatched workspace."
        error AbsentContent status 400 description "Absent content."
        error ContentTooLarge status 413 description "Content above one megabyte."
        error BadFileName status 400 description "A missing or invalid file name."
        error UnknownLanguage status 400 description "An unknown or non-current language."
        error UnknownWorkspace status 404 description "An unknown workspace."
        error UnknownUser status 404 description "An unknown user."
        error NoWriteRights status 403 description "An absence of write rights."
        error DisallowedExtension status 400 description "A disallowed extension."
        error NoSharedSecret status 500 description "No shared secret configured, which is a fault of the platform rather than of the request."
        description "Section 9. When a language is named the file receives that language registered extension whatever the conversation proposed. From that point the exported content is indistinguishable from an uploaded document."
    ]
]

AppService s_AssistanceConfigurationService "Assistance configuration service" : Application [
    interface "AssistanceConfigurationService"
    authorization ap_AssistanceConfiguration
    realizes uc_ConfigureAssistanceCatalogue
    operation configureCatalogue "Configure the catalogue" : Command [
        parameter organisationRef : entity e_Organisation [ location Input required True ]
        returns entity ec_Assistance
        postcondition "changing an engine arrangement clears the credentials belonging to the arrangement abandoned, and an empty key field keeps the key already stored"
        description "Section 10. The entries an organisation registers are its own, and credentials are held under names composed from the organisation, the provider, and the engine."
    ]
    operation assignEngineRole "Assign an engine role" : Command [
        parameter assignedRole : enum EngineRole [ location Input required True ]
        parameter engineRef : entity e_Engine [ location Input required False ]
        returns entity e_EngineRoleAssignment
        description "Section 10. An assignment naming an engine outside the organisation own catalogue is cleared rather than stored."
    ]
    operation editInstructionBlock "Edit the instruction block" : Command [
        parameter organisationRef : entity e_Organisation [ location Input required True ]
        parameter blockText : Text [ location Input required True ]
        returns entity e_InstructionBlock
    ]
    operation revertInstructionBlock "Revert the instruction block" : Command [
        parameter organisationRef : entity e_Organisation [ location Input required True ]
        returns entity e_InstructionBlock
        description "Section 10. A revert discards the organisation text entirely and restores the platform organisation-level text as the fallback."
    ]
]

AppService s_NotificationService "Notification service" : Infrastructure [
    interface "NotificationService"
    realizes uc_NotifyMembershipEvent
    operation raiseMembershipNotification "Raise a membership notification" : Command [
        parameter eventKind : enum NotificationEvent [ location Input required True ]
        returns entity e_Notification
        description "Section 11. An invitation notifies the invited user; an acceptance or a rejection notifies every accepted manager of the affected container and no one else."
    ]
    operation queueInvitationEmail "Queue an invitation email" : Command [
        parameter notificationRef : entity e_Notification [ location Input required True ]
        returns Boolean
        description "Section 11. Email accompanies only the two events that create an invitation, and only when the invited user has an email address on record. The message is queued rather than sent at once."
    ]
    operation markNotificationRead "Mark a notification read" : Command [
        parameter notificationRef : entity e_Notification [ location Input required True ]
        returns entity e_Notification
        authorization ap_PlatformProfiles
    ]
    operation readNotifications "Read the notifications" : Query [
        returns entity ec_Notification
        transaction ReadOnly
        description "Section 11. A bell in the site header shows the number of unread notifications and the ten most recent of them; a full list page shows every notification, newest first, with paging."
    ]
    operation viewActivityRecord "View the activity record" : Query [
        parameter scopeRef : String [ location Input required True ]
        returns entity e_ActivityMessage
        transaction ReadOnly
        description "Section 11. Accepting or rejecting an invitation posts a corresponding message on the organisation or workspace concerned, so the membership history of a container can be read from the container itself."
    ]
]

AppService s_AdministrationService "Administration service" : Application [
    interface "PlatformAdministrationService"
    authorization ap_PlatformProfiles
    realizes uc_OverseeEveryRecord
    operation manageUserAccounts "Manage the user accounts" : Command [
        parameter userRef : entity e_User [ location Input required True ]
        parameter profile : enum PlatformProfile [ location Input required False ]
        returns entity e_User
        description "Section 12. Viewing and editing every user, deleting users, and assigning the platform profile. This capability rests on the general settings permission of the underlying account system, which the administrator profile does not itself confer."
    ]
    operation suspendOrganisation "Suspend or reactivate an organisation" : Command [
        parameter organisationRef : entity e_Organisation [ location Input required True ]
        parameter newState : enum OrganisationState [ location Input required True ]
        returns entity e_Organisation
        description "Section 12. Not offered anywhere in the portal."
    ]
    operation resetWorkspaceProgress "Reset the workspace progress" : Command [
        parameter workspaceRef : entity e_Workspace [ location Input required True ]
        returns entity e_Workspace
        description "Section 4. Returning a concluded or cancelled workspace to not started is accepted by the platform but has no control in the portal."
    ]
    operation configureEditorIntegration "Configure the editor integration" : Command [
        parameter integrationSettingRef : entity e_EditorIntegrationSetting [ location Input required True ]
        returns entity e_EditorIntegrationSetting
        description "Section 12. The admitted extensions determine which documents the editor is offered and which files a conversation may deposit in a workspace."
    ]
    operation maintainPlatformAssistanceDefaults "Maintain the platform assistance defaults" : Command [
        parameter instructionBlockRef : entity e_InstructionBlock [ location Input required False ]
        returns entity ec_Assistance
        description "Section 10 and Section 12. The platform-wide catalogue, the default assignment of each engine role, and the platform instruction block that precedes every organisation own."
    ]
]

AppEndpoint ep_EditorLaunch "Editor launch" : GET "/workspaces/{workspaceKey}/specifications/launch" [
    operation s_EditorIntegrationService.launchEditorSession
    parameter workspaceKey : String [ location Path required True ]
    authentication as_PortalSignIn
    response status 302 description "Redirects to the editor in a new browser tab, carrying the encrypted session description."
    response status 404 description "The workspace does not exist, or a public launch named a workspace that is not public."
    description "Section 8. The platform merely redirects, so an editor that is unavailable produces the new tab own connection error and the platform says nothing about it."
]

AppEndpoint ep_EditorDocuments "Editor document import" : GET "/integration/editor/documents" [
    operation s_EditorIntegrationService.listImportableDocuments
    authentication as_EditorSession
    response status 200 description "The file name, the display title, and the origin of each importable document."
    response status 403 description "The session description is missing, unusable, mismatched, or carries no access."
]

AppEndpoint ep_EditorLanguages "Editor language catalogue" : GET "/integration/editor/languages" [
    operation s_EditorIntegrationService.supplyLanguages
    authentication as_EditorSession
    response status 200 description "The assembled grammar text, the registered file extensions, a fingerprint of the content, and the built services artefact of each supplied language."
]

AppEndpoint ep_ChatExport "Specification export" : POST "/integration/chat/export" [
    operation s_ChatIntegrationService.exportGeneratedSpecification
    authentication as_ChatSession
    response status 201 description "Names the created document and, beside it, whether the delivery was made, whether a live session received it, and, when it was not made, a stated reason."
    response status 403 description "An absence of write rights re-derived from the current workspace role, or a mismatched workspace."
    response status 413 description "Content above one megabyte."
    description "Section 9. The two operations are deliberately not tied together: the document survives a failed delivery."
]

AppEvent ev_OrgInvitationCreated "Organisation invitation created" : Notification [
    schema e_OrganisationRole
    publisher s_OrganisationService
    subscriber s_NotificationService
    delivery AtLeastOnce
    description "Section 11. Notifies the invited user, and is one of the two events that also queue an email."
]

AppEvent ev_OrgInvitationAccepted "Organisation invitation accepted" : Notification [
    schema e_OrganisationRole
    publisher s_OrganisationService
    subscriber s_NotificationService
    delivery AtLeastOnce
    description "Section 11. Notifies every accepted organisation manager of that organisation, and no one else."
]

AppEvent ev_OrgInvitationRejected "Organisation invitation rejected" : Notification [
    schema e_OrganisationRole
    publisher s_OrganisationService
    subscriber s_NotificationService
    delivery AtLeastOnce
    description "Section 11. Notifies the same managers."
]

AppEvent ev_WsInvitationCreated "Workspace invitation created" : Notification [
    schema e_WorkspaceRole
    publisher s_WorkspaceService
    subscriber s_NotificationService
    delivery AtLeastOnce
    description "Section 11. Notifies the invited user, and is the second of the two events that also queue an email."
]

AppEvent ev_WsInvitationAccepted "Workspace invitation accepted" : Notification [
    schema e_WorkspaceRole
    publisher s_WorkspaceService
    subscriber s_NotificationService
    delivery AtLeastOnce
    description "Section 11. Notifies every accepted workspace manager of that workspace."
]

AppEvent ev_WsInvitationRejected "Workspace invitation rejected" : Notification [
    schema e_WorkspaceRole
    publisher s_WorkspaceService
    subscriber s_NotificationService
    delivery AtLeastOnce
    description "Section 11. Notifies the same managers."
]

AppEvent ev_DocumentStateChanged "Document state changed" : Domain [
    schema e_Document
    publisher s_DocumentService
    delivery AtLeastOnce
    description "Section 5. A document leaving the published state loses its grounding knowledge mark and its text is withdrawn from the pool at the same moment. This event produces no notification."
]

AppEvent ev_LanguageFilesChanged "Language files changed" : Domain [
    schema e_LanguageVersion
    publisher s_LanguageService
    delivery AtLeastOnce
    description "Section 7. Any change to a version or to its files refreshes the language knowledge pool. This event produces no notification."
]

AppEvent ev_VersionPublished "Language version published" : Domain [
    schema e_LanguageVersion
    publisher s_LanguageService
    delivery AtLeastOnce
    description "Section 7. The version of the same family that was active becomes deprecated, and the editor, generation, and the chatbot change behaviour for every user of the platform. This event produces no notification."
]

AppChannel ch_MembershipEvents "Membership events" : Topic [
    message ev_OrgInvitationCreated
    message ev_OrgInvitationAccepted
    message ev_OrgInvitationRejected
    message ev_WsInvitationCreated
    message ev_WsInvitationAccepted
    message ev_WsInvitationRejected
    description "Section 11. The six events that produce a notification, all of them concerning membership."
]

AppChannel ch_EmailQueue "Invitation email queue" : Queue [
    message ev_OrgInvitationCreated
    message ev_WsInvitationCreated
    description "Section 11. The message is queued rather than sent at once, so its arrival is not simultaneous with the in-platform notification."
]

AppNotification n_InvitationInPlatform "In-platform invitation notification" : InApp [
    template "notifications/invitation"
    recipient "invitedUser"
    trigger ev_OrgInvitationCreated
    trigger ev_WsInvitationCreated
    description "Section 11. An invited user answers from their notifications, accepting or rejecting there."
]

AppNotification n_InvitationAnsweredInPlatform "In-platform answer notification" : InApp [
    template "notifications/invitation-answered"
    recipient "acceptedManagersOfContainer"
    trigger ev_OrgInvitationAccepted
    trigger ev_OrgInvitationRejected
    trigger ev_WsInvitationAccepted
    trigger ev_WsInvitationRejected
    description "Section 11. Ordinary members and document managers are not told when someone accepts or rejects an invitation; only the managers of the affected container are."
]

AppNotification n_InvitationEmail "Invitation email" : Email [
    template "email/invitation"
    recipient "invitedUser.emailAddress"
    trigger ev_OrgInvitationCreated
    trigger ev_WsInvitationCreated
    description "Section 11. Email accompanies only the two events that create an invitation, and only when the invited user has an email address on record. Acceptances and rejections produce no email at all."
]

AppIntegration i_EditorIntegration "ITOI editor integration" : Bidirectional [
    externalSystem "ITOI specification editor"
    protocol HTTP
    synchronization Synchronous
    credential sec_EditorSharedSecret
    description "Section 8. Every interface between the two carries content outward, and none accepts content inward except the delivery of a document the platform has just created."
]

AppIntegration i_ChatbotIntegration "Chatbot integration" : Bidirectional [
    externalSystem "Conversational assistant"
    protocol HTTP
    synchronization Synchronous
    credential sec_EditorSharedSecret
    description "Section 9. The chatbot receives a session statement and the platform never probes it before rendering the chat page."
]

AppIntegration i_AssistanceProviders "Assistance providers" : Outbound [
    externalSystem "Registered assistance providers"
    protocol HTTP
    synchronization Synchronous
    credential sec_EngineAccessKey
    credential sec_EngineServiceAddress
    description "Section 10. Each engine is addressed under one of three credential arrangements: an access key alone, a service address alone, or both together."
]

AppJob j_InvitationEmailDispatch "Invitation email dispatch" : Background [
    operation s_NotificationService.queueInvitationEmail
    description "Section 11. The queued invitation message is dispatched separately from the in-platform notification."
]

AppJob j_KnowledgePoolRefresh "Knowledge pool refresh" : Background [
    operation s_LanguageService.refreshKnowledgePool
    description "Sections 5, 7 and 9. Entries are added and withdrawn as documents leave the published state and as language versions come into and out of force."
]

/****************************************************
   User interface (Sections 2 to 12)
*****************************************************/

UIContainer ui_Public "Public website" : Window [
    isLandmark
    layout Column
    description "Section 2. What an unauthenticated visitor may reach: the home page, the terms and conditions, the catalogue of specification languages and the detail page of any version in force, and the list of workspaces their owners have marked public."

    UIComponent publicMenu "Public navigation" : Menu : Menu_Main [
        title "ITLingoCloud"
        part menuHome "Home" : Slot : Slot_MenuOption : WFC_Hyperlink [
            event selectHome "Open the home page" : Select [ navigateTo rt_Home ]
        ]
        part menuTerms "Terms and conditions" : Slot : Slot_MenuOption : WFC_Hyperlink [
            event selectTerms "Open the terms and conditions" : Select [ navigateTo rt_Terms ]
        ]
        part menuLanguages "Specification languages" : Slot : Slot_MenuOption : WFC_Hyperlink [
            event selectLanguages "Open the language catalogue" : Select [ navigateTo rt_LanguageCatalogue ]
        ]
        part menuPublicWorkspaces "Public workspaces" : Slot : Slot_MenuOption : WFC_Hyperlink [
            event selectPublicWorkspaces "Open the public workspace listing" : Select [ navigateTo rt_PublicWorkspaceList ]
        ]
        part menuRegister "Register" : Slot : Slot_MenuOption : WFC_Button [
            event selectRegister "Open the registration form" : Select [ navigateTo rt_Register ]
        ]
    ]

    UIComponent registrationForm "Registration" : Form : Form_Simple [
        title "Create an account"
        dataBinding e_User [
            visualizationAttributes e_User.fullName, e_User.emailAddress, e_User.termsVersion
        ]
        part registerName "Name" : Field : Field_Input : WFC_Text [ valueType String dataAttributeBinding e_User.fullName ]
        part registerEmail "Email address" : Field : Field_Input : WFC_Text [ valueType Email dataAttributeBinding e_User.emailAddress ]
        part registerPassword "Password" : Field : Field_Input : WFC_Text [ valueType String ]
        part registerTerms "I accept the terms and conditions" : Field : Field_Selection : WFC_CheckBox [
            valueType Boolean
            dataAttributeBinding e_User.termsVersion
            description "Section 2. The acceptance is recorded against the account together with the version accepted, the moment of acceptance, and the network address and the browser identification of the request."
        ]
    ]

    UIComponent languageCatalogue "Specification languages" : List : List_Table [
        title "Specification languages"
        isScrollable
        dataBinding e_LanguageVersion [
            visualizationAttributes e_LanguageVersion.versionLabel, e_LanguageVersion.summaryText, e_LanguageVersion.fileExtensions, e_LanguageVersion.versionState
            filterAttributes e_LanguageVersion.versionState
            orderBy e_LanguageVersion.versionLabel ASC
        ]
        description "Section 7. A visitor and an ordinary user see the versions in force of families that have not been withdrawn; a maintainer additionally sees the versions of the families they maintain, including drafts; an administrator sees everything."
        event selectLanguageVersion "Open a version detail page" : Select [ navigateTo rt_LanguageVersionDetail ]
    ]

    UIComponent templateReferencePanel "Template reference" : Details [
        title "What a template may address"
        dataBinding e_TemplateReference [
            visualizationAttributes e_TemplateReference.entryTypeName, e_TemplateReference.typeInventory, e_TemplateReference.iterableTypes, e_TemplateReference.starterTemplate, e_TemplateReference.isFallbackDocumentation
        ]
        description "Section 6. Reachable without signing in for every language the visitor may see, and falling back to generic documentation rather than presenting an empty inventory."
    ]

    UIComponent publicWorkspaceList "Public workspaces" : List : List_Table [
        title "Public workspaces"
        dataBinding e_Workspace [
            visualizationAttributes e_Workspace.workspaceName, e_Workspace.progressState
            searchAttributes e_Workspace.workspaceName
            filterAttributes e_Workspace.progressState
        ]
        description "Section 4. A public listing that anyone may browse and filter by name, organisation, and progress state."
        event selectPublicWorkspace "Open a public workspace" : Select [ navigateTo rt_PublicWorkspace ]
    ]

    UIComponent publicWorkspaceHub "Public workspace" : Details [
        title "Workspace"
        dataBinding e_Workspace [
            visualizationAttributes e_Workspace.workspaceName, e_Workspace.summaryText, e_Workspace.progressState
        ]
        description "Section 4. A reduced hub: the summary with counts of documents by type and by specification language family but not of members, the published documents, the specifications section from which the workspace opens read-only in the editor, and the conversations. No control that changes anything is offered."
        part publicDocumentsSection "Documents" : Slot : Slot_Other : WFC_List [
            isReadOnly
            description "Section 4. Only the documents that are in the published state."
        ]
        part publicSpecificationsSection "Specifications" : Slot : Slot_Other : WFC_Hyperlink [
            isReadOnly
            description "Section 8. A launch from the public view of a public workspace is always read-only, whoever performs it."
        ]
        part publicChatSection "Conversations" : Slot : Slot_Other : WFC_Paragraph [
            isReadOnly
            description "Section 9. An anonymous visitor to a public workspace reaches the same chat page; a signed-in member arriving there is redirected to their own view of the workspace."
        ]
    ]
]

UIContainer ui_Portal "Authenticated portal" : Window [
    isDefault
    isLandmark
    layout Column
    description "Sections 3 to 11. The organisation hub, the workspace hub, the document pages, the template generation page, the grammar editor, the assistance configuration page, and the notifications."

    UIComponent portalMenu "Portal navigation" : Menu : Menu_Main [
        title "ITLingoCloud"
        part menuOrganisations "Organisations" : Slot : Slot_MenuOption : WFC_Hyperlink [
            activationExpression "hasPermission('p_ViewOrganisation')"
            event selectOrganisationHub "Open the organisation hub" : Select [ navigateTo rt_OrganisationHome ]
        ]
        part menuWorkspaces "Workspaces" : Slot : Slot_MenuOption : WFC_Hyperlink [
            activationExpression "hasPermission('p_ViewWorkspace')"
            event selectWorkspaceHub "Open the workspace hub" : Select [ navigateTo rt_WorkspaceHome ]
        ]
        part menuNotificationBell "Notifications" : Slot : Slot_MenuOption : WFC_Button [
            event selectNotifications "Open the notification list" : Select [ navigateTo rt_Notifications ]
            description "Section 11. A bell in the site header showing the number of unread notifications and the ten most recent of them."
        ]
    ]

    UIComponent notificationBell "Notification bell" : List : List_Nested [
        title "Unread notifications"
        dataBinding e_Notification [
            visualizationAttributes e_Notification.eventKind, e_Notification.isRead, e_Notification.raisedOn
            filterAttributes e_Notification.isRead
            orderBy e_Notification.raisedOn DESC
        ]
        description "Section 11. Shows the number of unread notifications and the ten most recent of them, and offers to answer an invitation or mark a notification read without leaving the page."
        part bellUnreadCount "Unread count" : Field : Field_Output : WFC_Label [ valueType Integer isReadOnly ]
        part bellAnswerInvitation "Accept or reject" : Slot : Slot_MenuOption : WFC_Button []
        part bellMarkRead "Mark read" : Slot : Slot_MenuOption : WFC_Button []
    ]

    UIComponent notificationList "Notifications" : List : List_Table [
        title "Notifications"
        isScrollable
        dataBinding e_Notification [
            visualizationAttributes e_Notification.eventKind, e_Notification.isRead, e_Notification.raisedOn
            orderBy e_Notification.raisedOn DESC
        ]
        description "Section 11. Every notification, newest first, with paging, an action to mark all of them read, and, for an invitation still awaiting an answer, the accept and reject actions themselves."
        part markAllRead "Mark all read" : Slot : Slot_MenuOption : WFC_Button []
        part listAcceptInvitation "Accept" : Slot : Slot_MenuOption : WFC_Button []
        part listRejectInvitation "Reject" : Slot : Slot_MenuOption : WFC_Button []
    ]

    UIComponent orgHubHome "Organisation home" : Details [
        title "Organisation"
        dataBinding e_Organisation [
            visualizationAttributes e_Organisation.organisationName, e_Organisation.activityType, e_Organisation.country, e_Organisation.summaryText, e_Organisation.lifecycleState
        ]
        description "Section 3. Summarises the organisation in grouped counts: its workspaces by progress state, its documents by type and by specification language family, its members by role, and its registered assistance engines, each count linking to the corresponding filtered list. Document counts are restricted to the published state for members who hold no editing role."
        part countWorkspacesByProgress "Workspaces by progress state" : Field : Field_Output : WFC_Label [ valueType Integer isReadOnly ]
        part countDocumentsByType "Documents by type" : Field : Field_Output : WFC_Label [ valueType Integer isReadOnly ]
        part countDocumentsByFamily "Documents by language family" : Field : Field_Output : WFC_Label [ valueType Integer isReadOnly ]
        part countMembersByRole "Members by role" : Field : Field_Output : WFC_Label [ valueType Integer isReadOnly ]
        part countAssistanceEngines "Registered assistance engines" : Field : Field_Output : WFC_Label [ valueType Integer isReadOnly ]
    ]

    UIComponent orgWorkspaces "Organisation workspaces" : List : List_Table [
        title "Workspaces"
        dataBinding e_Workspace [
            visualizationAttributes e_Workspace.workspaceName, e_Workspace.progressState, e_Workspace.isPublic
            filterAttributes e_Workspace.progressState
        ]
        description "Section 3. Restricted to the workspaces in which the viewer holds an accepted workspace role, so that a manager sees all of them through the cascade while other members see only their own."
    ]

    UIComponent orgDocuments "Organisation documents" : List : List_Table [
        title "Documents"
        dataBinding e_Document [
            visualizationAttributes e_Document.documentName, e_Document.documentTypeRef, e_Document.versionLabel, e_Document.documentState
            filterAttributes e_Document.documentState
        ]
        description "Section 3. The organisation own documents, restricted to the published state for members who do not hold an editing role. They are shared into the organisation workspaces rather than copied."
    ]

    UIComponent orgUsers "Organisation users" : List : List_Table [
        title "Users"
        dataBinding e_OrganisationRole [
            visualizationAttributes e_OrganisationRole.holder, e_OrganisationRole.roleKind, e_OrganisationRole.assignmentStatus
            filterAttributes e_OrganisationRole.roleKind
        ]
        description "Section 3. An organisation manager sees every accepted member, with filters and paging, together with the controls for changing a role and removing a member. Every other accepted role sees only their own row, with the total member count but no filters and no paging, and supplying filter parameters in the address does not widen that view."
        part orgInviteMember "Invite" : Slot : Slot_MenuOption : WFC_Button [
            activationExpression "hasPermission('p_InviteOrganisationMember')"
        ]
        part orgChangeRole "Change role" : Slot : Slot_MenuOption : WFC_Button [
            activationExpression "hasPermission('p_ChangeOrganisationRole')"
        ]
        part orgRemoveMember "Remove" : Slot : Slot_MenuOption : WFC_Button [
            activationExpression "hasPermission('p_RemoveOrganisationMember')"
        ]
        part orgLeave "Leave the organisation" : Slot : Slot_MenuOption : WFC_Button []
    ]

    UIComponent orgAssistanceConfiguration "Assistance configuration" : Form : Form_MasterDetail [
        title "Assistance configuration"
        visibleWhen "role == 'OrgManager' and conversationalPartPresent == true"
        dataBinding e_Engine [
            visualizationAttributes e_Engine.displayLabel, e_Engine.providerIdentifier, e_Engine.arrangement, e_Engine.serviceAddress
        ]
        description "Section 10. Reserved to organisation managers, and present in the hub only when the conversational part of the system is present."
        part providerList "Providers" : Slot : Slot_Other : WFC_List [
            description "Section 10. A catalogue is a set of providers, each grouping one or more engines; the entries an organisation registers are its own."
        ]
        part engineLabel "Label" : Field : Field_Input : WFC_Text [ valueType String dataAttributeBinding e_Engine.displayLabel ]
        part engineIdentifier "Identifier passed to the provider" : Field : Field_Input : WFC_Text [ valueType String dataAttributeBinding e_Engine.providerIdentifier ]
        part engineArrangement "Credential arrangement" : Field : Field_Selection : WFC_ComboBox [
            dataAttributeBinding e_Engine.arrangement
            description "Section 10. An access key alone, a service address alone, or both together. Changing the arrangement clears the credentials belonging to the arrangement abandoned."
        ]
        part engineAccessKeyField "Access key" : Field : Field_Input : WFC_Text [
            valueType String
            description "Section 10. Leaving the key field empty keeps the key already stored, so a manager may change a label or an identifier without re-entering, or ever redisplaying, the secret."
        ]
        part engineAddressField "Service address" : Field : Field_Input : WFC_Text [ valueType URL dataAttributeBinding e_Engine.serviceAddress ]
        part engineRoleAssignments "Engine roles" : Slot : Slot_Other : WFC_Table [
            description "Section 10. Nine assignable roles: a default, an engine for answering from the knowledge pool, one for generating diagrams, one for interpreting images, and one for each of the five phases of specification generation."
        ]
        part organisationInstructionBlock "Organisation instruction block" : Field : Field_Input : WFC_Paragraph [
            valueType Text
            description "Section 10. Until an organisation saves a block of its own, the page presents the platform organisation-level text as the starting point."
        ]
        part revertInstructionsButton "Revert" : Slot : Slot_MenuOption : WFC_Button [
            description "Section 10. A revert action discards the organisation text entirely and restores that same fallback."
        ]
    ]

    UIComponent orgSettings "Organisation settings" : Form : Form_Simple [
        title "Settings"
        visibleWhen "role == 'OrgManager'"
        dataBinding e_Organisation [
            visualizationAttributes e_Organisation.organisationName, e_Organisation.activityType, e_Organisation.country
        ]
        description "Section 3. Reserved to organisation managers. Only the name, the activity type, and the country may be changed from the portal."
        part settingsName "Name" : Field : Field_Input : WFC_Text [ valueType String dataAttributeBinding e_Organisation.organisationName ]
        part settingsActivityType "Activity type" : Field : Field_Selection : WFC_ComboBox [ dataAttributeBinding e_Organisation.activityType ]
        part settingsCountry "Country" : Field : Field_Input : WFC_Text [ valueType String dataAttributeBinding e_Organisation.country ]
        part deleteOrganisationButton "Delete the organisation" : Slot : Slot_MenuOption : WFC_Button [
            activationExpression "hasPermission('p_DeleteOrganisation')"
        ]
    ]

    UIComponent wsHubHome "Workspace home" : Details [
        title "Workspace"
        dataBinding e_Workspace [
            visualizationAttributes e_Workspace.workspaceName, e_Workspace.summaryText, e_Workspace.progressState, e_Workspace.plannedStart, e_Workspace.plannedEnd, e_Workspace.actualStart, e_Workspace.actualEnd
        ]
        description "Section 4. The first of the six sections. Carries the summary and, for a workspace manager, the progress transitions."
        part startWorkspaceButton "Start" : Slot : Slot_MenuOption : WFC_Button [
            activationExpression "hasPermission('p_ChangeWorkspaceProgress')"
            description "Section 4. Records the actual start date."
        ]
        part concludeWorkspaceButton "Conclude" : Slot : Slot_MenuOption : WFC_Button [
            activationExpression "hasPermission('p_ChangeWorkspaceProgress')"
            description "Section 4. Records the actual end date."
        ]
        part cancelWorkspaceButton "Cancel" : Slot : Slot_MenuOption : WFC_Button [
            activationExpression "hasPermission('p_ChangeWorkspaceProgress')"
            description "Section 4. The workspace home offers the first three transitions only; returning a concluded or cancelled workspace to not started is performed from the administrative interface."
        ]
    ]

    UIComponent wsDocuments "Workspace documents" : List : List_Table [
        title "Documents"
        dataBinding e_Document [
            visualizationAttributes e_Document.documentName, e_Document.documentTypeRef, e_Document.versionLabel, e_Document.documentState, e_Document.isGroundingKnowledge
            searchAttributes e_Document.documentName
            filterAttributes e_Document.documentState
            orderBy e_Document.documentName ASC
        ]
        description "Section 4. The second section. Lists the workspace own documents together with a second list of the published documents of its organisation."
        dataFlowTo ui_Portal.documentForm
        event selectDocument "Open the document page" : Select [ navigateTo rt_DocumentEdit ]
    ]

    UIComponent wsSpecifications "Workspace specifications" : Details [
        title "Specifications"
        description "Section 8. The third section and the launching point for the editor. The page states, before the user commits to anything, whether the session that will open is writable or read-only, and the launch action opens the editor in a new browser tab."
        part sessionWriteModeLabel "This session will be" : Field : Field_Output : WFC_Label [ valueType String isReadOnly ]
        part launchEditorButton "Open in the editor" : Slot : Slot_MenuOption : WFC_Button [
            navigateTo rt_EditorLaunch [ mode External ]
        ]
    ]

    UIComponent wsChat "Workspace chat" : Details [
        title "Chat"
        description "Section 9. The fourth section, embedding the chatbot. Conversation happens beside the work it concerns; there is no organisation-level and no platform-level conversation. The platform never probes the chatbot before rendering, so an unreachable chatbot fails to load in the browser and the platform reports nothing."
        part chatFrame "Conversation" : Slot : Slot_Other : WFC_Paragraph []
        part exportSpecificationButton "Export into the workspace" : Slot : Slot_MenuOption : WFC_Button [
            activationExpression "hasPermission('p_ExportIntoWorkspace')"
            description "Section 9. An accepted export creates an ordinary workspace document in the draft state."
        ]
    ]

    UIComponent wsUsers "Workspace users" : List : List_Table [
        title "Users"
        dataBinding e_WorkspaceRole [
            visualizationAttributes e_WorkspaceRole.holder, e_WorkspaceRole.roleKind, e_WorkspaceRole.assignmentStatus
            filterAttributes e_WorkspaceRole.roleKind
        ]
        description "Section 4. The fifth section. Every accepted role sees the full member list with its filters and paging, unlike the organisation users page, and only the actions of inviting, changing a role, and removing are restricted to the workspace manager."
        part wsInviteMember "Invite" : Slot : Slot_MenuOption : WFC_Button [
            activationExpression "hasPermission('p_InviteWorkspaceMember')"
        ]
        part wsChangeRole "Change role" : Slot : Slot_MenuOption : WFC_Button [
            activationExpression "hasPermission('p_ChangeWorkspaceRole')"
        ]
        part wsRemoveMember "Remove" : Slot : Slot_MenuOption : WFC_Button [
            activationExpression "hasPermission('p_RemoveWorkspaceMember')"
        ]
        part wsLeave "Leave the workspace" : Slot : Slot_MenuOption : WFC_Button []
    ]

    UIComponent wsSettings "Workspace settings" : Form : Form_MasterDetail [
        title "Settings"
        visibleWhen "role == 'WsManager'"
        dataBinding e_Workspace [
            visualizationAttributes e_Workspace.workspaceName, e_Workspace.organisationRef, e_Workspace.isPublic, e_Workspace.plannedStart, e_Workspace.plannedEnd, e_Workspace.summaryText
        ]
        description "Section 4. The sixth section, reserved to a workspace manager. Reuses the four steps of creation to edit the workspace in place, each step saving as it is left."
        part stepIdentity "Step one: name, organisation, and public" : Slot : Slot_Other : WFC_Tab []
        part stepDates "Step two: planned and actual dates" : Slot : Slot_Other : WFC_Tab []
        part stepDescription "Step three: description" : Slot : Slot_Other : WFC_Tab []
        part stepReview "Step four: review" : Slot : Slot_Other : WFC_Tab []
        part deleteWorkspaceButton "Delete the workspace" : Slot : Slot_MenuOption : WFC_Button [
            activationExpression "hasPermission('p_DeleteWorkspace')"
        ]
    ]

    UIComponent documentForm "Document" : Form : Form_Simple [
        title "Document"
        dataBinding e_Document [
            visualizationAttributes e_Document.documentName, e_Document.documentTypeRef, e_Document.versionLabel, e_Document.contentLanguage, e_Document.languageFamilyRef, e_Document.languageVersionRef, e_Document.attachedFile, e_Document.documentState, e_Document.isGroundingKnowledge
        ]
        description "Section 5. The document editing page. The name is the only attribute the platform requires."
        part documentNameField "Name" : Field : Field_Input : WFC_Text [ valueType String dataAttributeBinding e_Document.documentName ]
        part documentTypeField "Type" : Field : Field_Selection : WFC_ComboBox [ dataAttributeBinding e_Document.documentTypeRef ]
        part documentVersionField "Version label" : Field : Field_Input : WFC_Text [
            valueType String
            dataAttributeBinding e_Document.versionLabel
            defaultValue "1.0"
            description "Section 5. Free text which the author maintains by hand."
        ]
        part documentContentLanguageField "Content language" : Field : Field_Selection : WFC_ComboBox [ dataAttributeBinding e_Document.contentLanguage ]
        part documentFamilyField "Specification language family" : Field : Field_Selection : WFC_ComboBox [ dataAttributeBinding e_Document.languageFamilyRef ]
        part documentVersionRefField "Specification language version" : Field : Field_Selection : WFC_ComboBox [
            dataAttributeBinding e_Document.languageVersionRef
            description "Section 5. Naming a version without its family, or a version belonging to a different family, is refused."
        ]
        part documentFileField "File" : Field : Field_Input : WFC_Button [ valueType File dataAttributeBinding e_Document.attachedFile ]
        part documentStateSelector "State" : Field : Field_Selection : WFC_ComboBox [
            dataAttributeBinding e_Document.documentState
            description "Section 5. An editor sets the state directly and any of the five values may be chosen from any other; the platform does not require a document to pass through review and approval before it is published."
        ]
        part groundingKnowledgeMark "Grounding knowledge" : Field : Field_Selection : WFC_CheckBox [
            valueType Boolean
            dataAttributeBinding e_Document.isGroundingKnowledge
            showIf "document.documentState == 'DocPublished' and document.formatGroup == 'FormatText'"
            description "Section 5. Offered only while the document is published and its file is textual. A document that leaves published loses the mark automatically."
        ]
        part documentHistoryPanel "Change history" : Slot : Slot_Other : WFC_Table [
            isReadOnly
            description "Section 5. Alterations to the name, state, version, type, and language associations, but not the content that was replaced and not the replacement of the file itself."
        ]
        event submitDocument "Save the document" : Submit []
    ]

    UIComponent templateGenerationPanel "Generate a document" : Form : Form_Simple [
        title "Generate from this template"
        dataBinding e_GenerationRun [
            visualizationAttributes e_GenerationRun.uploadedSpecification, e_GenerationRun.targetVersionRef, e_GenerationRun.refusalReason
        ]
        description "Section 6. The generation panel appears on the template own page, in the workspace hub, in the organisation hub, and on the view of an organisation template surfaced inside a workspace. It is offered to anyone who may read the template."
        part uploadSpecificationField "Specification" : Field : Field_Input : WFC_Button [
            valueType File
            dataAttributeBinding e_GenerationRun.uploadedSpecification
            description "Section 6. The upload must carry an extension the target language registers."
        ]
        part targetVersionField "Language version" : Field : Field_Selection : WFC_ComboBox [
            dataAttributeBinding e_GenerationRun.targetVersionRef
            showIf "user.maintainsFamily == true or user.profile == 'ProfileAdministrator'"
            description "Section 6. The version used is the one currently in force; a maintainer of that family, and an administrator, may instead direct the run at a particular version, including one still in draft."
        ]
        part generateButton "Generate" : Slot : Slot_MenuOption : WFC_Button []
        part generationRefusalMessage "Refusal" : Field : Field_Output : WFC_Label [
            isReadOnly
            dataAttributeBinding e_GenerationRun.refusalReason
        ]
    ]

    UIComponent templateAdvisoryPanel "Template check" : Form : Form_Simple [
        title "Check a template"
        dataBinding e_TemplateAdvisoryCheck [
            visualizationAttributes e_TemplateAdvisoryCheck.checkedFragment, e_TemplateAdvisoryCheck.reportedFindings
        ]
        description "Section 6. An advisory check that never blocks generation and never stores what it was given."
        part fragmentField "Fragment" : Field : Field_Input : WFC_Paragraph [ valueType Text dataAttributeBinding e_TemplateAdvisoryCheck.checkedFragment ]
        part findingsField "Findings" : Field : Field_Output : WFC_Paragraph [ isReadOnly dataAttributeBinding e_TemplateAdvisoryCheck.reportedFindings ]
    ]

    UIComponent grammarEditor "Grammar editor" : Form : Form_MasterDetail [
        title "Grammar and services"
        enabledWhen "languageVersion.versionState == 'VersionDraft'"
        dataBinding e_GrammarFile [
            visualizationAttributes e_GrammarFile.relativePath, e_GrammarFile.isEntryFile, e_GrammarFile.isEnabled, e_GrammarFile.contentText
        ]
        description "Section 7. A version grammar is a set of files that may import one another, edited in the browser, and the same rule applies separately to the services files. Every mutating action is refused outside the draft state, even when it is made directly."
        part grammarFileList "Grammar files" : Slot : Slot_Other : WFC_List [
            description "Section 7. Exactly one of them is the entry file. Files are constrained to plain relative paths, must carry the extension appropriate to their kind, must be valid text, and are bounded in size."
        ]
        part servicesFileList "Services files" : Slot : Slot_Other : WFC_List [
            description "Section 7. Custom services let a version carry behaviour a grammar cannot express. Each change to their content rebuilds them into a single artefact."
        ]
        part grammarFileContent "Content" : Field : Field_Input : WFC_Paragraph [ valueType Text dataAttributeBinding e_GrammarFile.contentText ]
        part grammarEntryFlag "Entry file" : Field : Field_Selection : WFC_CheckBox [ valueType Boolean dataAttributeBinding e_GrammarFile.isEntryFile ]
        part grammarEnabledFlag "Enabled" : Field : Field_Selection : WFC_CheckBox [
            valueType Boolean
            dataAttributeBinding e_GrammarFile.isEnabled
            description "Section 7. Enabling or disabling a services file neither rebuilds the artefact nor leaves a trace in the audit trail."
        ]
        part validateButton "Validate" : Slot : Slot_MenuOption : WFC_Button [
            description "Section 7. Runs a validation without changing the state. Only errors make a grammar invalid; warnings and hints are reported without blocking."
        ]
        part publishButton "Publish" : Slot : Slot_MenuOption : WFC_Button [
            activationExpression "hasPermission('p_PublishLanguageVersion')"
            description "Section 7. Reserved to the platform administrator, and conditional on a current, successful validation that the platform re-runs itself."
        ]
        part diagnosticsPanel "Diagnostics" : Field : Field_Output : WFC_Paragraph [
            isReadOnly
            description "Section 7. Services build failures are reported as diagnostics beside the grammar own rather than blocking the save."
        ]
    ]

    UIComponent adminConsole "Administrative interface" : List : List_Table [
        title "Administration"
        visibleWhen "user.profile == 'ProfileAdministrator'"
        dataBinding e_EditorIntegrationSetting [
            visualizationAttributes e_EditorIntegrationSetting.editorAddress, e_EditorIntegrationSetting.credentialLifetime, e_EditorIntegrationSetting.genericExtensions
        ]
        description "Section 12. Account management, organisation suspension and reactivation, workspace progress reset, language governance, the platform assistance defaults, and the integration with the editor. None of these capabilities is delegable through an organisation or workspace role."
        part adminAccounts "User accounts" : Slot : Slot_Other : WFC_Table []
        part adminSuspendOrganisation "Suspend or reactivate an organisation" : Slot : Slot_MenuOption : WFC_Button []
        part adminResetProgress "Reset the workspace progress" : Slot : Slot_MenuOption : WFC_Button []
        part adminPlatformInstructionBlock "Platform instruction block" : Field : Field_Input : WFC_Paragraph [ valueType Text ]
        part adminEditorAddress "Editor address" : Field : Field_Input : WFC_Text [ valueType URL dataAttributeBinding e_EditorIntegrationSetting.editorAddress ]
        part adminCredentialLifetime "Access credential lifetime" : Field : Field_Input : WFC_Text [ valueType Integer dataAttributeBinding e_EditorIntegrationSetting.credentialLifetime ]
        part adminGenericExtensions "General-purpose file extensions" : Field : Field_Input : WFC_Text [
            valueType String
            dataAttributeBinding e_EditorIntegrationSetting.genericExtensions
            description "Section 12. The extensions of every language version in force or in preparation are admitted automatically and are not listed there."
        ]
    ]

    UIAction act_SaveDocument "Save the document" : Server [
        invokes s_DocumentService.editDocument
        description "Section 5. Editing replaces the stored file and the version label in place."
        event documentSaved "Document saved" : Success []
        event documentSaveFailed "Document save failed" : Failure []
    ]

    UIAction act_SetDocumentState "Set the document state" : Server [
        invokes s_DocumentService.setDocumentState
        event documentStateSet "State written" : Success []
    ]

    UIAction act_Generate "Generate from the template" : Server [
        invokes s_TemplateService.generateDocument
        description "Section 6. The produced file is returned directly to the browser and nothing is retained."
        event generationProduced "File produced" : Success []
        event generationRefused "Generation refused" : Failure []
    ]

    UIAction act_ValidateGrammar "Validate the grammar" : Server [
        invokes s_LanguageService.validateGrammar
        event validationStored "Validation stored" : Success []
    ]

    UIAction act_PublishVersion "Publish the version" : Server [
        invokes s_LanguageService.publishLanguageVersion
        description "Section 7. Publication deprecates the version of the same family that was active."
        event versionPublished "Version published" : Success []
        event publicationRefused "Publication refused" : Failure []
    ]

    UIAction act_LaunchEditor "Launch the editor" : Server [
        invokes s_EditorIntegrationService.launchEditorSession
        description "Section 8. Opens the editor in a new browser tab, carrying the encrypted session description."
    ]

    UIAction act_ExportSpecification "Export the generated specification" : Server [
        invokes s_ChatIntegrationService.exportGeneratedSpecification
        event exportAccepted "Document created" : Success []
        event exportRefused "Export refused" : Failure []
    ]

    UIAction act_AssignEngineRole "Assign an engine role" : Server [
        invokes s_AssistanceConfigurationService.assignEngineRole
    ]

    on documentForm.submitDocument do act_SaveDocument
]

UIPage pg_Home "Home" : Application [
    useComponent ui_Public.publicMenu
    localizationKey "page.home"
    description "Section 2. Reachable without signing in."
]

UIPage pg_Terms "Terms and conditions" : Other [
    useComponent ui_Public.publicMenu
    description "Section 2. Reachable without signing in, and explicitly accepted at registration."
]

UIPage pg_Register "Registration" : Authentication [
    useComponent ui_Public.registrationForm
    description "Section 2. Asks for a name, an email address, a password, and explicit acceptance of the terms and conditions."
]

UIPage pg_LanguageCatalogue "Specification languages" : List [
    useComponent ui_Public.languageCatalogue
    description "Section 7. The catalogue of languages is public."
]

UIPage pg_LanguageVersionDetail "Language version" : Details [
    useComponent ui_Public.languageCatalogue
    description "Section 2. The detail page of any language version in force is reachable without signing in."
]

UIPage pg_TemplateReference "Template reference" : Details [
    useComponent ui_Public.templateReferencePanel
    useComponent ui_Portal.templateAdvisoryPanel
    description "Section 6. Reachable without signing in for every language the visitor may see."
]

UIPage pg_PublicWorkspaceList "Public workspaces" : List [
    useComponent ui_Public.publicWorkspaceList
    description "Section 4. Anyone may browse and filter the listing by name, organisation, and progress state."
]

UIPage pg_PublicWorkspace "Public workspace" : Dashboard [
    useComponent ui_Public.publicWorkspaceHub
    description "Section 4. A signed-in user who holds an accepted role on a public workspace is redirected from this view to their own."
]

UIPage pg_OrganisationHome "Organisation home" : Dashboard [
    useComponent ui_Portal.orgHubHome
    authorization ap_OrganisationRBAC
    accessibility ( label "Organisation home" role "main" keyboard True )
    description "Section 3. The first section of the organisation hub."
]

UIPage pg_OrganisationWorkspaces "Organisation workspaces" : List [
    useComponent ui_Portal.orgWorkspaces
    authorization ap_OrganisationRBAC
    description "Section 3. The workspaces section of the organisation hub."
]

UIPage pg_OrganisationDocuments "Organisation documents" : List [
    useComponent ui_Portal.orgDocuments
    authorization ap_PublishedOnlyVisibility
    description "Section 3. The documents section of the organisation hub."
]

UIPage pg_OrganisationUsers "Organisation users" : List [
    useComponent ui_Portal.orgUsers
    authorization ap_OrganisationRBAC
    description "Section 3. The users section of the organisation hub."
]

UIPage pg_OrganisationAssistance "Assistance configuration" : Form [
    useComponent ui_Portal.orgAssistanceConfiguration
    authorization ap_AssistanceConfiguration
    description "Section 10. Visible only to organisation managers, and present only when the conversational part of the system is present."
]

UIPage pg_OrganisationSettings "Organisation settings" : Form [
    useComponent ui_Portal.orgSettings
    authorization ap_OrganisationRBAC
    description "Section 3. Visible only to organisation managers."
]

UIPage pg_WorkspaceHome "Workspace home" : Dashboard [
    useComponent ui_Portal.wsHubHome
    authorization ap_WorkspaceRBAC
    description "Section 4. The first of the six workspace hub sections."
]

UIPage pg_WorkspaceDocuments "Workspace documents" : List [
    useComponent ui_Portal.wsDocuments
    authorization ap_PublishedOnlyVisibility
    description "Section 4. The second of the six workspace hub sections."
]

UIPage pg_WorkspaceSpecifications "Workspace specifications" : Details [
    useComponent ui_Portal.wsSpecifications
    authorization ap_WorkspaceRBAC
    description "Section 4 and Section 8. The third of the six workspace hub sections and the launching point for the editor."
]

UIPage pg_WorkspaceChat "Workspace chat" : Details [
    useComponent ui_Portal.wsChat
    authorization ap_WorkspaceRBAC
    description "Section 4 and Section 9. The fourth of the six workspace hub sections, embedding the chatbot."
]

UIPage pg_WorkspaceUsers "Workspace users" : List [
    useComponent ui_Portal.wsUsers
    authorization ap_WorkspaceRBAC
    description "Section 4. The fifth of the six workspace hub sections."
]

UIPage pg_WorkspaceSettings "Workspace settings" : Form [
    useComponent ui_Portal.wsSettings
    authorization ap_WorkspaceRBAC
    description "Section 4. The sixth of the six workspace hub sections, reserved to a workspace manager."
]

UIPage pg_DocumentEdit "Document" : Form [
    useComponent ui_Portal.documentForm
    editableWhen "hasPermission('p_ManageWorkspaceDocuments') or hasPermission('p_ManageOrganisationDocuments')"
    authorization ap_PublishedOnlyVisibility
    description "Section 5. Carries the state selector and, when the document is published and textual, the grounding-knowledge mark."
]

UIPage pg_TemplateGeneration "Template generation" : Form [
    useComponent ui_Portal.templateGenerationPanel
    description "Section 6. Offered to anyone who may read the template."
]

UIPage pg_GrammarEditor "Grammar editor" : Form [
    useComponent ui_Portal.grammarEditor
    authorization ap_LanguageGovernance
    description "Section 7. Grammar and services files, validation, and publication."
]

UIPage pg_Notifications "Notifications" : List [
    useComponent ui_Portal.notificationList
    description "Section 11. Every notification, newest first, with paging."
]

UIPage pg_Administration "Administrative interface" : Dashboard [
    useComponent ui_Portal.adminConsole
    authorization ap_PlatformProfiles
    description "Section 12. Reserved to the platform administrator."
]

UIRoute rt_Home : Page [ path "/" page pg_Home ]
UIRoute rt_Terms : Page [ path "/terms" page pg_Terms ]
UIRoute rt_Register : Page [ path "/register" page pg_Register ]
UIRoute rt_LanguageCatalogue : Page [ path "/languages" page pg_LanguageCatalogue ]
UIRoute rt_LanguageVersionDetail : Page [ path "/languages/versions" page pg_LanguageVersionDetail parent rt_LanguageCatalogue ]
UIRoute rt_TemplateReference : Page [ path "/languages/template-reference" page pg_TemplateReference parent rt_LanguageCatalogue ]
UIRoute rt_PublicWorkspaceList : Page [ path "/public/workspaces" page pg_PublicWorkspaceList ]
UIRoute rt_PublicWorkspace : Page [ path "/public/workspaces/detail" page pg_PublicWorkspace parent rt_PublicWorkspaceList ]
UIRoute rt_OrganisationHome : Page [ path "/organisations/home" page pg_OrganisationHome guard ap_OrganisationRBAC ]
UIRoute rt_OrganisationWorkspaces : Page [ path "/organisations/workspaces" page pg_OrganisationWorkspaces parent rt_OrganisationHome guard ap_OrganisationRBAC ]
UIRoute rt_OrganisationDocuments : Page [ path "/organisations/documents" page pg_OrganisationDocuments parent rt_OrganisationHome guard ap_PublishedOnlyVisibility ]
UIRoute rt_OrganisationUsers : Page [ path "/organisations/users" page pg_OrganisationUsers parent rt_OrganisationHome guard ap_OrganisationRBAC ]
UIRoute rt_OrganisationAssistance : Page [ path "/organisations/assistance" page pg_OrganisationAssistance parent rt_OrganisationHome guard ap_AssistanceConfiguration ]
UIRoute rt_OrganisationSettings : Page [ path "/organisations/settings" page pg_OrganisationSettings parent rt_OrganisationHome guard ap_OrganisationRBAC ]
UIRoute rt_WorkspaceHome : Page [ path "/workspaces/home" page pg_WorkspaceHome guard ap_WorkspaceRBAC ]
UIRoute rt_WorkspaceDocuments : Page [ path "/workspaces/documents" page pg_WorkspaceDocuments parent rt_WorkspaceHome guard ap_PublishedOnlyVisibility ]
UIRoute rt_WorkspaceSpecifications : Page [ path "/workspaces/specifications" page pg_WorkspaceSpecifications parent rt_WorkspaceHome guard ap_WorkspaceRBAC ]
UIRoute rt_WorkspaceChat : Page [ path "/workspaces/chat" page pg_WorkspaceChat parent rt_WorkspaceHome guard ap_WorkspaceRBAC ]
UIRoute rt_WorkspaceUsers : Page [ path "/workspaces/users" page pg_WorkspaceUsers parent rt_WorkspaceHome guard ap_WorkspaceRBAC ]
UIRoute rt_WorkspaceSettings : Page [ path "/workspaces/settings" page pg_WorkspaceSettings parent rt_WorkspaceHome guard ap_WorkspaceRBAC ]
UIRoute rt_DocumentEdit : Page [ path "/documents/edit" page pg_DocumentEdit ]
UIRoute rt_TemplateGeneration : Page [ path "/documents/generate" page pg_TemplateGeneration ]
UIRoute rt_GrammarEditor : Page [ path "/languages/grammar-editor" page pg_GrammarEditor guard ap_LanguageGovernance ]
UIRoute rt_Notifications : Page [ path "/notifications" page pg_Notifications ]
UIRoute rt_Administration : Page [ path "/administration" page pg_Administration guard ap_PlatformProfiles ]
UIRoute rt_EditorLaunch : External [ path "/workspaces/specifications/launch" redirect rt_WorkspaceSpecifications parent rt_WorkspaceSpecifications description "Section 8. The launch action opens the editor in a new browser tab; the platform merely redirects the browser to the editor with the session description and does not contact the editor itself. The redirect recorded here names the platform route the action belongs to, since the editor lies outside the platform." ]

UIRouteSet rs_Public "Public routes" : Public [
    route rt_Home
    route rt_Terms
    route rt_Register
    route rt_LanguageCatalogue
    route rt_LanguageVersionDetail
    route rt_TemplateReference
    route rt_PublicWorkspaceList
    route rt_PublicWorkspace
    defaultRoute rt_Home
    description "Section 2. The public surface. No other part of the platform is reachable without signing in."
]

UIRouteSet rs_Portal "Portal routes" : Authenticated [
    route rt_OrganisationHome
    route rt_OrganisationWorkspaces
    route rt_OrganisationDocuments
    route rt_OrganisationUsers
    route rt_OrganisationAssistance
    route rt_OrganisationSettings
    route rt_WorkspaceHome
    route rt_WorkspaceDocuments
    route rt_WorkspaceSpecifications
    route rt_WorkspaceChat
    route rt_WorkspaceUsers
    route rt_WorkspaceSettings
    route rt_DocumentEdit
    route rt_TemplateGeneration
    route rt_GrammarEditor
    route rt_Notifications
    route rt_EditorLaunch
    defaultRoute rt_OrganisationHome
    description "Sections 3 to 11. The authenticated portal, where a member or manager sees only the containers in which they hold an accepted role."
]

UIRouteSet rs_Administrative "Administrative routes" : Administrative [
    route rt_Administration
    authorization ap_PlatformProfiles
    description "Section 12. The administrative interface, reserved to the platform administrator."
]

/****************************************************
   Application rules: the invariants (Sections 2 to 10)
*****************************************************/

AppRule rule_NoOrphanWorkspaces "No orphan workspaces" : Invariant [
    condition "organisation.referencingWorkspaces == 0"
    appliesTo e_Organisation
    priority High
    description "Section 3. A sole member who leaves deletes the organisation, unless workspaces still reference it, in which case the departure is refused and the workspaces must be removed or reassigned first. Deleting the organisation outright follows the same restriction. A workspace nevertheless references at most one organisation and the reference is optional, so deleting an organisation does not destroy its workspaces."
]

AppRule rule_LastManagerProtected "Last manager protected" : Invariant [
    condition "acceptedManagers > 1"
    appliesTo e_OrganisationRole
    appliesTo e_WorkspaceRole
    priority VeryHigh
    description "Sections 3 and 4. The last accepted organisation manager, and the last accepted workspace manager, can neither be demoted nor removed. A manager leaving while other members remain must promote a successor first, and the promotion and the departure are carried out together."
]

AppRule rule_WorkspaceNeverWithoutMembers "A workspace is never left without members" : Invariant [
    condition "workspace.acceptedMembers > 0"
    appliesTo e_Workspace
    priority High
    description "Section 4. When its sole accepted member leaves, the workspace is deleted together with whatever it still contains. This is the deliberate difference from an organisation, whose sole member is refused departure while workspaces still reference it."
]

AppRule rule_SingleOwnerScope "A document has one owning scope" : Invariant [
    condition "document.ownerWorkspaceRef == null or document.ownerOrganisationRef == null"
    appliesTo e_Document
    priority VeryHigh
    description "Section 5. A document belongs either to a workspace or to an organisation, and the platform refuses to let it belong to both."
]

AppRule rule_PublishedOnlyVisibility "Published-only visibility" : Invariant [
    condition "document.documentState == 'DocPublished' or viewer.holdsEditingRole == true"
    appliesTo e_Document
    priority VeryHigh
    description "Section 5. A document in any state other than published is seen only by the roles that may edit it, and published alone opens it to the rest of the scope. The listings, the counts, and the document pages are all restricted accordingly."
]

AppRule rule_GroundingRequiresPublishedText "Grounding knowledge requires published text" : Invariant [
    condition "document.isGroundingKnowledge == false or (document.documentState == 'DocPublished' and document.formatGroup == 'FormatText' and document.documentTypeRef != 'TypeTemplate')"
    appliesTo e_Document
    appliesTo e_KnowledgePoolEntry
    priority VeryHigh
    description "Section 5. The mark may be applied only while the document is published and only when its file is textual. A document that leaves published loses the mark automatically and its text is withdrawn from the pool at the same moment, so that content which informs assisted answers is always content the platform currently publishes. Templates may never be marked."
]

AppRule rule_GenerationStoresNothing "Generation stores nothing" : Invariant [
    condition "generationRun.isResultStored == false"
    appliesTo e_GenerationRun
    priority High
    description "Section 6. The produced file is returned directly to the browser: no document is created and nothing is retained, so generation leaves the workspace unchanged."
]

AppRule rule_OneActiveVersionPerFamily "One version in force per family" : Invariant [
    condition "family.activeVersions <= 1"
    appliesTo e_LanguageVersion
    priority VeryHigh
    description "Section 7. At most one version of a family may be active at a time, and publication has one automatic consequence: the version of the same family that was active becomes deprecated. There is no separate action for deprecating a version."
]

AppRule rule_DraftOnlyGrammarEditing "Grammar and services edited only in draft" : Validation [
    condition "languageVersion.versionState == 'VersionDraft'"
    appliesTo e_GrammarFile
    appliesTo e_ServicesFile
    priority VeryHigh
    description "Section 7. Draft is the only state in which grammar and services files may be created, changed, or removed. The right is enforced where the change is submitted, not only by hiding controls: a request to alter a file of a version that is not in draft is refused even when it is made directly, and the same applies to every mutating action of the grammar editor."
]

AppRule rule_AdministratorOnlyPublication "Publication is the administrator" : Validation [
    condition "user.profile == 'ProfileAdministrator'"
    appliesTo e_LanguageVersion
    priority VeryHigh
    description "Section 7. Maintainers prepare and validate a version; only the platform administrator publishes or reactivates one, because a version in force changes the behaviour of the editor, of generation, and of the chatbot for every user of the platform."
]

AppRule rule_ValidationCurrentForPublication "Publication requires a current validation" : Validation [
    condition "languageVersion.validationState == 'ValidationCurrentSuccess'"
    appliesTo e_LanguageVersion
    priority VeryHigh
    description "Section 7. The platform re-runs the validation itself at publication time rather than trusting anything the browser reports, and the recorded result is marked out of date the moment any file of the set changes, so that a stale approval can never satisfy publication."
]

AppRule rule_ServicesAuditImmutable "The services audit trail is immutable" : Invariant [
    condition "servicesAuditEntry.isImmutable == true"
    appliesTo e_ServicesAuditEntry
    priority High
    description "Section 7. Every creation, change of content, and deletion of a services file is written to an audit trail that cannot subsequently be altered or removed, whereas merely enabling or disabling one neither rebuilds the artefact nor leaves a trace there."
]

AppRule rule_LanguageSelectionNarrows "A workspace selection narrows its organisation" : Validation [
    condition "workspaceSelection in organisationSelection and workspaceDefault in workspaceSelection"
    appliesTo e_LanguageSelection
    priority Medium
    description "Section 7. The platform refuses a workspace selection that falls outside its organisation selection, and a default that is not among the workspace available languages."
]

AppRule rule_ManagerOnlyAssistanceConfiguration "Assistance configuration is the organisation manager" : Validation [
    condition "organisationRole.roleKind == 'OrgManager' and organisationRole.assignmentStatus == 'RoleAccepted'"
    appliesTo e_Provider
    appliesTo e_Engine
    appliesTo e_EngineRoleAssignment
    appliesTo e_InstructionBlock
    priority VeryHigh
    description "Section 10. The configuration section is reserved to organisation managers, and every action on it refuses a user holding any other role."
]

AppRule rule_CredentialsNeverCollide "Credentials never collide" : Invariant [
    condition "credentialName == organisation + provider + engine"
    appliesTo e_Engine
    priority VeryHigh
    description "Section 10. Credentials are held under names the platform composes from the organisation, the provider, and the engine, so two organisations configuring the same provider can never collide. Changing an engine arrangement clears the credentials belonging to the arrangement abandoned, and editing an engine with the key field left empty keeps the key already stored."
]

AppRule rule_SelectionWithinOwnCatalogue "Engine selections stay within the own catalogue" : Validation [
    condition "engine.organisationRef == assignment.organisationRef"
    appliesTo e_EngineRoleAssignment
    priority High
    description "Section 10. A selection is only ever validated against the organisation own catalogue, never against another organisation or the platform, and an assignment naming anything else is cleared rather than stored."
]

AppRule rule_UnconfiguredInheritsDefaults "An unconfigured organisation inherits the platform text" : Decision [
    condition "organisationBlock == null"
    appliesTo e_InstructionBlock
    priority Medium
    description "Section 10. Until an organisation saves a block of its own, its page presents the platform organisation-level text as the starting point, and reverting discards the organisation text entirely and restores that same fallback. A newly created organisation begins with every engine role unassigned, and nothing on the platform requires them to be filled before conversation is possible."
]

AppRule rule_ExportRederivesWritePermission "An export re-derives the write permission" : Validation [
    condition "workspaceRole.roleKind in ['WsManager', 'WsDocumentManager'] and workspaceRole.assignmentStatus == 'RoleAccepted'"
    appliesTo e_ExportRequest
    priority VeryHigh
    description "Section 9. The platform verifies the statement, checks that the workspace named matches the one the statement was issued for, and then re-derives the user write permission from their current workspace role rather than relying on the read-only flag the statement carries."
]

AppRule rule_ExportSizeLimit "An export carries at most one megabyte" : Validation [
    condition "exportRequest.contentSize <= 1048576"
    appliesTo e_ExportRequest
    priority High
    description "Section 9. Content above one megabyte is refused, and the refusal is reported with the reason named rather than left to be guessed."
]

AppRule rule_DeliveryIndependentOfDocument "Delivery is independent of the document" : Invariant [
    condition "exportResult.createdDocumentRef != null"
    appliesTo e_ExportResult
    priority High
    description "Section 9. The two operations are deliberately not tied together. The document is the system of record and survives a failed delivery, and the platform reports the two outcomes separately: the response always names the created document and carries, beside it, whether the delivery was made, whether a live session received it, and, when it was not made, a stated reason."
]

AppRule rule_ChatSessionValidForOneHour "A chat session statement is valid for one hour" : Invariant [
    condition "chatSession.validForMinutes == 60"
    appliesTo e_ChatSession
    priority High
    description "Section 9. The statement is valid for one hour and is marked read-only unless the user holds an accepted workspace manager or document manager role."
]

AppRule rule_EditorSessionWriteFlag "The editor session write flag follows the workspace role" : Decision [
    condition "workspaceRole.roleKind in ['WsManager', 'WsDocumentManager']"
    appliesTo e_EditorSession
    priority VeryHigh
    description "Section 2 and Section 8. The flag is set from the user workspace role and is true only for a workspace manager or a workspace document manager; every other role, and any user with no accepted role, receives a read-only session. A launch from the public view of a public workspace is always read-only, whoever performs it."
]

AppRule rule_MembershipOnlyByInvitation "Membership grows only by invitation" : Invariant [
    condition "roleAssignment.originatedFromInvitation == true"
    appliesTo e_OrganisationRole
    appliesTo e_WorkspaceRole
    priority High
    description "Section 3. There is no way for a user to request admission: organisations are not listed publicly, and no page anywhere offers to apply."
]

/****************************************************
   Operational elements (Sections 5, 7 and 11)
*****************************************************/

OpsRetentionPolicy ret_ServicesAudit "Services audit retention" : Audit [
    duration 3650 d
    action Archive
    description "Section 7. The audit trail of every creation, change of content, and deletion of a services file cannot subsequently be altered or removed. The platform sets no expiry; the ten-year duration stated here is the nearest expressible form of indefinite retention."
]

OpsRetentionPolicy ret_DocumentHistory "Document history retention" : Operational [
    duration 3650 d
    action Archive
    description "Section 5. The change history records which of the tracked attributes changed, but not the content that was replaced and not the replacement of the file itself. The platform sets no expiry; the ten-year duration stated here is the nearest expressible form of indefinite retention."
]

OpsStore store_Platform "Platform store" : Relational [
    entity e_User
    entity ec_Organisation
    entity ec_Workspace
    entity ec_Document
    entity ec_Language
    entity ec_Assistance
    entity ec_Notification
    entity ec_Administration
    index ix_LanguageAcronym (e_LanguageFamily.acronymText) unique True
    index ix_WorkspaceKey (e_Workspace.workspaceKey) unique True
    index ix_DocumentScopeState (e_Document.ownerWorkspaceRef, e_Document.documentState)
    index ix_OrganisationRoleHolder (e_OrganisationRole.organisationRef, e_OrganisationRole.holder)
    index ix_WorkspaceRoleHolder (e_WorkspaceRole.workspaceRef, e_WorkspaceRole.holder)
    index ix_NotificationRecipient (e_Notification.recipientRef, e_Notification.isRead)
    auditing True
    softDeletion False
    retention ret_DocumentHistory
    description "Sections 3 to 11. The platform is the system of record for organisations, workspaces, documents, languages, assistance configuration, notifications, and the platform-level settings. Deletion of a document is permanent and is not an archive."
]

OpsObservability obs_Platform "Platform activity record" : Application [
    logging activityLog : Audit [
        format "Container history"
        destination "organisation, workspace, and document histories"
        retention ret_DocumentHistory
    ]
    logging servicesAuditLog : Audit [
        format "Services audit entry"
        destination "immutable audit trail"
        retention ret_ServicesAudit
    ]
    metric unreadNotifications : Gauge [ unit "notifications" description "Section 11. The count a bell in the site header shows." ]
    alert invitationEmailNotQueued when "invitedUser.emailAddress == null" [
        severity Info
        notify n_InvitationEmail
        description "Section 11. Email accompanies only the two events that create an invitation, and only when the invited user has an email address on record."
    ]
    description "Section 11. Beyond notifications the platform keeps an activity record, so the membership history of a container can be read from the container itself."
]

/****************************************************
   Requirements realised by the application (Sections 1 to 12)
*****************************************************/

FunctionalRequirement fr_ThreeLevelContainment "Three levels of containment" : System [
    statement "The platform shall organise specification work in an organisation that groups people and shared reference material, a workspace that holds one concrete body of specification work, and a document that carries a file, a type, and a lifecycle."
    stakeholder stk_Platform
    priority VeryHigh
    isPositive
    isConcrete
    isSolution
]

FunctionalRequirement fr_SingleAuthorityStructure "One authority structure" : System [
    statement "The platform shall grant every capability through a platform profile, an organisation role, a workspace role, or language maintainership, and through nothing else."
    stakeholder stk_Platform
    partOf mandatory fr_ThreeLevelContainment
    priority VeryHigh
    isPositive
    isConcrete
]

FunctionalRequirement fr_LanguageRegistry "Governed language registry" : System [
    statement "The platform shall hold specification languages as platform-level entities in two layers, a family carrying the identity of the language and a version carrying the particulars of one release, and shall decide which version of each family is in force."
    stakeholder stk_LanguageCustodian
    priority VeryHigh
    isPositive
    isConcrete
]

FunctionalRequirement fr_TemplateGeneration "Document generation from templates" : Business [
    statement "The platform shall produce a readable deliverable from an uploaded specification and a template of the same language family, and shall return it directly to the browser without retaining it."
    stakeholder stk_Practitioner
    priority High
    isPositive
    isConcrete
]

FunctionalRequirement fr_PlatformIsTheAuthority "The platform is the authority" : System [
    statement "The editor and the chatbot shall receive their working context from the platform, which decides who may read and write what, and neither shall write into the platform except through the delivery of a document the platform has just created."
    stakeholder stk_Platform
    partOf mandatory fr_SingleAuthorityStructure
    priority VeryHigh
    isPositive
    isConcrete
]

FunctionalRequirement fr_AssistancePerOrganisation "Assistance governed per organisation" : Business [
    statement "Each organisation shall maintain its own catalogue of assistance providers and engines, its own assignment of the nine engine roles, and its own instruction block."
    stakeholder stk_ContainerManager
    priority Medium
    isPositive
    isConcrete
]

FunctionalRequirement fr_MembershipNotifications "Membership notifications" : User [
    statement "The platform shall notify the invited user when an invitation is created, and every accepted manager of the affected container when an invitation is accepted or rejected, and shall produce no notification for any other event."
    stakeholder stk_Practitioner
    priority Medium
    isPositive
    isConcrete
]

QualityRequirement qr_PublishedOnlyVisibility "Published-only visibility" : Security : Confidentiality [
    statement "A document in any state other than published shall be invisible to members of the scope who hold no editing role, in the listings, in the counts, and on the document pages alike."
    stakeholder stk_Practitioner
    measure "States in which an ordinary member may see a document"
    target "Published only"
    priority VeryHigh
    isPositive
]

QualityRequirement qr_ExportSizeLimit "Export size limit" : Performance : Capacity [
    statement "An exported specification shall carry no more than one megabyte of content."
    expression [ <= 1 Capacity_MByte ]
    measure "Content size of an export request"
    target "At most one megabyte"
    stakeholder stk_ChatbotProduct
    priority Medium
    isPositive
]

QualityRequirement qr_ChatSessionValidity "Chat session validity" : Security : Authenticity [
    statement "A chat session statement shall remain valid for one hour and shall be marked read-only unless the user holds an accepted workspace manager or document manager role."
    expression [ = 1 Time_Hour ]
    measure "Validity of the session statement"
    target "One hour"
    stakeholder stk_ChatbotProduct
    priority High
    isPositive
]

QualityRequirement qr_DeliveryIndependence "Delivery independence" : Reliability : FaultTolerance [
    statement "A failed delivery of exported content into a live editing session shall not affect the document the platform created, and the two outcomes shall be reported separately."
    measure "Documents lost to a failed delivery"
    target "None"
    stakeholder stk_Platform
    priority High
    isPositive
]

QualityRequirement qr_AuditImmutability "Audit immutability" : Security : Accountability [
    statement "The audit trail of the custom services files shall not be alterable or removable after it is written."
    measure "Alterations possible on a written audit entry"
    target "None"
    stakeholder stk_LanguageCustodian
    priority High
    isPositive
]

QualityRequirement qr_LenientRendering "Lenient rendering" : Usability : Operability [
    statement "A value a template asks for and the specification does not supply shall render as blank rather than aborting the run, so that an incomplete specification still produces a document."
    measure "Runs aborted by an absent value"
    target "None"
    stakeholder stk_Practitioner
    priority Medium
    isPositive
    rationale "The cost is that a misspelled field name is indistinguishable from an absent value, which the template reference and the advisory check exist largely to compensate."
]

ConstraintRequirement cr_NoOrphanWorkspaces "No orphan workspaces" : Technical : Architecture [
    statement "An organisation shall not be deleted, nor left by its sole member, while workspaces still reference it; the workspaces must be removed or reassigned first."
    source "Section 3 of the system description"
    stakeholder stk_ContainerManager
    priority High
    isPositive
]

ConstraintRequirement cr_OneActiveVersionPerFamily "One version in force per family" : Technical : Standard [
    statement "At most one version of a language family shall be active at a time, and publishing one shall deprecate the version of the same family that was active."
    source "Section 7 of the system description"
    stakeholder stk_LanguageCustodian
    priority VeryHigh
    isPositive
]

ConstraintRequirement cr_GroundingOnlyPublishedText "Grounding knowledge only when published and textual" : Data : Privacy [
    statement "A document shall be markable as grounding knowledge only while it is in the published state and only when its file is textual, and shall lose the mark, and its place in the pool, the moment it leaves that state. Templates shall never be markable."
    source "Section 5 of the system description"
    stakeholder stk_Practitioner
    priority VeryHigh
    isPositive
]

ConstraintRequirement cr_CredentialsNeverCollide "Credentials never collide" : Technical : Privacy [
    statement "Engine credentials shall be held under names composed from the organisation, the provider, and the engine, so that two organisations configuring the same provider can never collide."
    source "Section 10 of the system description"
    stakeholder stk_ContainerManager
    priority VeryHigh
    isPositive
]

ConstraintRequirement cr_UnconfiguredInheritsDefaults "An unconfigured organisation inherits the defaults" : Organizational : Standard [
    statement "Until an organisation saves an instruction block of its own, the platform organisation-level text shall serve as its starting point and as the value a revert restores, and a newly created organisation shall begin with every engine role unassigned."
    source "Section 10 of the system description"
    stakeholder stk_ContainerManager
    priority Medium
    isPositive
]

ConstraintRequirement cr_ExportRederivesPermission "An export re-derives the write permission" : Technical : Compliance [
    statement "An export shall be authorised by the write permission re-derived from the user current workspace role, not by the read-only flag the session statement carries."
    source "Section 9 of the system description"
    stakeholder stk_Platform
    priority VeryHigh
    isPositive
]

ConstraintRequirement cr_LastManagerProtected "The last manager is protected" : Organizational : Compliance [
    statement "The last accepted manager of an organisation or of a workspace shall be neither demoted nor removed, and a departing last manager shall promote a successor first."
    source "Sections 3 and 4 of the system description"
    stakeholder stk_ContainerManager
    priority VeryHigh
    isPositive
]

ConstraintRequirement cr_DraftOnlyGrammarEditing "Grammar and services edited only in draft" : Technical : Compliance [
    statement "Grammar and services files shall be creatable, changeable, and removable only while their version is in the draft state, and the rule shall be enforced where the change is submitted rather than only by hiding controls."
    source "Section 7 of the system description"
    stakeholder stk_LanguageCustodian
    priority VeryHigh
    isPositive
]

ConstraintRequirement cr_AdministratorOnlyPublication "Publication is the administrator" : Organizational : Compliance [
    statement "Publishing or reactivating a language version, creating and deleting a language, and naming and removing its maintainers shall be reserved to the platform administrator and shall not be delegable through an organisation or workspace role."
    source "Sections 7 and 12 of the system description"
    stakeholder stk_PlatformAdministration
    priority VeryHigh
    isPositive
]

ConstraintRequirement cr_ManagerOnlyAssistanceConfiguration "Assistance configuration is the organisation manager" : Organizational : Compliance [
    statement "Every action on the assistance configuration section shall refuse a user holding any role other than accepted organisation manager."
    source "Section 10 of the system description"
    stakeholder stk_ContainerManager
    priority VeryHigh
    isPositive
]

ConstraintRequirement cr_DocumentSingleScope "A document has one owning scope" : Data : Standard [
    statement "A document shall belong either to a workspace or to an organisation, and never to both."
    source "Section 5 of the system description"
    stakeholder stk_Practitioner
    priority VeryHigh
    isPositive
]

ConstraintRequirement cr_WorkspaceNeverWithoutMembers "A workspace is never left without members" : Organizational : Compliance [
    statement "When the sole accepted member of a workspace leaves, the workspace shall be deleted together with whatever it still contains."
    source "Section 4 of the system description"
    stakeholder stk_ContainerManager
    priority High
    isPositive
]

ConstraintRequirement cr_NoContentReturnsByItself "Content does not return by itself" : Technical : Architecture [
    statement "Every interface between the platform and the editor shall carry content outward, and none shall accept content inward except the delivery of a document the platform has just created."
    source "Section 8 of the system description"
    stakeholder stk_Platform
    priority VeryHigh
    isPositive
]

/****************************************************
   Traceability to the requirements specification
*****************************************************/

ExternalRef ext_RSLSpecification "ITLingoCloud requirements specification" : RSL [
    source "ITLingoCloud-System-2026.rsl"
    version "RSL-2.10"
    description "The requirements-level twin of this specification. Actor, enumeration, entity, cluster, and use-case identifiers are shared between the two."
]

ExternalRef ext_SystemDescription "ITLingoCloud system description" : Other [
    source "ITLingoCloud-System-2026.tex"
    version "2026"
    description "The verified natural-language description of the platform as it exists today, in twelve sections."
]

/****************************************************
   Views
*****************************************************/

View v_Data "Data view" : DataView [
    ec_Organisation, ec_Workspace, ec_Document, ec_Language, ec_Assistance, ec_Interaction, ec_Notification, ec_Administration
    description "Sections 3 to 12. The eight clusters into which the thirty-four entities fall."
]

View v_Application "Application view" : ApplicationView [
    m_PublicWebsite, m_Portal, m_OrganisationDomain, m_WorkspaceDomain, m_DocumentDomain, m_TemplateGeneration, m_LanguageRegistry, m_EditorIntegration, m_ChatbotIntegration, m_AssistanceConfiguration, m_NotificationsAndActivity, m_Administration, m_KnowledgePool
    description "Sections 1 to 12. The modules of the platform and its two integrations."
]

View v_Security "Security view" : SecurityView [
    r_Visitor, r_PlatformMember, r_PlatformManager, r_PlatformAdministrator, r_OrganisationManager, r_OrganisationDocumentManager, r_OrganisationMember, r_WorkspaceManager, r_WorkspaceDocumentManager, r_WorkspaceMember, r_LanguageMaintainer, r_SpecificationEditor, r_Chatbot
    description "Section 2. Authority is held at three independent levels, plus language maintainership, which is independent of all three."
]

View v_UserInterface "User interface view" : UIView [
    ui_Public, ui_Portal, rs_Public, rs_Portal, rs_Administrative
    description "Sections 2 to 12. The public website, the authenticated portal, and the administrative interface."
]
