routing table
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:
- Request ID
- Gin access logger
- 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/modelandinternal/servicedo not importnet/http, Gin, orinternal/api.internal/handlerandinternal/middlewaredo not importinternal/repository.- Repository implementations do not call GORM
Save; mutation methods select writable columns explicitly.