Skip to content

Commit

Permalink
chore(docs): create a simple developer documentation for getting started
Browse files Browse the repository at this point in the history
  • Loading branch information
vehagn committed Nov 10, 2024
1 parent 9647b17 commit 3c51533
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 11 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Deltahouse
# Deltabeer

A rewrite of an old project called [DeltaPi](https://github.com/vehagn/DeltaPi) for trading tokens for refreshments at
the student office.
Deltabeer is the backend of _Ølsystemet_,
a program for trading tokens for refreshments at the student office.

## Getting started

Expand All @@ -17,4 +17,6 @@ To start the application using an in-memory H2 database run
The application will be available at [localhost:8080](http://localhost:8080).

Open API (swagger) documentation is available
at [http://localhost:8080/swagger-ui/index.html](http://localhost:8080/swagger-ui/index.html).
at [http://localhost:8080/swagger-ui/index.html](http://localhost:8080/swagger-ui/index.html).

For contributing read the [DEVELOPERS.md](./docs/DEVELOPERS.md) documentation.
96 changes: 96 additions & 0 deletions docs/DEVELOPERS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Developer information

Deltabeer is written in mainly [Kotlin](https://kotlinlang.org/) using [Gradle](https://gradle.org/) as a build tool and
leveraging the [Spring Boot](https://spring.io/projects/spring-boot) framework.
[Hibernate](https://hibernate.org/) is used for persistence.

## Model

This program follows the Repository [MVC pattern](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)
(Model–View–Controller) with [DTO](https://en.wikipedia.org/wiki/Data_transfer_object)s for transferring data through
a [REST](https://en.wikipedia.org/wiki/REST)
-like [JSON](https://en.wikipedia.org/wiki/JSON) [API](https://en.wikipedia.org/wiki/API),
and [DAO](https://en.wikipedia.org/wiki/Data_access_object)s for accessing and interacting with the database.
A third object type without a postfix is used internally for business logic.

```mermaid
---
title: Model–View–Controller with a repositry
---
graph TD
Browser -->|Requests| Controller
Controller -->|Calls| Service
Service -->|Interacts with| Repository
Repository -->|CRUD Operations| Database
Repository -->|Returns Data| Service
Service -->|Returns Data| Controller
Controller -->|Selects| View
View -->|Renders| Browser
Service -->|Business Logic| Service
Database -->|Returns Data| Repository
```

DTOs live in the View-layer, whereas DAOs live in the Repository-layer.
The Controller-layer is the interface between DTOs and internal objects which are used by Services in the Model-layer.
The Model-layer also translates between internal objects and DAOs that represents objects in the database.

Spring takes care of the Controller- and View-layers
using [Decorations](https://www.baeldung.com/spring-interface-driven-controllers) and Hibernate handles the Repository
layer, so we mostly have to care about the Model-layer.
This includes configuration and business login in the Service.

## Database

The database is modelled using Hibernate decorations (using `spring.jps.hibernate.ddl-auto: create` and
`spring.jps.show-sql: true`),
and then copied over to regular SQL creation queries to use with [Flyway](https://github.com/flyway/flyway) for better
control over the database.

Normally `hibernate.ddl-auto` is set to `validate`,
so remember to update the Flyway migrations when changing the database using Hibernate.

![Database structure](img/database.png "Database relational diagram")

The main database table is the _Users_ table which — as the name indicates, contains the users registered in the system.
Each user is given a unique ID which is not exposed.
Users are retrieved using either the cardID or e-mail field which must both be unique to each user.
This opens up for the possibility of changing a user's cardID using e-mail or updating the e-mail using the cardID.

A wallet is created when a user first performs a transactions, each user can only have one wallet.
This wallet is stored in the aptly named _Wallets table.
Each wallet transaction (i.e. buying or spending tokens) is stored in the _Transactions_ table for auditing purposes.
It should be possible to re-build and verify a Wallet balance using the transaction log for auditing purposes.

For personalisation and fun, it's possible to register different _properties_ on a user,
these properties are defined in
the [UserPropertyType](../src/main/kotlin/dev/stonegarden/deltahouse/user/UserPropertyType.kt) enum as
either `TITLE`, `COMMENT`, `CREDIT` or `OTHER`.
The `CREDIT` property is used to give users the possibility of having a negative wallet balance.

A planned feature is the use of this system to register items and keeping track of borrowed items by user,
though this can probably be scrapped if there's no need for the feature.
This could perhaps be split into a different application.

## Profiles

When running locally the `local-h2` can be used to spin up an in-memory [H2-database](https://www.h2database.com/).
This profile is also set up to run the migrations present in the `db/testdata` resources folder,
i.e. populate the database with testdata.

There is also a `local-postgres` profile for connecting with a local [PostgreSQL](https://www.postgresql.org/) database.

## Testing

[JUnit 5](https://junit.org/junit5/) is used for testing.
Developers should aim to write simple [unit tests](https://en.wikipedia.org/wiki/Unit_testing) for each new feature or
fix they create.
This is to avoid regressions and maintain a stable codebase.

## Development

Developers should aim to use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) for concise commit
comments explaining what they've changed.

It would also be good to introduce a Changelog following [Keep A Changelog](https://keepachangelog.com/en/1.1.0/)
practises,
and follow [Semantic Versioning](https://semver.org/).
62 changes: 62 additions & 0 deletions docs/img/database.mmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
classDiagram
direction BT
class BorrowedItems {
long id
ZonedDateTime borrowedDate
String itemComment
ZonedDateTime returnByDate
ZonedDateTime returnedDate
}
class Items {
long id
String changedBy
ZonedDateTime changedDate
String createdBy
ZonedDateTime createdDate
String description
String name
}
class Transactions {
long id
short balanceChange
int previousBalance
Long previousTransactionId
ZonedDateTime transactionDate
Long transactionHash
}
class UserProperties {
long id
String changedBy
ZonedDateTime changedDate
String createdBy
ZonedDateTime createdDate
UserPropertyType propertyType
String propertyValue
}
class Users {
long id
ZonedDateTime birthday
long cardId
String changedBy
ZonedDateTime changedDate
String createdBy
ZonedDateTime createdDate
ZonedDateTime deletedDate
String email
String firstName
boolean isMember
String lastName
String userGroup
}
class Wallets {
long id
int cashBalance
int totalSpent
}

BorrowedItems "0..*" --> "0..1" Items
BorrowedItems "0..*" --> "0..1" Users
Transactions "0..*" --> "0..1" Wallets
Users "0..1" --> "0..*" UserProperties
Wallets "0..1" --> "0..1" Transactions
Wallets "0..1" --> "0..1" Users
Binary file added docs/img/database.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import jakarta.persistence.*
import java.io.Serializable
import java.time.ZonedDateTime

@Entity(name = "BORROWED_ITEMS")
@Entity(name = "BorrowedItems")
data class BorrowedItemDAO(
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "borrowed_item_id_generator")
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/dev/stonegarden/deltahouse/item/ItemDAO.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import org.hibernate.annotations.UpdateTimestamp
import java.io.Serializable
import java.time.ZonedDateTime

@Entity(name = "ITEMS")
@Entity(name = "Items")
data class ItemDAO(
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "item_id_generator")
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/dev/stonegarden/deltahouse/user/UserDAO.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import org.hibernate.annotations.UpdateTimestamp
import java.io.Serializable
import java.time.ZonedDateTime

@Entity(name = "USERS")
@Entity(name = "Users")
data class UserDAO(
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_id_generator")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import org.hibernate.annotations.UpdateTimestamp
import java.io.Serializable
import java.time.ZonedDateTime

@Entity(name = "USER_PROPERTIES")
@Entity(name = "UserProperties")
data class UserPropertyDAO(
@Enumerated(EnumType.STRING)
@Column(length = 15, nullable = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import org.hibernate.annotations.CreationTimestamp
import java.io.Serializable
import java.time.ZonedDateTime

@Entity(name = "TRANSACTIONS")
@Entity(name = "Transactions")
data class TransactionDAO(
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "transaction_id_generator")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import dev.stonegarden.deltahouse.user.UserDAO
import jakarta.persistence.*
import java.io.Serializable

@Entity(name = "WALLETS")
@Entity(name = "Wallets")
data class WalletDAO(
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "wallet_id_generator")
val id: Long = -1,
@OneToOne
val user: UserDAO,
// If this were for real money we should BigDecimal instead of Int
// If this were for real money we should use BigDecimal instead of Int
val cashBalance: Int,
val totalSpent: Int,
@OneToOne(cascade = [CascadeType.ALL])
Expand Down

0 comments on commit 3c51533

Please sign in to comment.