Update documentation

This commit is contained in:
Aaron Po
2026-02-15 21:13:07 -05:00
parent 0d52c937ce
commit b7bd287c48
11 changed files with 2792 additions and 863 deletions

View File

@@ -0,0 +1,75 @@
@startuml architecture
!theme plain
skinparam backgroundColor #FFFFFF
skinparam defaultFontName Arial
skinparam packageStyle rectangle
title The Biergarten App - Layered Architecture
package "API Layer" #E3F2FD {
[API.Core\nASP.NET Core Web API] as API
note right of API
- Controllers (Auth, User)
- Swagger/OpenAPI
- Middleware
- Health Checks
end note
}
package "Service Layer" #F3E5F5 {
[Service.Auth] as AuthSvc
[Service.UserManagement] as UserSvc
note right of AuthSvc
- Business Logic
- Validation
- Orchestration
end note
}
package "Infrastructure Layer" #FFF3E0 {
[Infrastructure.Repository] as Repo
[Infrastructure.Jwt] as JWT
[Infrastructure.PasswordHashing] as PwdHash
[Infrastructure.Email] as Email
}
package "Domain Layer" #E8F5E9 {
[Domain.Entities] as Domain
note right of Domain
- UserAccount
- UserCredential
- UserVerification
end note
}
database "SQL Server" {
[Stored Procedures] as SP
[Tables] as Tables
}
' Relationships
API --> AuthSvc
API --> UserSvc
AuthSvc --> Repo
AuthSvc --> JWT
AuthSvc --> PwdHash
AuthSvc --> Email
UserSvc --> Repo
Repo --> SP
Repo --> Domain
SP --> Tables
AuthSvc --> Domain
UserSvc --> Domain
' Notes
note left of Repo
SQL-first approach
All queries via
stored procedures
end note
@enduml

View File

@@ -0,0 +1,72 @@
@startuml authentication-flow
!theme plain
skinparam backgroundColor #FFFFFF
skinparam defaultFontName Arial
title User Authentication Flow
actor User
participant "API\nController" as API
participant "Service.Auth" as AuthSvc
participant "Password\nHasher" as PwdHash
participant "Repository" as Repo
participant "JWT\nProvider" as JWT
database "SQL Server\nStored Procedures" as DB
== Registration ==
User -> API: POST /api/auth/register
activate API
API -> AuthSvc: RegisterAsync(username, email, password)
activate AuthSvc
AuthSvc -> AuthSvc: Validate input
AuthSvc -> PwdHash: HashPassword(password)
activate PwdHash
PwdHash -> PwdHash: Argon2id\n(64MB, 4 iterations)
return hash + salt
AuthSvc -> Repo: CreateUserWithCredential(user, hash)
activate Repo
Repo -> DB: EXEC USP_RegisterUser
activate DB
DB -> DB: Create UserAccount\nCreate UserCredential\nCreate UserVerification
return userId
return userId
AuthSvc -> JWT: GenerateToken(userId, username)
activate JWT
JWT -> JWT: HS256 signing\nInclude claims
return JWT token
return RegisterResult{token, userId}
API -> User: 201 Created + JWT
deactivate API
== Login ==
User -> API: POST /api/auth/login
activate API
API -> AuthSvc: LoginAsync(username, password)
activate AuthSvc
AuthSvc -> Repo: GetUserCredential(username)
activate Repo
Repo -> DB: EXEC USP_GetUserAccountByUsername
activate DB
return user + credential
return UserCredential
AuthSvc -> PwdHash: VerifyPassword(password, hash, salt)
activate PwdHash
PwdHash -> PwdHash: Argon2id verify
return isValid
alt Password Valid
AuthSvc -> JWT: GenerateToken(userId, username)
activate JWT
return JWT token
AuthSvc -> Repo: UpdateLastLogin(userId)
activate Repo
Repo -> DB: Update LastLogin
return
return LoginResult{token, userId}
API -> User: 200 OK + JWT
else Invalid Credentials
return AuthenticationException
API -> User: 401 Unauthorized
end
deactivate API
@enduml

View File

@@ -0,0 +1,104 @@
@startuml database-schema
!theme plain
skinparam backgroundColor #FFFFFF
skinparam defaultFontName Arial
skinparam linetype ortho
title Key Database Schema - User & Authentication
entity "UserAccount" as User {
* UserAccountId: INT <<PK>>
--
* Username: NVARCHAR(30) <<UNIQUE>>
* Email: NVARCHAR(255) <<UNIQUE>>
* FirstName: NVARCHAR(50)
* LastName: NVARCHAR(50)
Bio: NVARCHAR(500)
CreatedAt: DATETIME2
UpdatedAt: DATETIME2
LastLoginAt: DATETIME2
}
entity "UserCredential" as Cred {
* UserCredentialId: INT <<PK>>
--
* UserAccountId: INT <<FK>>
* PasswordHash: VARBINARY(32)
* PasswordSalt: VARBINARY(16)
CredentialRotatedAt: DATETIME2
CredentialExpiresAt: DATETIME2
CredentialRevokedAt: DATETIME2
* IsActive: BIT
CreatedAt: DATETIME2
}
entity "UserVerification" as Verify {
* UserVerificationId: INT <<PK>>
--
* UserAccountId: INT <<FK>>
* IsVerified: BIT
VerifiedAt: DATETIME2
VerificationToken: NVARCHAR(255)
TokenExpiresAt: DATETIME2
}
entity "UserAvatar" as Avatar {
* UserAvatarId: INT <<PK>>
--
* UserAccountId: INT <<FK>>
PhotoId: INT <<FK>>
* IsActive: BIT
CreatedAt: DATETIME2
}
entity "UserFollow" as Follow {
* UserFollowId: INT <<PK>>
--
* FollowerUserId: INT <<FK>>
* FollowedUserId: INT <<FK>>
CreatedAt: DATETIME2
}
entity "Photo" as Photo {
* PhotoId: INT <<PK>>
--
* Url: NVARCHAR(500)
* CloudinaryPublicId: NVARCHAR(255)
Width: INT
Height: INT
Format: NVARCHAR(10)
CreatedAt: DATETIME2
}
' Relationships
User ||--o{ Cred : "has"
User ||--o| Verify : "has"
User ||--o{ Avatar : "has"
User ||--o{ Follow : "follows"
User ||--o{ Follow : "followed by"
Avatar }o--|| Photo : "refers to"
note right of Cred
Password hashing:
- Algorithm: Argon2id
- Memory: 64MB
- Iterations: 4
- Salt: 128-bit
- Hash: 256-bit
end note
note right of Verify
Account verification
via email token
with expiry
end note
note bottom of User
Core stored procedures:
- USP_RegisterUser
- USP_GetUserAccountByUsername
- USP_RotateUserCredential
- USP_UpdateUserAccount
end note
@enduml

View File

@@ -0,0 +1,94 @@
@startuml deployment
!theme plain
skinparam backgroundColor #FFFFFF
skinparam defaultFontName Arial
title Docker Deployment Architecture
package "Development Environment\n(docker-compose.dev.yaml)" #E3F2FD {
node "SQL Server" as DevDB {
database "Biergarten\nDatabase"
}
node "API Container" as DevAPI {
component "API.Core" as API1
component "Port: 8080"
}
node "Migrations" as DevMig {
component "Database.Migrations"
}
node "Seed" as DevSeed {
component "Database.Seed"
}
}
package "Test Environment\n(docker-compose.test.yaml)" #FFF3E0 {
node "SQL Server" as TestDB {
database "Test\nDatabase"
}
node "Migrations" as TestMig {
component "Database.Migrations"
}
node "Seed" as TestSeed {
component "Database.Seed"
}
node "API.Specs" as Specs {
component "Reqnroll\nIntegration Tests"
}
node "Repository Tests" as RepoTests {
component "xUnit\nData Access Tests"
}
node "Service Tests" as SvcTests {
component "xUnit\nAuth Service Tests"
}
}
folder "test-results/" as Results {
file "api-specs/results.trx"
file "repository-tests/results.trx"
file "service-auth-tests/results.trx"
}
' Development flow
DevMig --> DevDB : migrate
DevSeed --> DevDB : seed
DevAPI --> DevDB : connect
' Test flow
TestMig --> TestDB : migrate
TestSeed --> TestDB : seed
Specs --> TestDB : test
RepoTests --> TestDB : test
SvcTests ..> TestDB : mock
Specs --> Results : export
RepoTests --> Results : export
SvcTests --> Results : export
' Notes
note right of DevAPI
Swagger UI:
http://localhost:8080/swagger
end note
note right of Results
Test results
exported to host
end note
note bottom of TestDB
Isolated environment
Fresh database each run
end note
@enduml