195 lines
11 KiB
Markdown
195 lines
11 KiB
Markdown
# Engineering
|
|
|
|
Versioned Java standards, formatting, coverage checks, and the Gitea
|
|
Actions / Maven Java 25 / npm / Docker Compose recipe. Architecture and
|
|
specifications belong to [landscape](http://192.168.2.28:3000/wanjakrah/landscape).
|
|
Shared agent skills are maintained in landscape under skills/. Source attribution is in SOURCE.md.
|
|
|
|
## Start a project
|
|
|
|
Clone this repository and check out a released tag. Use JDK 25, Maven, Python 3,
|
|
Git, Docker with Compose, and a supported Node version for a frontend.
|
|
|
|
```sh
|
|
python3 create-project.py my-project ../my-project --version v2.0.0 --components both
|
|
```
|
|
|
|
Choose `backend`, `frontend`, or `both`. The command refuses existing destinations
|
|
and creates local files only. The backend starter is Quarkus; the frontend starter
|
|
uses npm and a minimal static page. Replace these starters with application code
|
|
while preserving the configured build commands and container contracts.
|
|
|
|
Initialize the resulting Git repository and commit its generated resources.
|
|
Create the remote repository separately, configure its runner and secrets, then
|
|
push. New projects default to the shared **host** runner label `mini-pc`.
|
|
Register it once at Gitea user scope for the owner of the projects; it then serves
|
|
existing and future repositories of that owner. `--runner` overrides the label for
|
|
another workstation. A label alone does not grant a repository access to a runner.
|
|
Do not install another runner service for every project.
|
|
|
|
## Consumer layout and configuration
|
|
|
|
`engineering.lock.json` selects a repository, immutable semantic version tag and
|
|
full commit SHA. `scripts/engineering.py` is the independent bootstrap, and
|
|
`generated/` is the committed release snapshot. No sibling checkout or global
|
|
skill installation is needed for ordinary use. Regeneration uses Git credentials
|
|
or a Git credential helper; never place credentials in the lockfile URL.
|
|
|
|
```sh
|
|
mvn -N -Pregenerate-engineering validate
|
|
python3 scripts/engineering.py --check
|
|
mvn -Dformat.mode=check clean verify
|
|
java generated/ci/Ci.java verify
|
|
java generated/ci/Ci.java test
|
|
java generated/ci/Ci.java release-test
|
|
```
|
|
|
|
The Maven regeneration profile skips formatting and works without `generated/`.
|
|
CI checks regeneration in a temporary checkout before running the pipeline. Added,
|
|
removed, modified and executable-bit changes fail the check. Runtime `target/`
|
|
and Python cache output are not release resources. Updates remove obsolete
|
|
generated files and never overwrite project-owned files outside `generated/`.
|
|
|
|
`engineering.properties` supplies project defaults; environment variables take
|
|
precedence. Required settings are `PROJECT_NAME` and at least one of
|
|
`BACKEND_MODULE` / `FRONTEND_MODULE`. Modules must be relative paths within the
|
|
project. Image names are `<PROJECT_NAME>-backend` and `<PROJECT_NAME>-frontend`;
|
|
changing PROJECT_NAME configures that namespace without changing shared code.
|
|
|
|
`BACKEND_CONTEXT` defaults to `.`, and `FRONTEND_CONTEXT` to its module path.
|
|
Both Dockerfiles provide a `prebuilt` target packaging verified output and a
|
|
default standalone source build. `FORMAT_DIRECTORIES` lists comma-separated
|
|
handwritten Java directories. Backend verification prepares a standards classpath,
|
|
runs the shared standards checker and requires 80% line coverage. Application
|
|
waivers remain in `tooling/standards/waivers.tsv`; no waiver is supplied by default.
|
|
|
|
`FRONTEND_TEST_COMMAND` is a JSON argument array, defaulting to the established
|
|
Vitest JUnit command; the starter sets `["npm","test"]`. Frontend verification
|
|
runs npm ci, lint, tests, and build. `BROWSER_TESTS=true` enables the recipe's
|
|
Playwright/JaCoCo integration for a backend and frontend. Configure
|
|
`CI_READINESS_URL`, `PLAYWRIGHT_IMAGE`, `CI_DATABASE`, `DATABASE_NAME` and
|
|
`DATABASE_USER` as appropriate. The browser recipe expects backend port 8080,
|
|
frontend port 8080, a backend JaCoCo agent and CLI prepared by Maven, and npm's
|
|
`e2e` script. Projects without that integration leave BROWSER_TESTS=false.
|
|
|
|
## Gitea setup
|
|
|
|
Build workflows need a host runner, `TARGET_PLATFORM` (for example linux/amd64),
|
|
and `REGISTRY_USER` / `REGISTRY_TOKEN` secrets with the repository/package access
|
|
needed for registry publication. The runner must also be able to read the pinned
|
|
engineering repository during the regeneration check. For private engineering,
|
|
install a read-only credential helper on the runner. Application registry and
|
|
release tokens are not used as implicit bootstrap credentials.
|
|
|
|
Publication is restricted to main after verification. Immutable commit images
|
|
are pulled back and checked before moving main tags. A host lock serializes
|
|
publication; a newer main prevents an older run from moving those tags.
|
|
|
|
Manual deployment and rollback workflows require variables `DEPLOY_HOST`,
|
|
`DEPLOY_USER`, `DEPLOY_SSH_PORT`, `DEPLOY_DIRECTORY`, `DEPLOY_REGISTRY`, and secrets
|
|
`RELEASE_TOKEN`, `DEPLOY_SSH_KEY`, `DEPLOY_KNOWN_HOSTS`. Release eligibility requires
|
|
a successful main-push build.yaml run. Keep build.yaml's filename when adapting
|
|
the recipe. Configure Gitea access, registry access and SSH host trust explicitly.
|
|
|
|
### Shared workstation runner
|
|
|
|
Set up the physical mini-pc once, using a consumer generated from this release:
|
|
|
|
```sh
|
|
export GITEA_SERVER_URL=http://192.168.2.28:3000
|
|
export RUNNER_NAME=mini-pc
|
|
export RUNNER_LABEL=mini-pc
|
|
export RUNNER_SCOPE=user
|
|
# Owner-only PAT file with permissions for the selected runner scope; never a workflow secret.
|
|
export GITEA_ADMIN_TOKEN_FILE="$HOME/.config/mini-pc-runner/admin-token"
|
|
java generated/ci/Ci.java configure-runner
|
|
java generated/ci/Ci.java install-runner
|
|
systemctl --user status mini-pc-runner
|
|
```
|
|
|
|
User scope uses `/api/v1/user/actions/runners/registration-token`, granting the
|
|
runner access to that user's current and future repositories. Organization and
|
|
instance scopes are optional alternatives (`RUNNER_ORGANIZATION` is required for
|
|
organization scope); instance scope requires a Gitea administrator. Repository
|
|
scope is available only for intentionally isolated runners. For this landscape,
|
|
use user scope for `wanjakrah` and the label `mini-pc`.
|
|
|
|
The runner has one slot shared by all projects. Its identity, service and state
|
|
are based on RUNNER_NAME, independent of PROJECT_NAME: `~/.local/share/mini-pc-runner`,
|
|
`~/.config/mini-pc-runner` and `mini-pc-runner.service`. Application credentials remain
|
|
in each application's secrets; never copy deployment credentials into runner defaults.
|
|
The host runner executes trusted project code as the workstation user; use it for
|
|
repositories maintained by the trusted owner. A new project's first push needs no
|
|
new workstation registration. Ensure the workstation is awake and Docker is ready.
|
|
|
|
For each new repository enable Actions, configure its own registry secrets and
|
|
TARGET_PLATFORM, then verify availability before pushing:
|
|
|
|
```sh
|
|
export CI_REPOSITORY=wanjakrah/my-project
|
|
# Owner PAT with read access to the repository, user profile and user runners.
|
|
java generated/ci/Ci.java check-runner
|
|
```
|
|
|
|
`configure-gitea` configures the application and does not create runner registrations.
|
|
`configure-runner` obtains the one-time shared registration token; `install-runner`
|
|
installs and registers the workstation. `--prepare-only` installs without registering
|
|
or starting. Installation supports Linux x86_64. `configure-docker` uses
|
|
INSECURE_REGISTRY only for a deliberately trusted internal HTTP registry.
|
|
Runner configuration and service templates are under ci/runner/.
|
|
|
|
When migrating a repository-scoped runner, keep the old registration and service
|
|
available until the new shared runner is online and has run a test workflow for
|
|
both an existing and a new consumer. Change all workflow labels to `mini-pc`, then
|
|
stop/disable the old service. Preserve its state outside Git for recovery. Do not
|
|
change application-specific deployment credential paths as part of this migration.
|
|
|
|
## Deployment and recovery
|
|
|
|
Projects own deploy/compose.yaml, deploy/health.sh and production.env. Set
|
|
COMPOSE_PROJECT, DEPENDENCY_SERVICES and REQUIRED_DEPLOY_SECRETS in project
|
|
configuration. Backend/frontend services use BACKEND_IMAGE / FRONTEND_IMAGE,
|
|
RELEASE_SHA and RELEASE_VERSION. Missing roles are represented by `-` in release
|
|
state; at least one image is required. Dependency services are started without
|
|
recreating their storage. Application containers alone are recreated on releases.
|
|
|
|
The remote mechanism requires a dedicated directory with owner-only
|
|
production.env containing BIND_IP, FRONTEND_PORT, DOCKER_BIN, DOCKER_CONFIG and
|
|
DOCKER_SUDO. The bind IP must be private, and the port 1024..65535. Provision a
|
|
pull-only registry login. `generated/deploy/provision.sh` accepts directory,
|
|
registry user, registry, bind IP, port and Docker executable. Optional
|
|
`generated/deploy/enable-docker.sh` takes deployment account and Docker executable
|
|
and must be run by an administrator after reviewing the Docker permission grant.
|
|
|
|
deploy/health.sh defines `application_health`, returning nonzero until the app is
|
|
ready. It can use the shared `compose` and `docker_cmd` functions. Health scripts,
|
|
Compose configuration, digests and deployment settings are retained per release.
|
|
For pre-S19 retained releases lacking health.sh/settings, the current project
|
|
health function/settings provide compatibility; verify them before rolling back
|
|
across this migration. Existing release-state JSON remains compatible.
|
|
|
|
Locking, a pending journal, digest/revision checks, bounded readiness checks and
|
|
automatic recovery protect replacement. An ambiguous state write or failed
|
|
recovery retains the journal and lock for manual inspection. Inspect retained
|
|
state, pending.json, history and diagnostics before repairing a deployment; never
|
|
blindly delete a lock. Each application must document its own recovery procedure
|
|
and database-schema rollback limits. Production deployment remains manual.
|
|
|
|
## Releases and upgrades
|
|
|
|
Release the resources, mechanisms and templates together. Use semantic version
|
|
tags `vMAJOR.MINOR.PATCH`; never move or reuse a published tag. Breaking changes
|
|
increase MAJOR. Record required project-file changes in UPGRADING.md before tagging.
|
|
Consumers update both tag and commit, regenerate, review and commit the diff.
|
|
The bootstrap rejects a tag resolving to a different commit and never upgrades
|
|
automatically. Templates create project-owned files once; upgrading only replaces
|
|
generated/. Bootstrap/profile/workflow changes require deliberate consumer edits.
|
|
|
|
## Validation
|
|
|
|
Run `python3 -m unittest discover -s tests`. The example definition is
|
|
examples/recipe-demo.json. Generate it with create-project.py and use the same
|
|
pipeline as any consumer. `tests/acceptance.py` exercises generated projects and
|
|
isolated deployment/rollback without touching production. Validation evidence is
|
|
recorded in VALIDATION.md.
|