Files
mygo/docs/server/architecture.md
T

4.7 KiB

Server Architecture

Request Flow

HTTP request
  -> middleware
  -> handler
  -> service
  -> repository and storage

Layer Responsibilities

Layer Packages Responsibility
CLI cmd Register Cobra commands and start the application
Composition internal/app Open runtime resources and construct services
HTTP internal/server, internal/handler, internal/middleware, internal/api Route requests, authenticate principals, map DTOs, and write HTTP responses
Business internal/service, internal/model Validate operations, enforce authorization, and represent domain results and errors
Data internal/repository, internal/storage Persist metadata and file content
Infrastructure internal/config, internal/logging, internal/auth Load configuration, create loggers, and provide token and password primitives
Test support internal/testutil Prepare privileged fixtures through test-only helpers

Handlers define REST request and response DTOs. internal/api maps domain error kinds to HTTP status codes and error bodies.

Services use protocol-neutral domain types and errors. Each service constructor accepts the repository capabilities required by its use cases.

Repository query capabilities return domain records. Mutation capabilities use operation-specific parameter types, select writable columns explicitly, and apply the ownership and lifecycle predicates of the operation.

Storage backends manage staged and permanent file content. Repository records hold storage paths and file metadata.

Runtime Composition

app.Bootstrap opens the configured database, runs migrations, creates repositories and local storage, constructs the services, and returns app.WebApp.

server.NewRouter creates a Gin engine and registers the public and protected route groups. cmd/serve.go loads configuration, initializes logging, bootstraps the application, and runs graceful shutdown.

app.WebApp owns the database lifecycle and exposes the services, storage backend, configuration, and build metadata required by HTTP setup.

HTTP Boundaries

Global middleware runs in this order:

  1. Request ID
  2. Gin access logger
  3. Gin recovery

Protected routes use AuthRequired to authenticate an access token and attach a service principal. Administrator routes add AdminRequired to verify the principal's administrator flag.

Route group Access Capability
/api/v1/version Public Build metadata
/api/v1/auth Public Registration, login, refresh, and logout
/api/v1/account Authenticated Account and application passkeys
/api/v1/files Authenticated File and directory operations
/api/v1/admin/users Administrator User listing, lookup, and deletion

The route declarations in internal/server/routes_public.go and internal/server/routes_protected.go are the source of truth for individual methods and paths.

Persistence Commands

Area Mutation contract
Users Registration accepts RegisteredUserParams and creates an active non-admin user. Administration exposes a separate deletion command.
Sessions Refresh sessions are created, atomically consumed, revoked by token hash, or removed by maintenance operations.
Files Upload, directory creation, metadata update, and soft deletion use distinct parameter types and commands.
Credentials Application passkeys have explicit creation, usage-recording, and revocation operations.

Metadata updates can write name, parent_id, and GORM-managed updated_at. File ownership and active-state predicates scope user mutations.

Transaction Boundaries

File child creation, movement, and directory deletion use one hierarchy transaction protocol. PostgreSQL locks active owned source and parent rows in sorted ID order. SQLite adds _txlock=immediate to the configured DSN and reserves the write transaction before reading hierarchy state.

Refresh rotation locks, returns, and deletes the session in one transaction. A refresh session can issue one replacement token pair.

Uploads write to a staging path before promotion. The service promotes validated content before creating the active file record and attempts to remove promoted content when the database create fails.

Enforced Architecture Constraints

internal/architecture_test.go enforces these boundaries:

  • internal/model and internal/service do not import net/http, Gin, or internal/api.
  • internal/handler and internal/middleware do not import internal/repository.
  • Repository implementations do not call GORM Save; mutation methods select writable columns explicitly.