S19 refinement
All checks were successful
Build, test and publish / verify (push) Successful in 8m15s
All checks were successful
Build, test and publish / verify (push) Successful in 8m15s
This commit is contained in:
215
adr/approved/ADR1_application-size.md
Normal file
215
adr/approved/ADR1_application-size.md
Normal file
@@ -0,0 +1,215 @@
|
||||
**ID:** ADR1 \
|
||||
**Title:** Application size \
|
||||
**Supersedes:** - \
|
||||
**Status:** APPROVED \
|
||||
**Expiration Date:** Six months after approval; record the calendar date upon manual approval.
|
||||
|
||||
## Context
|
||||
|
||||
Agile Dancers currently keeps its frontend, backend, CI pipeline, skills,
|
||||
specifications, ADRs, and other documentation in one repository. As the application
|
||||
grows, humans and agents need more context to understand individual tasks.
|
||||
Functional dependencies can become entangled, making changes and reuse harder.
|
||||
|
||||
The primary goal is to reduce the context required for a task. Supporting goals
|
||||
are preventing uncontrolled coupling and enabling reuse and replacement of
|
||||
capabilities. Repository organization, module boundaries, and deployment
|
||||
boundaries are separate architectural choices.
|
||||
|
||||
Business capabilities stand on their own, while an application system may support
|
||||
multiple capabilities. Loosely coupled capability boundaries allow implementations
|
||||
to change between custom software, libraries, and externally supplied components.
|
||||
Scheduling and school administration are candidate areas to examine; their exact
|
||||
system boundaries have not yet been decided.
|
||||
|
||||
Code-level modularity alone is insufficient when shared tables, materialized
|
||||
views, SQL scripts, or other database access bypass module boundaries. Separate
|
||||
services would have the same weakness without enforced data ownership.
|
||||
|
||||
Systems can initially run on the same physical server. Independent workload
|
||||
placement is nevertheless useful: computational work, such as runners and future
|
||||
scheduling calculations, may run on a mini-PC rather than the Synology. Independent
|
||||
scaling and release cycles are future possibilities rather than universal current
|
||||
requirements. Colocation reduces network exposure but process restarts, timeouts,
|
||||
and resource contention still require defined failure behavior.
|
||||
|
||||
Reusable engineering resources should also support other projects. Specifications
|
||||
can affect several projects, and ADRs apply across the application landscape.
|
||||
|
||||
## Decisions
|
||||
|
||||
### Capabilities and systems
|
||||
|
||||
Organize the landscape into independently deployable systems. Group capabilities
|
||||
into systems according to cohesion, data ownership, replacement needs, and
|
||||
operational requirements, including workload placement. Capability size alone does
|
||||
not justify a separate system.
|
||||
|
||||
Each system has its own repository and independent deployment lifecycle. Within a
|
||||
system, use modules to keep its capabilities loosely coupled. A capability does
|
||||
not automatically require its own service or deployment. Compute workers may be
|
||||
deployed separately from the business system that delegates work to them.
|
||||
|
||||
Capability contracts should allow implementations to be replaced by custom code,
|
||||
libraries, or external products, using adapters where necessary.
|
||||
|
||||
### Data ownership
|
||||
|
||||
Each system exclusively owns its data. Other systems access that data through
|
||||
explicit contracts, never through direct access to its storage. This restriction
|
||||
also applies to reporting queries, views, migrations, and maintenance scripts.
|
||||
Cross-system reporting requires explicit contracts or a separately owned
|
||||
projection.
|
||||
|
||||
PostgreSQL-backed systems initially share one PostgreSQL server/container, with
|
||||
separate databases or schemas and separate credentials whose permissions enforce
|
||||
ownership. Sharing physical infrastructure does not permit sharing storage access.
|
||||
Systems may choose other storage technologies when justified. This permits future
|
||||
CQRS designs without adopting CQRS through this ADR.
|
||||
|
||||
### Contracts and communication
|
||||
|
||||
Systems communicate through explicit, versioned contracts. Internal domain models
|
||||
and persistence entities remain private to their owning system and are not shared
|
||||
through common libraries. Contract definitions and generated clients may be shared.
|
||||
|
||||
Choose synchronous APIs or asynchronous messaging for each interaction according
|
||||
to its needs. Define failure behavior for each interaction. This ADR mandates
|
||||
neither a landscape-wide communication mechanism nor a message broker.
|
||||
|
||||
### Landscape and engineering resources
|
||||
|
||||
Maintain a landscape repository containing ADRs, specifications, and the capability
|
||||
and system map. Specifications identify the projects they affect and may span
|
||||
multiple systems. ADRs govern the application landscape according to their scope.
|
||||
Each system retains a README describing its implementation and operation.
|
||||
|
||||
Maintain reusable engineering resources, including pipeline components, skills,
|
||||
and general engineering documentation, separately from the landscape repository
|
||||
and individual systems. Group these resources according to maintenance and release
|
||||
needs; a separate repository per resource type is not required. Version shared
|
||||
resources so consuming projects can adopt updates deliberately.
|
||||
|
||||
### Adoption and review
|
||||
|
||||
Use this ADR as guidance and the starting point for follow-up specifications.
|
||||
Detailed system boundaries, contracts, and migration designs are follow-up work.
|
||||
Migrate incrementally, keeping the application working after each extraction.
|
||||
|
||||
Perform an initial review six months after approval. Review earlier if contract
|
||||
coordination, operational overhead, or persistent cross-system coupling becomes a
|
||||
significant burden. The expiration date triggers reevaluation and does not
|
||||
automatically invalidate the decision.
|
||||
|
||||
## Options considered
|
||||
|
||||
### 1. Improve navigation within the current structure
|
||||
|
||||
Keep the existing projects and deployment structure, improving focused
|
||||
documentation, task guidance, and file organization.
|
||||
|
||||
Pros:
|
||||
|
||||
- Requires little disruption or migration work.
|
||||
- Makes relevant context easier to find.
|
||||
- Retains simple local development and coordinated changes.
|
||||
|
||||
Cons:
|
||||
|
||||
- Offers limited protection against functional entanglement.
|
||||
- Does not enforce data ownership or support independent workload placement.
|
||||
- Leaves reuse and replacement dependent on existing application boundaries.
|
||||
|
||||
Not chosen because navigation improvements alone do not establish the ownership
|
||||
and replacement boundaries needed as the landscape grows.
|
||||
|
||||
### 2. Modular monolith in one repository
|
||||
|
||||
Organize capabilities into modules with explicit interfaces and dependency rules,
|
||||
while retaining coordinated deployment and one repository.
|
||||
|
||||
Pros:
|
||||
|
||||
- Reduces the code area needed to understand a capability.
|
||||
- Enables dependency checks and straightforward changes across modules.
|
||||
- Keeps deployment and in-process communication simple.
|
||||
|
||||
Cons:
|
||||
|
||||
- Shared database access can bypass code-level boundaries through tables, views,
|
||||
and scripts unless storage ownership is separately enforced.
|
||||
- Workload placement and deployment remain coupled.
|
||||
- Independent replacement and reuse may require later extraction.
|
||||
|
||||
Not chosen as the landscape-wide approach because independently enforced ownership
|
||||
and deployment boundaries are desired. Modular design remains part of the chosen
|
||||
approach inside each system.
|
||||
|
||||
### 3. Separate projects and repositories with coordinated deployment
|
||||
|
||||
Extract capabilities into separately built libraries or applications with
|
||||
versioned contracts, while retaining a coordinated deployment lifecycle.
|
||||
|
||||
Pros:
|
||||
|
||||
- Separates source and build context.
|
||||
- Gives reusable components their own versioned releases.
|
||||
- Retains a coordinated operational release process.
|
||||
|
||||
Cons:
|
||||
|
||||
- Changes spanning repositories require dependency release coordination.
|
||||
- Deployment remains coupled despite repository separation.
|
||||
- Repository separation alone does not enforce storage ownership or runtime
|
||||
independence.
|
||||
|
||||
Not chosen because it incurs repository coordination costs while retaining a
|
||||
deployment constraint that would limit workload placement and replacement.
|
||||
|
||||
### 4. Independently deployable systems with internal capability modules — chosen
|
||||
|
||||
Give systems their own repositories, deployment lifecycles, contracts, and enforced
|
||||
data ownership. Keep capabilities loosely coupled through modules within a system.
|
||||
Place compute workers independently where useful.
|
||||
|
||||
Pros:
|
||||
|
||||
- Supports focused development context and independent system evolution.
|
||||
- Enforces data ownership beyond code dependency rules through storage permissions.
|
||||
- Allows workloads to move between the Synology and mini-PC.
|
||||
- Supports capability replacement and reuse through explicit contracts.
|
||||
- Allows storage technology choices per system.
|
||||
|
||||
Cons:
|
||||
|
||||
- Requires contract compatibility and coordination for changes spanning systems.
|
||||
- Adds deployment, configuration, and operational maintenance for multiple processes.
|
||||
- Requires explicit failure handling and cross-system consistency decisions.
|
||||
- Sharing one server or PostgreSQL instance retains common infrastructure failure
|
||||
points despite logical isolation.
|
||||
|
||||
Chosen because ownership, replaceability, focused context, and independent workload
|
||||
placement outweigh the additional operational and contract coordination work.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Write follow-up specifications to map capabilities and dependencies, choose
|
||||
initial system boundaries, define contracts and data ownership, and plan
|
||||
extraction. This ADR does not itself settle those boundaries or implement them.
|
||||
- Establish the landscape repository and the repositories and versioning needed
|
||||
for reusable engineering resources. Preserve links between specifications and
|
||||
affected projects, and between system READMEs and landscape guidance.
|
||||
- Extract systems one at a time, establishing contracts and enforcing storage
|
||||
ownership as part of each extraction. Moving tables into separate schemas is
|
||||
insufficient while cross-system SQL access remains possible.
|
||||
- Adapt build and deployment pipelines to release systems independently and
|
||||
consume versioned shared engineering resources.
|
||||
- Add appropriate checks for module dependencies, contract compatibility, and
|
||||
storage isolation. Include views and scripts in boundary enforcement.
|
||||
- Specify how systems exchange information, handle failed interactions, and keep
|
||||
derived information consistent. These choices belong to the relevant follow-up
|
||||
specifications rather than a universal messaging requirement.
|
||||
- Keep one PostgreSQL container initially. Detailed backup and failover design is
|
||||
future work; logical data separation does not provide infrastructure failover.
|
||||
- Record the calendar review date when a maintainer manually approves this ADR.
|
||||
REFINED records the agreed proposal; approval remains a separate manual step.
|
||||
176
adr/approved/ADR2_http-api-contracts-and-tooling.md
Normal file
176
adr/approved/ADR2_http-api-contracts-and-tooling.md
Normal file
@@ -0,0 +1,176 @@
|
||||
**ID:** ADR2 \
|
||||
**Title:** HTTP API contracts and tooling \
|
||||
**Supersedes:** - \
|
||||
**Status:** APPROVED \
|
||||
**Expiration Date:** Six months after approval; record the calendar date upon manual approval.
|
||||
|
||||
## Context
|
||||
|
||||
Agile Dancers currently uses REST without an explicit architectural decision.
|
||||
The landscape needs agreed defaults for communication across system boundaries,
|
||||
contract documentation, client generation, compatibility, and error handling.
|
||||
|
||||
Interactions include frontend access, requests between business systems,
|
||||
delegation of long-running calculations to workers, change notifications, and
|
||||
external consumers. Most clients and servers are developed by the same maintainer.
|
||||
Consumers must nevertheless be able to upgrade independently. The independently
|
||||
deployable systems proposed in ADR1 are relevant context; ADR1 remains REFINED
|
||||
and is not approved through this decision.
|
||||
|
||||
The current frontend uses Angular, but future clients may use other frameworks
|
||||
or languages. Contracts and tooling should support that flexibility.
|
||||
|
||||
For now, interactions use a defined alternative path when another system is
|
||||
offline. Durable queued delivery is not a current requirement. More specialized
|
||||
communication mechanisms may become appropriate for particular interactions.
|
||||
|
||||
## Decisions
|
||||
|
||||
### Scope and communication style
|
||||
|
||||
Use HTTP APIs with JSON payloads as the default across system boundaries.
|
||||
Use resource-oriented endpoints where natural and action-oriented endpoints
|
||||
where they express business intent more clearly. Do not force business actions
|
||||
into CRUD operations. For example:
|
||||
|
||||
```text
|
||||
GET /api/v1/schedules/{id}
|
||||
POST /api/v1/schedules/{id}/calculate
|
||||
```
|
||||
|
||||
Action endpoints still follow HTTP method and status semantics. For long-running
|
||||
work, use an explicit job or operation resource with a status endpoint when the
|
||||
caller needs to track progress. A notification can initially use a direct HTTP
|
||||
request with documented failure behavior; this does not promise durable delivery.
|
||||
|
||||
These are landscape defaults. Document justified exceptions alongside the
|
||||
relevant interface, including the reason and the alternative contract and failure
|
||||
behavior. This ADR does not mandate GraphQL, RPC, or messaging infrastructure.
|
||||
|
||||
### Contracts and documentation
|
||||
|
||||
Describe HTTP APIs using OpenAPI. Normally generate the description from server
|
||||
code, adding explicit descriptions and annotations where needed. Review the
|
||||
resulting contract as a public interface; generation alone does not ensure
|
||||
completeness or backward compatibility.
|
||||
|
||||
Use self-hosted Scalar API Reference as the default interactive documentation UI.
|
||||
Keep the OpenAPI document independently available so consumers and tooling do not
|
||||
depend on the UI. Publish a contract artifact for each supported major version.
|
||||
|
||||
Choose an OpenAPI specification version supported by the server tooling, Scalar,
|
||||
and the selected client generators. Do not automatically adopt the latest version
|
||||
without checking that compatibility.
|
||||
|
||||
### Client generation
|
||||
|
||||
Generate client transport code and contract types from OpenAPI by default, using
|
||||
OpenAPI Generator. Select the generator appropriate to the consuming technology;
|
||||
use `typescript-angular` for Angular clients. This choice does not require future
|
||||
frontends to use Angular.
|
||||
|
||||
Pin generator versions and configuration for reproducible generation. Generate
|
||||
against a selected contract artifact rather than requiring a running server during
|
||||
the client build. Keep generated code separate from handwritten application logic
|
||||
and do not manually edit generated files. Generated static types do not by
|
||||
themselves provide runtime response validation.
|
||||
|
||||
### Versioning and compatibility
|
||||
|
||||
Put the major contract version in the URL, such as `/api/v1/schedules`.
|
||||
Keep backward-compatible changes within that major version. Introduce a new
|
||||
major version for breaking changes. Software release and generated client package
|
||||
versions may advance independently of the major contract version.
|
||||
|
||||
Allow consumers to upgrade independently. Normally support one contract version;
|
||||
during transitions, aim to support two. This is a guideline rather than a hard
|
||||
cap: additional versions may coexist when justified. Document supported versions,
|
||||
deprecation, and the transition plan, coordinating retirement with affected
|
||||
consumers. Check compatibility before releasing contract changes.
|
||||
|
||||
### Errors and offline behavior
|
||||
|
||||
Standardize API error bodies on RFC 9457 Problem Details using
|
||||
`application/problem+json` and appropriate HTTP status codes. Use stable problem
|
||||
`type` identifiers for programmatic handling and readable explanations for humans.
|
||||
Clients must not depend on parsing human-readable messages. Document expected
|
||||
errors in OpenAPI, including validation details where applicable. Do not expose
|
||||
internal exception details or sensitive information in error responses.
|
||||
|
||||
Define timeouts and the offline alternative path for each interaction. A network
|
||||
failure may produce no HTTP response, so consumers must handle that separately
|
||||
from a Problem Details response. Avoid automatic retries of actions unless
|
||||
repeating them is safe. Do not assume durable delivery or eventual replay.
|
||||
|
||||
### Adoption and review
|
||||
|
||||
Adopt incrementally for new interfaces and interfaces being substantially changed.
|
||||
Migrate existing interfaces through planned work while preserving compatibility
|
||||
for existing consumers. No immediate landscape-wide rewrite is required.
|
||||
|
||||
Review six months after approval, or earlier if integration needs expose
|
||||
limitations. The review date triggers reevaluation rather than automatic expiry.
|
||||
|
||||
## Options considered
|
||||
|
||||
### Communication approach
|
||||
|
||||
| Option | Pros | Cons | Outcome |
|
||||
| --- | --- | --- | --- |
|
||||
| Resource-oriented HTTP/JSON with action endpoints | Readable resources and business actions; supports different client technologies; retains HTTP semantics. | Requires consistent endpoint conventions and explicit handling of long-running work and failures. | Chosen as the default. |
|
||||
| GraphQL | Flexible data selection; typed schema; supports different consumer views of related data. | Adds query authorization and performance concerns; requires additional conventions for work delegation and notifications. | Not chosen: current needs and common client/server ownership do not justify the added complexity. |
|
||||
| RPC, including JSON-RPC and gRPC | Explicit operation contracts; JSON-RPC is lightweight; gRPC supports strongly typed generated clients. | Operation-oriented contracts require careful evolution; gRPC adds browser integration requirements. | Not chosen as the default: resource-oriented HTTP with optional actions better matches the desired interface flexibility. RPC remains a possible justified exception. |
|
||||
|
||||
### Contract description and authoring
|
||||
|
||||
| Option | Pros | Cons | Outcome |
|
||||
| --- | --- | --- | --- |
|
||||
| OpenAPI, normally generated from server code | Language-independent HTTP contracts; supports documentation and client generation; avoids separately maintaining a design language. | Needs annotations, review, and compatibility checks; generated output can be incomplete. | Chosen. |
|
||||
| TypeSpec generating OpenAPI | Dedicated contract authoring language; can generate descriptions and other artifacts. | Adds a language and compiler to maintain. | Not chosen: no current benefit sufficient to justify the additional tooling. |
|
||||
| RAML | API description language with reusable modeling constructs. | Its specification repository is archived, creating a maintenance concern for a new standard. | Not chosen. |
|
||||
|
||||
### Interactive documentation
|
||||
|
||||
| Option | Pros | Cons | Outcome |
|
||||
| --- | --- | --- | --- |
|
||||
| Scalar API Reference | Readable interactive documentation; integrated request testing; self-hosting and configuration options. | Requires integration and maintenance alongside the server framework. | Chosen: readability and testability are the primary purposes of the UI. |
|
||||
| Swagger UI | Interactive requests and authentication support; direct integration with Quarkus OpenAPI tooling. | Its expandable operation layout is less aligned with the preferred reading experience. | Not chosen as the landscape default. |
|
||||
|
||||
### Client generation
|
||||
|
||||
| Option | Pros | Cons | Outcome |
|
||||
| --- | --- | --- | --- |
|
||||
| OpenAPI Generator | Supports Angular and other client technologies in one tool family; configurable generation. | Generator-specific options and upgrades need management. | Chosen to support future technology changes. |
|
||||
| ng-openapi-gen | Angular-focused generation; npm-based tooling. | Other client technologies require another generator. | Not chosen as the landscape default. |
|
||||
| Handwritten clients | Direct control over client code and application integration. | Duplicates contract types and request details; increases drift risk. | Not chosen as the default. |
|
||||
|
||||
## Consequences
|
||||
|
||||
- Apply the defaults to new and substantially changed interfaces. Plan migration
|
||||
of existing interfaces incrementally, preserving consumer compatibility.
|
||||
- Generate and publish versioned OpenAPI artifacts. Add Scalar to provide
|
||||
interactive documentation and request testing for supported contracts.
|
||||
- Establish pinned OpenAPI Generator configurations for client technologies,
|
||||
initially Angular. Keep generated code separate from application logic.
|
||||
- Add contract validation and compatibility checks to release workflows. Verify
|
||||
generated clients against the actual contract before adopting generator upgrades.
|
||||
- Introduce URL major versions and coordinate deprecation with consumers. Normally
|
||||
maintain one version and temporarily two, documenting justified deviations.
|
||||
- Align API error responses with Problem Details and document expected failures.
|
||||
Define timeout and offline behavior per interaction, including safe retry rules.
|
||||
- Record justified exceptions alongside their interfaces rather than imposing an
|
||||
unsuitable communication mechanism on every interaction.
|
||||
- Record the calendar review date upon manual approval. REFINED captures the
|
||||
agreed proposal; approval remains a separate manual step.
|
||||
|
||||
### References
|
||||
|
||||
- [OpenAPI specification](https://spec.openapis.org/oas/)
|
||||
- [Scalar API Reference configuration](https://scalar.com/products/api-references/configuration)
|
||||
- [OpenAPI Generator: TypeScript Angular](https://openapi-generator.tech/docs/generators/typescript-angular/)
|
||||
- [RFC 9457: Problem Details for HTTP APIs](https://www.rfc-editor.org/rfc/rfc9457.html)
|
||||
- [Swagger UI configuration](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/)
|
||||
- [TypeSpec overview](https://learn.microsoft.com/en-us/azure/developer/typespec/overview/)
|
||||
- [RAML specification repository](https://github.com/raml-org/raml-spec)
|
||||
- [JSON-RPC specification](https://www.jsonrpc.org/specification)
|
||||
- [ng-openapi-gen](https://github.com/cyclosproject/ng-openapi-gen)
|
||||
Reference in New Issue
Block a user