Accept planning baseline and UC-001 artifacts

Add the Use Case Diagram, Domain Model (use case and project), Dictionary,
Operation Contract, Sequence Diagram, review records RC-001 to RC-015 and
the Traceability Matrix. Split US-001 into one story per milestone, make
GitHub optional (AGPL license applied when chosen), and accept BC-001,
SA-001, PP-001, UCD-001, US-001, UC-001, SSD-001, DM-001, DM-002, OC-001,
SD-001, DICT-001 and MIL-001 to MIL-003 after review.

Refs: no issues synced yet (sync-project.sh dry run only)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 13:41:36 +08:00
co-authored by Claude Sonnet 5.5
parent fa3beaf1c1
commit 02875aee5f
32 changed files with 1666 additions and 73 deletions
+171
View File
@@ -0,0 +1,171 @@
# Domain Model (UC-001)
## Metadata
| Key | Value |
| --- | --- |
| ID | DM-001 |
| CrossReference | [UC-001], [SSD-001], [DICT-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-05 | Accepted | Jens Tirsvad Nielsen | S02 | Initial version | pending |
---
## Purpose and Scope
Covers [UC-001] "Create a new project". The concepts come from the nouns of that use case. Concept names are the PO terms recorded in [DICT-001]; the project-level model that consolidates all use cases is [DM-002].
## Diagram
Concepts, attributes and associations only — no operations.
```plantuml
@startuml
class Maintainer {
name
}
class Project {
name
description
visibility
}
class Configuration
class "Git Host" as GitHost {
name
web address
API address
}
class "Access Token" as AccessToken {
kind
}
class Owner {
name
kind
}
class Repository {
name
description
visibility
address
}
class "Gitea Repository" as GiteaRepository
class "GitHub Repository" as GitHubRepository
class License {
name
}
class Mirror {
interval
sync on commit
}
class "Local Project" as LocalProject {
directory
}
class Remote {
name
address
}
class Framework {
name
address
}
class "Framework Setup" as FrameworkSetup {
plan gate enabled
}
class Template {
name
}
class Summary {
created items
skipped items
next steps
}
Repository <|-- GiteaRepository
Repository <|-- GitHubRepository
Maintainer "1" --> "0..*" Project : creates
Configuration "1" --> "1..2" GitHost : defines
Configuration "1" --> "1..2" AccessToken : holds
AccessToken "1" --> "1" GitHost : gives access to
GitHost "1" --> "0..*" Owner : has
Owner "1" --> "0..*" Repository : owns
Project "1" --> "1" GiteaRepository : is stored in
Project "1" --> "0..1" GitHubRepository : is also stored in
GiteaRepository "1" --> "0..1" License : has
Mirror "1" --> "1" GiteaRepository : copies from
Mirror "1" --> "1" GitHubRepository : copies to
Mirror "0..*" --> "1" AccessToken : is authorised by
LocalProject "1" --> "1" Project : is the working copy of
LocalProject "1" --> "1..2" Remote : has
Remote "0..*" --> "1" Repository : points to
LocalProject "1" --> "1" Framework : includes
LocalProject "1" --> "1" FrameworkSetup : has
FrameworkSetup "0..*" --> "1" Framework : is installed from
Framework "1" --> "1..*" Template : provides
LocalProject "1" --> "0..*" Template : contains a copy of
Summary "1" --> "1" Project : reports on
@enduml
```
## Concept Table
| Concept | Definition | Attributes | Source (use case / glossary) |
| --- | --- | --- | --- |
| Maintainer | The person who creates a new project (S01 or S02) | name | [UC-001] primary actor |
| Project | The new software project being set up | name, description, visibility | [UC-001] "new project", step 3 |
| Configuration | The service addresses and access tokens the Maintainer has set up before starting | none | [UC-001] precondition, step 2 "configuration and credentials" |
| Git Host | A service that holds repositories: Gitea or GitHub | name, web address, API address | [UC-001] steps 5 to 7 "GitHub", "Gitea" |
| Access Token | A secret that lets the Maintainer act on a Git Host; it is never part of an address | kind | [UC-001] precondition "Gitea token", "GitHub PAT" |
| Owner | The user or organization on a Git Host that owns repositories | name, kind (user or organization) | [UC-001] step 3 "owner" |
| Repository | A place on a Git Host that holds a project's history | name, description, visibility, address | [UC-001] steps 5 and 6 "repository" |
| Gitea Repository | The Repository on Gitea; the source of truth | none beyond Repository | [UC-001] step 6 |
| GitHub Repository | The Repository on GitHub; receives its content from the Mirror | none beyond Repository | [UC-001] step 5 |
| License | The legal terms file added to a Gitea Repository (AGPL-3.0) when GitHub is chosen | name | [UC-001] step 6 "AGPL license" |
| Mirror | The push mirror that copies a Gitea Repository to a GitHub Repository | interval, sync on commit | [UC-001] step 7 "push mirror" |
| Local Project | The project directory on the Maintainer's machine | directory | [UC-001] step 8 "local project" |
| Remote | A named link from a Local Project to a Repository (`origin`, `github`) | name, address | [UC-001] step 8 "remote" |
| Framework | The SQA-QC-Framework added to a Local Project | name, address | [UC-001] step 9 "framework submodule" |
| Framework Setup | The skills and git hooks installed from the Framework, with the plan gate on or off | plan gate enabled | [UC-001] step 9 "skills and hooks", "plan gate" |
| Template | A file the Framework provides to copy into a project (`AGENTS.md`, artifact registry) | name | [UC-001] step 9 "templates" |
| Summary | The report of what was created, skipped or failed and how to continue | created items, skipped items, next steps | [UC-001] step 10 "summary" |
## Association Table
| From | Association (reading direction) | To | Multiplicity |
| --- | --- | --- | --- |
| Maintainer | creates | Project | 1 to 0..* |
| Configuration | defines | Git Host | 1 to 1..2 (GitHub is optional) |
| Configuration | holds | Access Token | 1 to 1..2 |
| Access Token | gives access to | Git Host | 1 to 1 |
| Git Host | has | Owner | 1 to 0..* |
| Owner | owns | Repository | 1 to 0..* |
| Project | is stored in | Gitea Repository | 1 to 1 |
| Project | is also stored in | GitHub Repository | 1 to 0..1 |
| Gitea Repository | has | License | 1 to 0..1 (1 when GitHub is chosen) |
| Mirror | copies from | Gitea Repository | 1 to 1 |
| Mirror | copies to | GitHub Repository | 1 to 1 |
| Mirror | is authorised by | Access Token | 0..* to 1 |
| Local Project | is the working copy of | Project | 1 to 1 |
| Local Project | has | Remote | 1 to 1..2 |
| Remote | points to | Repository | 0..* to 1 |
| Local Project | includes | Framework | 1 to 1 |
| Local Project | has | Framework Setup | 1 to 1 |
| Framework Setup | is installed from | Framework | 0..* to 1 |
| Framework | provides | Template | 1 to 1..* |
| Local Project | contains a copy of | Template | 1 to 0..* |
| Summary | reports on | Project | 1 to 1 |
## Generalizations
| General | Specializations | Is-a justification |
| --- | --- | --- |
| Repository | Gitea Repository, GitHub Repository | Each is a Repository with the same name, visibility and owner rules; they differ in role (source of truth against mirror target) |
---
[UC-001]: ./uc.md
[SSD-001]: ./ssd.md
[DICT-001]: ../dictionary.md
[DM-002]: ../domain-model.md
+90
View File
@@ -0,0 +1,90 @@
# Operation Contract
## Metadata
| Key | Value |
| --- | --- |
| ID | OC-001 |
| CrossReference | [SSD-001], [DM-001], [SD-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-05 | Accepted | Jens Tirsvad Nielsen | S02 | Initial version | pending |
---
Concepts below use the IT terms of [DICT-001] for the PO concepts of [DM-001]. `Run`, `ToolCheck`, `PreflightResult` and `PromptSet` are system concepts with no PO term and are not in the Domain Model.
## Contract: startProjectCreation
| Item | Value |
| --- | --- |
| Operation | `startProjectCreation(): PromptSet` |
| Traces to | `startProjectCreation` in [SSD-001] |
| Concepts | Run, Configuration, ToolCheck |
**Preconditions**
- None; this is the first operation of a Run.
**Postconditions**
- P1. A `Run` instance was created.
- P2. A `Configuration` instance was created from `config.env` and `.env`, with every value validated and the credentials held only in memory.
- P3. A `ToolCheck` instance was created and associated with the `Run`, recording that `git` and `curl` are present and whether `jq` is present.
- P4. The `Run` was associated with a `PromptSet` that is returned.
**Exceptions**
| Condition (failing precondition) | Outcome |
| --- | --- |
| `config.env` or `.env` is missing, or a value is missing or malformed | The `Run` ends with an error naming the key, never its value; nothing was changed |
| `git` or `curl` is missing | The `Run` ends with an error naming the tool; nothing was changed |
## Contract: provideProjectDetails
| Item | Value |
| --- | --- |
| Operation | `provideProjectDetails(name: String, description: String, visibility: Visibility, giteaOwner: Owner, githubOwner: Owner [0..1], directory: Path, enablePlanGate: Boolean): Summary` |
| Traces to | `provideProjectDetails` in [SSD-001] |
| Concepts | ProjectRequest, PreflightResult, GiteaRepository, GitHubRepository, LicenseFile, PushMirror, LocalProject, Remote, Submodule, HookSetup, Summary |
**Preconditions**
- A `Run` exists and its `Configuration` is valid (from `startProjectCreation`).
- `githubOwner` is present exactly when the Maintainer chose GitHub.
**Postconditions**
- P1. A `ProjectRequest` instance was created with the given attributes and associated with the `Run`.
- P2. A `PreflightResult` instance was created and associated with the `ProjectRequest`, recording that each token needed for the chosen hosts works, that each owner accepts new repositories, that the name is free on the chosen hosts, that `AGPL-3.0` is offered by Gitea when GitHub was chosen, and the outcome of the SSH test to Gitea on port 10022.
- P3. A `GiteaRepository` instance was created under `giteaOwner` with the given name, description and visibility, and associated with the `ProjectRequest`.
- P4. If `githubOwner` is present, a `LicenseFile` instance for `AGPL-3.0` was created and associated with the `GiteaRepository`, so that repository is not empty. Otherwise the `GiteaRepository` has no `LicenseFile` and is empty.
- P5. If `githubOwner` is present, an empty `GitHubRepository` instance was created under `githubOwner` and associated with the `ProjectRequest`.
- P6. If `githubOwner` is present, a `PushMirror` instance was created, associated with the `GiteaRepository` as source and the `GitHubRepository` as target, with its effective sync setting recorded, and a first sync was requested.
- P7. A `LocalProject` instance was created at `directory`, associated with the `ProjectRequest`. If the `GiteaRepository` is not empty, the `LocalProject` holds its history, including the `LicenseFile` commit.
- P8. A `Remote` named `origin` was associated with the `LocalProject`, pointing at the `GiteaRepository` over SSH if the SSH test passed, otherwise over HTTPS, with no credential in its URL.
- P9. If `githubOwner` is present, a `Remote` named `github` was associated with the `LocalProject`, pointing at the `GitHubRepository`, with no credential in its URL.
- P10. A `Submodule` named `framework` was associated with the `LocalProject`.
- P11. A `HookSetup` instance was associated with the `LocalProject`, recording that skills and git hooks were installed once and, if `enablePlanGate`, that the plan gate was enabled.
- P12. `AGENTS.md` and `docs/artifact-registry.md` exist in the `LocalProject`, each either newly copied from the framework templates or left as it was because the Maintainer declined to replace it.
- P13. A `Summary` instance was created listing every created item, every skipped item and the next step for anything that failed, and is returned. It contains no credential.
**Exceptions**
| Condition (failing precondition) | Outcome |
| --- | --- |
| A token is invalid, an owner refuses new repositories, or the name is taken on a chosen host (P2) | The `Run` ends before P3; nothing was created; the error names the failed check |
| GitHub was chosen and Gitea does not offer `AGPL-3.0` (P2) | The `Run` ends before P3; nothing was created |
| `GiteaRepository` creation fails after a `GitHubRepository` was created (P5, P3 ordering) | The `Summary` lists the `GitHubRepository` as created, the `GiteaRepository` as failed and how to continue |
| `PushMirror` creation fails (P6) | The `Summary` lists both repositories as created, the mirror as failed and how to continue; the local steps are not run |
| `directory` exists, or a target file exists, and the Maintainer declines replacing it (P7, P12) | That item is skipped and listed in the `Summary` |
| A different `core.hooksPath` exists and the Maintainer declines replacing it (P11) | Hooks are not installed and this is listed in the `Summary` |
| SSH to port 10022 fails and the `Submodule` cannot be added (P10) | The `Summary` lists the repositories as created, the submodule as failed, and the SSH prerequisite |
---
[SSD-001]: ./ssd.md
[DM-001]: ./dm.md
[DICT-001]: ../dictionary.md
[SD-001]: ./sd.md
+189
View File
@@ -0,0 +1,189 @@
# Sequence Diagram
## Metadata
| Key | Value |
| --- | --- |
| ID | SD-001 |
| CrossReference | [OC-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-05 | Accepted | Jens Tirsvad Nielsen | S02 | Initial version | pending |
---
Design objects are conceptual; in `create-project.sh` each becomes a small function group. No Design Class Diagram exists yet.
## Sequence: startProjectCreation
**Realizes:** `startProjectCreation` in [OC-001]
### Diagram
```plantuml
@startuml
actor Maintainer
participant ":ProjectCreator" as PC
participant ":ConfigLoader" as CL
participant ":ToolChecker" as TC
Maintainer -> PC : startProjectCreation()
activate PC
create CL
PC -> CL : load(config.env, .env)
activate CL
CL --> PC : configuration
deactivate CL
create TC
PC -> TC : check(git, curl, jq)
activate TC
TC --> PC : toolCheck
deactivate TC
PC --> Maintainer : promptSet
deactivate PC
destroy CL
destroy TC
@enduml
```
### Pattern Annotations
| Pattern (GRASP / GoF) | Applied to | Rationale |
| --- | --- | --- |
| Controller (GRASP) | `ProjectCreator` | Receives the system operations and coordinates, without doing the work itself |
| Pure Fabrication (GRASP) | `ConfigLoader`, `ToolChecker` | No domain concept owns parsing or tool checks; separate small units keep cohesion high |
| Creator (GRASP) | `ConfigLoader` creates `Configuration` | It holds the data needed to build and validate it |
### Postcondition Coverage
| Postcondition (from contract) | Satisfied by message |
| --- | --- |
| P1 Run created | `startProjectCreation` received by `ProjectCreator` |
| P2 Configuration created and validated | `load(config.env, .env)` |
| P3 ToolCheck created | `check(git, curl, jq)` |
| P4 PromptSet returned | `promptSet` return to the Maintainer |
### Responsibility Check
`ProjectCreator` only sequences two calls; parsing and validation sit in `ConfigLoader`, tool detection in `ToolChecker`. No object receives every message.
## Sequence: provideProjectDetails
**Realizes:** `provideProjectDetails` in [OC-001]
### Diagram
```plantuml
@startuml
actor Maintainer
participant ":ProjectCreator" as PC
participant ":Preflight" as PF
participant ":GiteaClient" as GT
participant ":GitHubClient" as GH
participant ":LocalProjectBuilder" as LB
participant ":FrameworkInstaller" as FI
participant ":SummaryReport" as SR
Maintainer -> PC : provideProjectDetails(name, description, visibility, giteaOwner, githubOwner, directory, enablePlanGate)
activate PC
create GT
PC -> GT : new(configuration)
opt githubOwner present
create GH
PC -> GH : new(configuration)
end
create PF
PC -> PF : check(request)
activate PF
PF -> GT : verifyToken(), ownerAccepts(giteaOwner), nameFree(name), hasLicense(AGPL-3.0)
opt githubOwner present
PF -> GH : verifyToken(), ownerAccepts(githubOwner), nameFree(name)
end
PF --> PC : preflightResult
deactivate PF
opt githubOwner present
PC -> GH : createEmptyRepository(githubOwner, name)
activate GH
GH --> PC : gitHubRepository
deactivate GH
end
alt githubOwner present
PC -> GT : createRepository(giteaOwner, name, license=AGPL-3.0)
else no GitHub
PC -> GT : createRepository(giteaOwner, name, license=none)
end
activate GT
GT --> PC : giteaRepository
deactivate GT
opt githubOwner present
PC -> GT : addPushMirror(giteaRepository, gitHubRepository)
activate GT
GT -> GT : requestSync()
GT --> PC : pushMirror
deactivate GT
end
create LB
PC -> LB : build(directory, giteaRepository, gitHubRepository, sshPassed)
activate LB
LB --> PC : localProject (remotes origin, github)
deactivate LB
create FI
PC -> FI : install(localProject, enablePlanGate)
activate FI
FI --> PC : submodule, hookSetup, templates
deactivate FI
create SR
PC -> SR : compose(all results)
SR --> PC : summary
PC --> Maintainer : summary
deactivate PC
destroy PF
destroy GT
destroy GH
destroy LB
destroy FI
destroy SR
@enduml
```
### Pattern Annotations
| Pattern (GRASP / GoF) | Applied to | Rationale |
| --- | --- | --- |
| Controller (GRASP) | `ProjectCreator` | Single entry for the system operation; sequences the steps and stops on the first failure |
| Pure Fabrication (GRASP) | `Preflight`, `LocalProjectBuilder`, `FrameworkInstaller`, `SummaryReport` | Each groups one responsibility that no domain concept owns |
| Facade (GoF) | `GiteaClient`, `GitHubClient` | Hide each host's HTTP API and credential handling behind a small interface; tokens never leave them |
| Protection from variations (GRASP) | Client classes | The `github`-optional and license variations are decided by the controller's `alt` and `opt`, not inside the clients |
### Postcondition Coverage
| Postcondition (from contract) | Satisfied by message |
| --- | --- |
| P1 ProjectRequest created | `provideProjectDetails` received by `ProjectCreator` |
| P2 PreflightResult created | `check(request)` |
| P3 GiteaRepository created | `createRepository(giteaOwner, name, license)` |
| P4 LicenseFile when GitHub chosen, otherwise empty | `createRepository(..., license=AGPL-3.0)` and the `alt` branch `license=none` |
| P5 empty GitHubRepository when chosen | `createEmptyRepository(githubOwner, name)` |
| P6 PushMirror and first sync | `addPushMirror(...)` and `requestSync()` |
| P7 LocalProject created, history from Gitea when not empty | `build(directory, ...)` |
| P8 origin remote (SSH if the test passed, else HTTPS) | `build(..., sshPassed)` |
| P9 github remote when chosen | `build(...)` |
| P10 framework Submodule | `install(localProject, ...)` |
| P11 HookSetup, plan gate if chosen | `install(localProject, enablePlanGate)` |
| P12 AGENTS.md and registry copied or kept | `install(...)` returning `templates` |
| P13 Summary created and returned | `compose(all results)` and the final return |
### Responsibility Check
`ProjectCreator` sequences and decides on the optional paths but performs no HTTP, git or file work. Host calls are in the two clients, local work in `LocalProjectBuilder` and `FrameworkInstaller`, reporting in `SummaryReport`, so cohesion stays high and no object receives all messages. Failure handling (exceptions in [OC-001]) is the controller's single stop-and-report rule and is not drawn.
---
[OC-001]: ./oc.md
+7 -4
View File
@@ -4,12 +4,13 @@
| Key | Value |
| --- | --- |
| ID | SSD-001 |
| CrossReference | [UC-001] |
| CrossReference | [UC-001], [DM-001], [OC-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-05 | Proposed | Jens Tirsvad Nielsen | S02 | Initial version | [424f14f] |
| 2026-10-05 | Rejected | Jens Tirsvad Nielsen | S02 | Initial version | [424f14f] |
| 2026-10-05 | Accepted | Jens Tirsvad Nielsen | S02 | Optional GitHub; choosing GitHub applies the AGPL license to the Gitea repository<br>Cited OC-001 and DM-001 | pending |
---
@@ -25,7 +26,7 @@ actor Maintainer as A
participant ":System" as S
A -> S : startProjectCreation()
S --> A : prompts for project details
A -> S : provideProjectDetails(name, description, visibility, githubOwner, giteaOwner, directory, enablePlanGate)
A -> S : provideProjectDetails(name, description, visibility, giteaOwner, githubOwner, directory, enablePlanGate)
S --> A : checks passed
S --> A : creation summary
@enduml
@@ -36,7 +37,7 @@ S --> A : creation summary
| Step | Message | Parameters | Return | Use case step |
| --- | --- | --- | --- | --- |
| 1 | startProjectCreation | none | prompts for project details (after configuration and tool checks) | 1, 2 |
| 2 | provideProjectDetails | name, description, visibility, githubOwner, giteaOwner, directory, enablePlanGate | checks passed, then a creation summary | 3 to 10 |
| 2 | provideProjectDetails | name, description, visibility, giteaOwner, githubOwner (optional; given means GitHub is chosen and the Gitea repository gets the AGPL license; omitted means no GitHub and no license), directory, enablePlanGate | checks passed, then a creation summary | 3 to 10 |
Steps 4 to 9 are internal to the system, so one operation covers them. A consent question (step 8a, 9a, 9b) is a prompt from the system and is out of scope for this diagram; failure flows are out of scope here.
@@ -47,4 +48,6 @@ The system is one script run. It starts with the first operation and ends after
---
[UC-001]: ./uc.md
[DM-001]: ./dm.md
[OC-001]: ./oc.md
[424f14f]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/424f14f4f5577bb47fea41c8f3a655dca953e6d8
+23 -16
View File
@@ -4,12 +4,13 @@
| Key | Value |
| --- | --- |
| ID | UC-001 |
| CrossReference | [US-001], [SA-001] |
| CrossReference | [UCD-001], [US-001], [SA-001], [DM-001] |
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-05 | Proposed | Jens Tirsvad Nielsen | S02 | Initial version | [424f14f] |
| 2026-10-05 | Deprecated | Jens Tirsvad Nielsen | S02 | Initial version | [424f14f] |
| 2026-10-05 | Accepted | Jens Tirsvad Nielsen | S02 | Optional GitHub; choosing GitHub applies the AGPL license to the Gitea repository<br>Cited DM-001 and UCD-001 | pending |
---
@@ -27,23 +28,23 @@
- **Preconditions:**
- `config.env` and `.env` exist and are valid.
- `git` and `curl` are installed.
- The Maintainer has a GitHub PAT, a Gitea token and SSH access to Gitea on port 10022.
- The Maintainer has a Gitea token, a GitHub PAT (only when GitHub is chosen) and SSH access to Gitea on port 10022.
- **Postconditions (success guarantee):**
- An empty repository exists on GitHub and on Gitea under the chosen owners.
- The Gitea repository is a push mirror to GitHub.
- A local project directory exists with credential-free remotes `origin` (Gitea) and `github`, the `framework` submodule, installed skills and hooks, and the copied templates.
- A repository exists on Gitea under the chosen owner. It is empty, or, when the Maintainer chose GitHub, it holds the AGPL license file.
- When the Maintainer chose to create a GitHub repository, an empty repository exists on GitHub under the chosen owner, the Gitea repository is a push mirror to it, and the AGPL license file reaches GitHub through the mirror.
- A local project directory exists with credential-free remotes `origin` (Gitea) and, when GitHub was chosen, `github`, the `framework` submodule, installed skills and hooks, and the copied templates.
- The Maintainer has a summary of what was created.
### Main Success Scenario
1. The Maintainer starts the project creation.
2. The system loads and validates the configuration and credentials and checks that the required tools exist.
3. The Maintainer provides the repository name, description, visibility, the GitHub owner, the Gitea owner, the local directory, and whether to enable the plan gate.
4. The system checks that both tokens work, that the owners accept new repositories, that the name is free on both hosts, and whether SSH to Gitea works.
5. The system creates the empty GitHub repository.
6. The system creates the empty Gitea repository.
7. The system configures the Gitea repository as a push mirror to GitHub and verifies it.
8. The system creates the local project with the `origin` and `github` remotes.
3. The Maintainer provides the repository name, description, visibility, the Gitea owner, whether to also create a GitHub repository (and if so its owner), the local directory, and whether to enable the plan gate.
4. The system checks that the tokens needed for the chosen hosts work, that the owners accept new repositories, that the name is free on those hosts, and whether SSH to Gitea works.
5. Optional: if the Maintainer chose GitHub, the system creates the empty GitHub repository.
6. The system creates the Gitea repository. If the Maintainer chose GitHub, the repository is created with the AGPL license file and so is not empty; otherwise it is empty and has no license.
7. Optional: if GitHub was chosen, the system configures the Gitea repository as a push mirror to GitHub and verifies it. A license file in the Gitea repository is pushed to GitHub by the mirror.
8. The system creates the local project with the `origin` remote and, if GitHub was chosen, the `github` remote.
9. The system adds the framework submodule, installs its skills and hooks (and the plan gate if chosen) and copies the templates.
10. The system reports a summary of what was created.
@@ -52,14 +53,16 @@
- 2a. A required tool is missing, or a configuration value is missing or malformed:
1. The system stops before any change and names the problem without showing a credential.
- 4a. A token is invalid, an owner does not accept the repository, or the name is taken:
1. The system stops before creating anything and says which check failed.
1. The system stops before creating anything and says which check failed. The GitHub token is only checked when GitHub was chosen.
- 4c. GitHub was chosen and the Gitea server does not offer the `AGPL-3.0` license:
1. The system stops before creating anything and names the missing license.
- 4b. SSH to Gitea does not work:
1. The system uses HTTPS for `origin` and warns that the framework submodule step will fail until SSH is configured.
- 5a, 6a, 7a. A step fails after an earlier one succeeded:
1. The system stops and reports what exists, what failed and how to continue.
- 8a, 9a. The target directory or a target file already exists:
1. The system asks the Maintainer before replacing it; on no, it skips that item and reports it.
- 9b. A different `core.hooksPath` is already set:
- 9b. A different git hooks setup is already configured in the project:
1. The system asks before replacing it.
### Special Requirements / Business Rules
@@ -68,8 +71,10 @@
| --- | --- |
| 2, 4 | A token never appears in output, logs, command lines, remote URLs or temporary files left behind |
| 3 | The GitHub owner and the Gitea owner are chosen separately; `GITHUB_USER` is only the authenticating account |
| 7 | The mirror direction is Gitea to GitHub |
| 8 | `origin` uses HTTPS derived from `GITEA_URL`, or SSH when the SSH test in step 4 passed |
| 3, 5, 7 | GitHub is optional; without it no GitHub repository, mirror or `github` remote is created and the GitHub credentials are not required |
| 6 | Choosing GitHub applies the AGPL license (key `AGPL-3.0`) to the Gitea repository when it is created, so that repository is not empty; without GitHub there is no license and the repository is empty |
| 7 | The mirror direction is Gitea to GitHub; the GitHub repository stays empty and receives its content from the mirror |
| 8 | `origin` uses HTTPS derived from `GITEA_URL`, or SSH when the SSH test in step 4 passed; when the Gitea repository is not empty (GitHub chosen) the local project is created by fetching it, not by an unrelated `git init` history |
| 8, 9 | Nothing is overwritten or deleted without consent, and no commit is made |
### Open Issues
@@ -78,6 +83,8 @@
---
[UCD-001]: ../use-case-diagram.md
[US-001]: ../user-stories.md
[SA-001]: ../stakeholder-analysis.md
[DM-001]: ./dm.md
[424f14f]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/424f14f4f5577bb47fea41c8f3a655dca953e6d8