- Onion Architecture
- Due to the relative simplicity of the features implemented on the project a simple flavor of the Onion Architecture was used.
- Domain
- DDD was not implemented along the Onion Structure and an anemic model was built for this project. To invert this decision all the authorization logic and business rules should be migrated from the Application and Service layer to the domain, along with other adjusts to comply with DDD best-pratices.
- All entities that are persisted on the database are implementing simple in-table audit fields.
- Validation logic
- Input validation was implemented using data annotations on the request Dtos.
- Input lenght and other simple validations were considered input validation and not a business logic for this project.
- Business logic validations were implemented on the service layer.
- Authorization logic was implemented on the controller layer.
- Input validation was implemented using data annotations on the request Dtos.
- Controllers
- Exceptions propagated to the controller layer are handled by the exception handler returning a slighly enhanced problem details object.
- Services
- Single database operations using the repository layer are not using the transaction block, or unit of work pattern since PostgreSQL MVCC actually handle those statements into a implicit transaction.
- Repositories / Database
- Database unique constraints are used to mantain integrity of the entities.
- Unique indexes were not created to avoid index duplication. Link
- C# string -> PostgreSQL text data type
- This choice of database collumn type was made since restricting the size of the collumns on the database is a little bit less performatic. Link
- Decided to use BCL Date types, despite NpgSQL recomending the utilization of NodaTime. Link
- Not using ON CONFLICT to describe behaviors different than throwing exceptions on INSERT/UPDATE conflicts.
- In case of concurrent operations violating unique database constraints, an 500 status code might be returned to the client due to the exception propagation. Those scenarios were not handled since they can be considered rare scenarios on this API.
- Example: Two users attempting to be registered with the same username on the same instant.
- In case of concurrent operations violating unique database constraints, an 500 status code might be returned to the client due to the exception propagation. Those scenarios were not handled since they can be considered rare scenarios on this API.
- Requirements
- docker-compose
- Instructions
- Open the project folder using your favorite terminal.
- Execute docker-compose (docker-compose up) to create a new container with the PostgreSQL database
- Wait for the compose to finish and startup the PostgreSQL database.
- The seed data will include an Admin user with simple credentials (Username = adminuser / Password = Adminpassword)
- Wait for the compose to finish and startup the PostgreSQL database.
- Configure project secrets using CLI or using your favorite IDE
{
"Jwt": {
"Key": "{secrets.json}",
"Issuer": "{secrets.json}",
"Audience": "{secrets.json}"
},
"AWS": {
"S3": {
"Region": "{secrets.json}",
"BucketName": "{secrets.json}",
"AccessKeyId": "{secrets.json}",
"AccessKeySecret": "{secrets.json}"
}
}
}
- Execute the project using dotnet run OR start the project using your favorite IDE.
- Logs
- Implement log scopes to enrich the logged information.
- API Design
- Return list of entities using pagination.
- Revoke document permissions.
- Security
- Rate limit on login requests based on origin.
- Implement refresh token.
- Enfoce HTTPS traffic.
- File Upload Security
- Improve file extension validation by checking file signature. link
- Hosting
- Implement health check
- Database
- Create stored procedures to implement some functionalities.
- Unit test
- Cover project with unit tests
- End to end tests
- Create end to end test scenario