519aa35f1f
routing table
87 lines
4.7 KiB
Markdown
87 lines
4.7 KiB
Markdown
# Server Architecture
|
|
|
|
## Request Flow
|
|
|
|
```text
|
|
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.
|