Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
08a2049
chore: gitignore development
inacio88 Nov 26, 2025
5af5533
feat: projetos base e solucao development
inacio88 Nov 26, 2025
e848720
feat: libs identity development
inacio88 Nov 27, 2025
afe15a3
feat: adicao do ApplicationDbContext development
inacio88 Nov 27, 2025
fe36003
feat: configuracoes basica da api e identity development
inacio88 Nov 27, 2025
21b354a
feat: secrets da conexao e migracoes development
inacio88 Nov 27, 2025
f3128b2
feat: instrucoes setup banco development
inacio88 Nov 27, 2025
27a8ea5
feat: mapeamento agrupado do identity development
inacio88 Nov 28, 2025
197465a
feat: entidade principal e mapeamento development
inacio88 Nov 28, 2025
743b420
feat: controller de teste development
inacio88 Nov 28, 2025
67354f2
feat: migracoes da entidade development
inacio88 Nov 28, 2025
1cd3573
feat: irepo investment development
inacio88 Nov 28, 2025
eec8f26
feat: controller investment development
inacio88 Nov 28, 2025
deb352e
feat: projeto infra development
inacio88 Nov 28, 2025
1d74bb3
feat: passando dbcontext para infra development
inacio88 Nov 28, 2025
f979da9
feat: migracoes development
inacio88 Nov 28, 2025
7ad4962
feat: projeto application com servico investimento development
inacio88 Nov 29, 2025
a9e213a
feat: separacao de logica com outras classes do core development
inacio88 Nov 29, 2025
111a25d
feat: registrando servicos development
inacio88 Nov 29, 2025
97ef329
feat: count async development
inacio88 Nov 29, 2025
0dd93c5
feat: dtos development
inacio88 Nov 29, 2025
31e238d
feat: utilizando novas dtos development
inacio88 Nov 29, 2025
c8a7e7c
feat: utilizando ClaimTypes development
inacio88 Nov 29, 2025
d80fbf9
feat: extensoes datetime development
inacio88 Nov 29, 2025
bb8b75f
feat: lista e contagem simultaneas development
inacio88 Nov 29, 2025
918c31b
feat: extension claims development
inacio88 Nov 29, 2025
fceade0
feat: filtro development
inacio88 Nov 29, 2025
e92852f
feat: usando o filtro development
inacio88 Nov 29, 2025
d7df772
feat: logout development
inacio88 Nov 29, 2025
0e79adf
feat: tags no identity e atualizacao swagger development
inacio88 Nov 30, 2025
1557a10
feat: configuracao e exemplo docs development
inacio88 Nov 30, 2025
36942d8
feat: documentacao dos endpoints development
inacio88 Nov 30, 2025
4a5a746
chore: removendo codigo sem uso development
inacio88 Nov 30, 2025
82ebcab
feat: cricao projeto de teste development
inacio88 Nov 30, 2025
f8bf7ef
feat: testando o gaincalculateservice development
inacio88 Nov 30, 2025
9517946
feat: teste do TaxCalculationService development
inacio88 Nov 30, 2025
d636a87
feat: testes do TestInvestmentService development
inacio88 Nov 30, 2025
92e01a7
feat: aplicando migracoes no statup development
inacio88 Dec 1, 2025
47f9cef
feat: readme development
inacio88 Dec 1, 2025
b3ef396
chore: remocao codigo sem uso development
inacio88 Dec 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
484 changes: 484 additions & 0 deletions .gitignore

Large diffs are not rendered by default.

100 changes: 18 additions & 82 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,88 +1,24 @@
# Back End Test Project <img src="https://raw.githubusercontent.com/Coderockr/backend-test/refs/heads/main/coderockr.banner.svg" align="right" height="50px" />
# Setup

You should see this challenge as an opportunity to create an application following modern development best practices (given the stack of your choice), but also feel free to use your own architecture preferences (coding standards, code organization, third-party libraries, etc). It’s perfectly fine to use vanilla code or any framework or libraries.
- Necesário: .net 8
- Necessário: docker ou postgres, coloquei aqui numa porta diferente o mapeamento caso já tenha outro rodando na padrão

## Scope
Banco:
docker run --name api-investments-postgres -e POSTGRES_PASSWORD=1q2w3e4r@@@ -d -p 5436:5432 postgres

In this challenge you should build an **API** for an application that stores and manages investments, it should have the following features:

1. __Creation__ of an investment with an owner, a creation date and an amount.
1. The creation date of an investment can be today or a date in the past.
2. An investment should not be or become negative.
2. __View__ of an investment with its initial amount and expected balance.
1. Expected balance should be the sum of the invested amount and the [gains][].
2. If an investment was already withdrawn then the balance must reflect the gains of that investment
3. __Withdrawal__ of a investment.
1. The withdraw will always be the sum of the initial amount and its gains,
partial withdrawn is not supported.
2. The withdrawal date must be informmed by the user, and it can be a date in the past or today, but can't happen before the investment creation or the future.
3. [Taxes][taxes] need to be applied to the withdrawals before showing the final value.
4. __List__ of a person's investments
1. This list should have pagination.
- Stringconnection pelo user secrets ( mas também pode ser variável de ambiente normal)
dotnet user-secrets set conexao "User ID=postgres;Password=1q2w3e4r@@@;Host=localhost;Port=5436;Database=ClienteDB;Pooling=true;"

__NOTE:__ the implementation of an interface will not be evaluated, and if implemented the endpoints still need to be usable/readable for a machine.
# Libs
- Identity: Para autenticação e autorização, usei pois agiliza bastante a autenticação e autorização
- entityFrameWorkCore.Design: para gerar as migrações, ferramente muito boa de code em code first
- Swashbuckle.AspNetCore.Annotations: para fazer a documentação da api pelo swagger.
- EntityFrameworkCore.PostgreSQL: Oferece orm para lidar com banco postgres, também uma execelente lib com boa performance atualmente. Gostaria de ter inserido também o dapper para operações que exigissem um controle mais perfomátíco, mas pelo escopo acredito que o desempenho do entity é suficiente.
- Moq: Me auxiliou no mock do repositório para testes unitários e focar apenas nos serços e lógicas de negócio.

# Run
- Todos os projetos estão .net8, então basta ter .net 8 sdk instalado e rodar "dotnet run" ele vai restaurar pacotes, compilar e rodar.

### Gain Calculation

The investment will pay 0.52% every month in the same day of the investment creation.

Given that the gain is paid every month, it should be treated as [compound gain][], which means that every new period (month) the amount gained will become part of the investment balance for the next payment.

### Taxation

When money is withdrawn, tax is triggered. Taxes apply only to the gain portion of the money withdrawn. For example, if the initial investment was 1000.00, the current balance is 1200.00, then the taxes will be applied to the 200.00.

The tax percentage changes according to the age of the investment:
* If it is less than one year old, the percentage will be 22.5% (tax = 45.00).
* If it is between one and two years old, the percentage will be 18.5% (tax = 37.00).
* If older than two years, the percentage will be 15% (tax = 30.00).

## Requirements
1. Create project using any technology of your preference. It’s perfectly OK to use vanilla code or any framework or libraries;
2. Although you can use as many dependencies as you want, you should manage them wisely;
3. It is not necessary to send the notification emails, however, the code required for that would be welcome;
4. The API must be documented in some way.

## Deliverables
The project source code and dependencies should be made available in GitHub. Here are the steps you should follow:
1. Fork this repository to your GitHub account (create an account if you don't have one, you will need it working with us).
2. Create a "development" branch and commit the code to it. Do not push the code to the main branch.
3. Include a README file that describes:
- Special build instructions, if any
- List of third-party libraries used and short description of why/how they were used
- A link to the API documentation.
4. Once the work is complete, create a pull request from "development" into "main" and send us the link.
5. Avoid using huge commits hiding your progress. Feel free to work on a branch and use `git rebase` to adjust your commits before submitting the final version.

## Coding Standards
When working on the project be as clean and consistent as possible.

## Project Deadline
Ideally you'd finish the test project in 5 days. It shouldn't take you longer than a entire week.

## Quality Assurance
Use the following checklist to ensure high quality of the project.

### General
- First of all, the application should run without errors.
- Are all requirements set above met?
- Is coding style consistent?
- The API is well documented?
- The API has unit tests?

## Submission
1. A link to the Github repository.
2. Briefly describe how you decided on the tools that you used.

## Have Fun Coding 🤘
- This challenge description is intentionally vague in some aspects, but if you need assistance feel free to ask for help.
- If any of the seems out of your current level, you may skip it, but remember to tell us about it in the pull request.

## Credits

This coding challenge was inspired on [kinvoapp/kinvo-back-end-test](https://github.com/kinvoapp/kinvo-back-end-test/blob/2f17d713de739e309d17a1a74a82c3fd0e66d128/README.md)

[gains]: #gain-calculation
[taxes]: #taxation
[interest]: #interest-calculation
[compound gain]: https://www.investopedia.com/terms/g/gain.asp
# Obs
- Deixei as migrações sendo aplicadas no startup da aplicação, mas apenas facilitar o trabalho do avaliador; geralmente coloco isso no pipeline de publicação de uma realease e fica separado num passo de ci/cd.
84 changes: 84 additions & 0 deletions api/Common/Api/BuilderExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System.Reflection;
using application.Services;
using core.Repositories;
using core.Services;
using infra.Data;
using infra.Repositories;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi.Models;

namespace api.Common.Api
{
public static class BuilderExtension
{
public static void AddConfiguration(this WebApplicationBuilder builder)
{
Configuration.ConnectionString = builder.Configuration.GetValue<string>("conexao") ?? string.Empty;

}

public static void AddDocumentation(this WebApplicationBuilder builder)
{

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
options.EnableAnnotations();
options.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "Investment API",
Description = "Web API for investments",
TermsOfService = new Uri("https://example.com/terms"),
Contact = new OpenApiContact
{
Name = "Investment API Contact",
Url = new Uri("https://example.com/contact")
},
License = new OpenApiLicense
{
Name = "Investment API License",
Url = new Uri("https://example.com/license")
}
});
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
});


}

public static void AddSecurity(this WebApplicationBuilder builder)
{
builder.Services.AddIdentityApiEndpoints<IdentityUser>();


builder.Services.AddAuthorization();
}

public static void AddDataContexts(this WebApplicationBuilder builder)
{

builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseNpgsql(Configuration.ConnectionString);
});

builder.Services.AddIdentityCore<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddApiEndpoints()
;
}


public static void AddServices(this WebApplicationBuilder builder)
{
builder.Services.AddScoped<IInvestmentRepository, InvestmentRepository>();

builder.Services.AddScoped<IInvestmentService, InvestmentService>();
builder.Services.AddScoped<IGainCalculationService, GainCalculationService>();
builder.Services.AddScoped<ITaxCalculationService, TaxCalculationService>();
}
}
}
8 changes: 8 additions & 0 deletions api/Common/Api/Configuration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace api.Common.Api
{
public static class Configuration
{
public static string ConnectionString { get; set; } = string.Empty;

}
}
26 changes: 26 additions & 0 deletions api/Controllers/IdentityController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;

namespace api.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class IdentityController : ControllerBase
{
private readonly SignInManager<IdentityUser> _signInManager;

public IdentityController(SignInManager<IdentityUser> signInManager)
{
_signInManager = signInManager;
}

[Authorize]
[HttpPost("logout")]
public async Task<IActionResult> Logout()
{
await _signInManager.SignOutAsync();
return Ok();
}
}
}
Loading