docs: restructure server and web documentation into ADR files and a
routing table
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
# ADR-0001: Select the Server Foundation
|
||||
|
||||
Status: Accepted
|
||||
Date: 2026-04-25
|
||||
|
||||
## Context
|
||||
|
||||
MyGO needed a server stack that supports local development, relational metadata, configurable deployment, and multiple file storage backends.
|
||||
|
||||
## Decision
|
||||
|
||||
- Use Gin for HTTP routing and middleware.
|
||||
- Use GORM with SQLite and PostgreSQL drivers.
|
||||
- Use Viper for YAML and environment configuration, with a Cobra flag for the config file path.
|
||||
- Use local file storage first and expose storage through `internal/storage`.
|
||||
- Use UUIDs for file and domain identities.
|
||||
- Use JWT access tokens and database-backed refresh sessions.
|
||||
- Use offset and limit pagination for the initial API.
|
||||
- Return direct JSON success bodies and a shared JSON error shape.
|
||||
- Organize the server as Handler -> Service -> Repository and Storage.
|
||||
|
||||
## Consequences
|
||||
|
||||
- SQLite supports a zero-service local setup; PostgreSQL supports multi-instance deployments.
|
||||
- Repository and storage interfaces isolate infrastructure choices from services.
|
||||
- Database-backed refresh sessions support rotation and revocation.
|
||||
- Offset pagination remains suitable for the current dataset size and API scope.
|
||||
@@ -0,0 +1,24 @@
|
||||
# ADR-0002: Establish the REST API Foundation
|
||||
|
||||
Status: Accepted
|
||||
Date: 2026-04-27
|
||||
|
||||
## Context
|
||||
|
||||
The first HTTP slice needed stable versioning, response conventions, dependency composition, and server lifecycle behavior.
|
||||
|
||||
## Decision
|
||||
|
||||
- Place REST routes under `/api/v1`.
|
||||
- Expose build metadata through `GET /api/v1/version`.
|
||||
- Return resource bodies directly for successful requests.
|
||||
- Return errors as `{"error":{"message":"..."}}` with optional diagnostic fields.
|
||||
- Use `internal/app.Bootstrap` to construct runtime dependencies and return `app.WebApp`.
|
||||
- Register public and protected routes in separate server functions.
|
||||
- Stop accepting new requests during shutdown and allow in-flight requests to finish.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Future REST endpoints share one version boundary and response convention.
|
||||
- `app.WebApp` provides the services and metadata required by route setup.
|
||||
- HTTP lifecycle behavior stays in `internal/server`.
|
||||
@@ -0,0 +1,24 @@
|
||||
# ADR-0003: Define Authentication Contracts
|
||||
|
||||
Status: Accepted
|
||||
Date: 2026-04-29
|
||||
|
||||
## Context
|
||||
|
||||
Authentication requires distinct access and refresh behavior, stable duration parsing, and safe development defaults.
|
||||
|
||||
## Decision
|
||||
|
||||
- Use `AuthHandler` for public authentication routes and `AccountHandler` for authenticated account routes.
|
||||
- Add a JWT `type` claim that distinguishes access and refresh tokens.
|
||||
- Verify token type at the boundary that consumes the token.
|
||||
- Store configuration durations as `time.Duration` values.
|
||||
- Replace known development JWT placeholders with a random runtime secret during configuration loading.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Access tokens authenticate protected requests.
|
||||
- Refresh tokens rotate token pairs through database sessions.
|
||||
- Invalid duration values fail during startup.
|
||||
- Tokens signed with the generated development secret expire when the process restarts.
|
||||
- Multi-instance deployments require a stable configured secret.
|
||||
@@ -0,0 +1,24 @@
|
||||
# ADR-0004: Stage Uploads Before Publication
|
||||
|
||||
Status: Accepted
|
||||
Date: 2026-07-05
|
||||
|
||||
## Context
|
||||
|
||||
File uploads need streaming size enforcement and a clear publication boundary between stored content and visible metadata.
|
||||
|
||||
## Decision
|
||||
|
||||
- Stream multipart bodies with `Request.MultipartReader`.
|
||||
- Interpret `storage.max_upload_size = 0` as unlimited and positive values as a byte limit.
|
||||
- Write upload content to a staging path.
|
||||
- Validate and promote staged content before creating the active database record.
|
||||
- Pass multipart `parent_id` as a query parameter.
|
||||
- Convert HTTP body errors in the handler and domain upload errors in the service.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Upload size checks apply while the request streams.
|
||||
- Interrupted and rejected uploads remain in the staging namespace.
|
||||
- Local storage promotes with rename and uses copy and delete across filesystems.
|
||||
- A failed database create can leave a promoted object; the service attempts cleanup and the object remains invisible to the file API.
|
||||
@@ -0,0 +1,23 @@
|
||||
# ADR-0005: Keep Service Contracts Protocol-Neutral
|
||||
|
||||
Status: Accepted
|
||||
Date: 2026-07-05
|
||||
|
||||
## Context
|
||||
|
||||
MyGO exposes REST today and is designed to support additional protocols. Business services need contracts that transport adapters can reuse.
|
||||
|
||||
## Decision
|
||||
|
||||
- Services return domain results and `model.AppError` values.
|
||||
- HTTP handlers own REST response DTOs.
|
||||
- `internal/api` maps domain error kinds to REST responses.
|
||||
- HTTP packages obtain application behavior through service contracts and authenticated principals.
|
||||
- Architecture tests enforce the package dependency boundaries.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Additional protocol adapters can reuse the existing services.
|
||||
- Each protocol adapter defines its own response mapping.
|
||||
- Service tests exercise business behavior without constructing HTTP requests.
|
||||
- Error responses can include `error.log_id` for failures recorded by the server.
|
||||
@@ -0,0 +1,22 @@
|
||||
# ADR-0006: Conceal File Ownership Boundaries
|
||||
|
||||
Status: Accepted
|
||||
Date: 2026-07-15
|
||||
|
||||
## Context
|
||||
|
||||
Authenticated callers must not infer the existence of files owned by another user from status codes or response messages.
|
||||
|
||||
## Decision
|
||||
|
||||
- Map missing, deleted, and cross-user file targets to the same not-found result.
|
||||
- Apply the same rule to parent-directory lookups.
|
||||
- Return success for one deletion of an active owned file.
|
||||
- Return not found for repeated deletion and cross-user deletion.
|
||||
- Guard soft deletion with ownership and active-state predicates.
|
||||
|
||||
## Consequences
|
||||
|
||||
- File responses conceal resource ownership from other authenticated users.
|
||||
- The first successful deletion returns `204 No Content`; later attempts return `404 Not Found`.
|
||||
- Non-empty directory deletion continues to return a conflict.
|
||||
@@ -0,0 +1,29 @@
|
||||
# ADR-0007: Use Command-Scoped Persistence Mutations
|
||||
|
||||
Status: Accepted
|
||||
Date: 2026-07-16
|
||||
|
||||
## Context
|
||||
|
||||
Each business operation needs a persistence contract that exposes its writable fields, authorization predicates, and transaction boundary.
|
||||
|
||||
## Decision
|
||||
|
||||
- Give each mutation a use-case-specific method and parameter type.
|
||||
- Inject the query and mutation capabilities required by each service.
|
||||
- Select mutation columns explicitly.
|
||||
- Include ownership, credential type, and active-state predicates where the operation requires them.
|
||||
- Revalidate file hierarchy state inside the mutation transaction.
|
||||
- Lock PostgreSQL hierarchy rows in sorted order.
|
||||
- Start SQLite write transactions with `_txlock=immediate`.
|
||||
- Consume a refresh session in one lock, read, and delete transaction.
|
||||
- Use `internal/testutil` for privileged fixture setup.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Mutation inputs expose the fields writable by the use case.
|
||||
- Guarded zero-row updates map to domain not-found results.
|
||||
- File hierarchy mutations preserve active parent-child relationships under concurrency.
|
||||
- One refresh session issues one replacement token pair.
|
||||
- SQLite serializes these write transactions from their first database operation.
|
||||
- Future mutations require a named command and an explicit capability.
|
||||
Reference in New Issue
Block a user