mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
Update documentation
This commit is contained in:
75
docs/diagrams/architecture.puml
Normal file
75
docs/diagrams/architecture.puml
Normal 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
|
||||
72
docs/diagrams/authentication-flow.puml
Normal file
72
docs/diagrams/authentication-flow.puml
Normal 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
|
||||
104
docs/diagrams/database-schema.puml
Normal file
104
docs/diagrams/database-schema.puml
Normal 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
|
||||
94
docs/diagrams/deployment.puml
Normal file
94
docs/diagrams/deployment.puml
Normal 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
|
||||
Reference in New Issue
Block a user