# SwisssignChallenge ## Requirements - [GraalVM 23](https://www.graalvm.org/) - PostgreSQL 17, but a Docker Compose file is available for your convenience. If you decide to run it locally, **please check application.yml for default values**. ## Generate sources To generate code from the API contract, run `./mvnw generate-sources` ## Build native executable 1. Make sure your `JAVA_HOME` or `GRAALVM_HOME` environment variable is correctly pointing to your JDK. 1. Run `./mvnw -Pnative native:compile`. Note that you don't need to build a native executable to run a development environment. ## Retrieving PDFs You must have 2 PDF files with the names `cv-actual.pdf` and `cv-stackoverflow.pdf` as this is what is referenced by the rows in the database. By default, they must be placed in `/srv/pdfs/` but feel free to modify the constant before running the code. For your convenience, those files are placed at the root of the project. ## Choices ### GraalVM It's my first time using GraalVM, but I took the opportunity of using it in this project because of its small scale. Its goals are to improve the performance of JVM-based applications to match native languages. Startup times are also greatly improved; less than 0.5 seconds. The drawback is that the build times are greatly lengthened; around 1 minute for an empty project. ### PostgreSQL I don't think I have to explain much about PostgreSQL, but it's well-suited for both small and large-scale projects. Also, support with Spring Boot is, in my experience, flawless. ### Flyway I'm experienced with Liquibase, but after quickly reading about errors related to GraalVM, I understood it was unsupported. Flyway is another popular migration tool, so I gave it a go. I have nothing to say for or against it. ### JWT I knew the basics but never implemented the authentication layer myself. JWT is a standard, but in an enterprise environment there would probably be an OIDC-compliant service to be plugged into. After initializing the correct beans, it worked really well. As I don't specify the JWT secret, all issued tokens are not recognized after a restart and must be regenerated (i.e. all users are logged out). LLMs were a great help here too, along with good ol' Baeldung. ### Files At first, I wanted to store the files as a BYTEA in the database. I thought this would be much simpler and minimalistic, but I was wrong on the first point. I gave up after I couldn't find the root of the error "cannot convert to long", despite not having a single long in my source code. Anyway, files are stored on the filesystem and are retrieved by the `PdfServiceImpl`. This service makes sure that the file name doesn't contain `".."` in the file name in order to prevent [directory traversal attacks](https://en.wikipedia.org/wiki/Directory_traversal_attack). Files are not uploaded by the user so there is virtually 0 chance of it containing malicious characters, but I thought it was important to safeguard against this. ### UUID As there is insanely little chance of collision, UUID are most useful in distributed systems where we could give the responsibility of generating the UUID to the clients. For a system like this, I doubt that the max value of 64-bit integers would be reached, but the maintainability cost isn't much higher than using integers. If anything, it at least prevents the user from using the ID in the wrong place (i.e. `DELETE /person/1` instead of `DELETE /city/1`) as no entity shares the same ID. ### json-patch I used [json-patch](https://github.com/java-json-tools/json-patch) to confirm the status of documents. Instead of sending the whole representation, only the operation (`op`), the path (`path`) to apply it to and the new value (`value`) have to be supplied. ## Potential improvements A lot more tests. Integration tests, fuzz tests and benchmarks are those that come to mind. ~~I would also spend a lot more time understanding cyclic dependencies when (de)serializing JSON. For now there's a manual workaround in `SigningRequestDocumentServiceImpl.java`~~.