feat: enhance filament management and UI improvements

- Update SpoolPresetRepository to include user_id in the update query.
- Expand .gitignore to include various environment and temporary files.
- Revise agent documentation for better clarity and formatting.
- Implement pull-to-refresh functionality in the inventory list.
- Integrate API calls for deleting and updating filaments, ensuring state synchronization.
- Add custom color picker for filament color selection with hex validation.
- Update AndroidManifest and Gradle files for improved configuration and permissions.
- Refactor MainActivity and MainApplication for better splash screen handling.
- Update styles and colors for a cohesive UI experience.
- Replace splash screen logos and icons with new assets.
This commit is contained in:
2026-03-14 14:14:06 -03:00
parent 416e13893c
commit 9c0b3d584c
33 changed files with 519 additions and 164 deletions
+81 -45
View File
@@ -8,22 +8,22 @@ Backend da aplicação MeowSpool escrito em **Rust**, utilizando **Axum** como f
## Stack
| Componente | Biblioteca | Versão mínima |
|-------------------|-----------------------------------------------|---------------|
| HTTP Framework | `axum` | 0.7 |
| Async Runtime | `tokio` (full) | 1.x |
| ORM / Query | `sqlx` (postgres, uuid, time, macros) | 0.8 |
| Autenticação JWT | `jsonwebtoken` | 9.x |
| Hash de senha | `argon2` | 0.5 |
| OAuth Google | `oauth2` | 4.x |
| UUID | `uuid` (v4, serde) | 1.x |
| Serialização | `serde`, `serde_json` | 1.x |
| Erros | `thiserror` | 1.x |
| Env vars | `dotenvy` | 0.15 |
| Logging | `tracing`, `tracing-subscriber` | 0.1 |
| Validação | `validator` | 0.18 |
| HTTP Client | `reqwest` (json, rustls-tls) | 0.12 |
| Geração QR Code | `qrcode` | 0.14 |
| Componente | Biblioteca | Versão mínima |
| ---------------- | ------------------------------------- | ------------- |
| HTTP Framework | `axum` | 0.7 |
| Async Runtime | `tokio` (full) | 1.x |
| ORM / Query | `sqlx` (postgres, uuid, time, macros) | 0.8 |
| Autenticação JWT | `jsonwebtoken` | 9.x |
| Hash de senha | `argon2` | 0.5 |
| OAuth Google | `oauth2` | 4.x |
| UUID | `uuid` (v4, serde) | 1.x |
| Serialização | `serde`, `serde_json` | 1.x |
| Erros | `thiserror` | 1.x |
| Env vars | `dotenvy` | 0.15 |
| Logging | `tracing`, `tracing-subscriber` | 0.1 |
| Validação | `validator` | 0.18 |
| HTTP Client | `reqwest` (json, rustls-tls) | 0.12 |
| Geração QR Code | `qrcode` | 0.14 |
---
@@ -109,37 +109,38 @@ Todas as rotas são prefixadas com `/api/v1`.
### Auth — `/api/v1/auth`
| Método | Rota | Handler | Acesso |
|--------|-----------------------|---------------------------|--------------------------------|
| POST | `/register` | `register_handler` | Público |
| POST | `/login` | `login_handler` | Público |
| POST | `/oauth/google` | `google_oauth_handler` | Público |
| POST | `/refresh` | `refresh_token_handler` | Público (requer refresh token) |
| POST | `/logout` | `logout_handler` | Autenticado |
| POST | `/forgot-password` | `forgot_password_handler` | Público |
| POST | `/verify-email` | `verify_email_handler` | Público |
| POST | `/reset-password` | `reset_password_handler` | Público (requer token de reset)|
| Método | Rota | Handler | Acesso |
| ------ | ------------------ | ------------------------- | ------------------------------- |
| POST | `/register` | `register_handler` | Público |
| POST | `/login` | `login_handler` | Público |
| POST | `/oauth/google` | `google_oauth_handler` | Público |
| POST | `/refresh` | `refresh_token_handler` | Público (requer refresh token) |
| POST | `/logout` | `logout_handler` | Autenticado |
| POST | `/forgot-password` | `forgot_password_handler` | Público |
| POST | `/verify-email` | `verify_email_handler` | Público |
| POST | `/reset-password` | `reset_password_handler` | Público (requer token de reset) |
### Users — `/api/v1/users`
| Método | Rota | Handler | Acesso |
|--------|-------|---------------------|-------------|
| ------ | ----- | ------------------- | ----------- |
| GET | `/me` | `get_me_handler` | Autenticado |
| PUT | `/me` | `update_me_handler` | Autenticado |
### Filaments — `/api/v1/filaments`
| Método | Rota | Handler | Acesso |
|--------|-------------------|----------------------------|-------------|
| GET | `/` | `list_filaments_handler` | Autenticado |
| POST | `/` | `create_filament_handler` | Autenticado |
| GET | `/:id` | `get_filament_handler` | Autenticado |
| PUT | `/:id` | `update_filament_handler` | Autenticado |
| DELETE | `/:id` | `delete_filament_handler` | Autenticado |
| GET | `/:id/qrcode` | `get_qrcode_handler` | Autenticado |
| GET | `/:id/label.svg` | `export_label_handler` | Autenticado |
| Método | Rota | Handler | Acesso |
| ------ | ---------------- | ------------------------- | ----------- |
| GET | `/` | `list_filaments_handler` | Autenticado |
| POST | `/` | `create_filament_handler` | Autenticado |
| GET | `/:id` | `get_filament_handler` | Autenticado |
| PUT | `/:id` | `update_filament_handler` | Autenticado |
| DELETE | `/:id` | `delete_filament_handler` | Autenticado |
| GET | `/:id/qrcode` | `get_qrcode_handler` | Autenticado |
| GET | `/:id/label.svg` | `export_label_handler` | Autenticado |
**Query params de listagem (`GET /filaments`):**
- `material` — filtra por tipo (PLA, ABS, PETG, TPU, ASA, PA, PC...)
- `brand` — filtra por marca
- `search` — busca em marca, modelo e notas
@@ -149,20 +150,21 @@ Todas as rotas são prefixadas com `/api/v1`.
### Spool Presets — `/api/v1/spool-presets`
| Método | Rota | Handler | Acesso |
|--------|----------|--------------------------|-------------------------------------|
| GET | `/` | `list_presets_handler` | Autenticado |
| POST | `/` | `create_preset_handler` | Autenticado |
| PUT | `/:id` | `update_preset_handler` | Autenticado (apenas presets do user)|
| DELETE | `/:id` | `delete_preset_handler` | Autenticado (apenas presets do user)|
| Método | Rota | Handler | Acesso |
| ------ | ------ | ----------------------- | ------------------------------------ |
| GET | `/` | `list_presets_handler` | Autenticado |
| POST | `/` | `create_preset_handler` | Autenticado |
| PUT | `/:id` | `update_preset_handler` | Autenticado (apenas presets do user) |
| DELETE | `/:id` | `delete_preset_handler` | Autenticado (apenas presets do user) |
### Dashboard — `/api/v1/dashboard`
| Método | Rota | Handler | Acesso |
|--------|------|----------------------|-------------|
| GET | `/` | `dashboard_handler` | Autenticado |
| Método | Rota | Handler | Acesso |
| ------ | ---- | ------------------- | ----------- |
| GET | `/` | `dashboard_handler` | Autenticado |
**Resposta do dashboard:**
```json
{
"total_stock_kg": 14.2,
@@ -361,11 +363,13 @@ O backend implementa **last-write-wins com timestamp**:
## Geração de QR Code e Etiqueta SVG
### QR Code (`GET /filaments/:id/qrcode`)
- Gera QR Code com deep link: `meowspool://filament/:id` (singular)
- Retorna PNG (`image/png`) por padrão, ou SVG com `?format=svg`
- Biblioteca: crate `qrcode`
### Etiqueta SVG (`GET /filaments/:id/label.svg`)
- Query params: `width_mm` (padrão: 50), `height_mm` (padrão: 30)
- Retorna SVG com: cor visual, modelo, material, marca, peso líquido e QR Code embutido
- `Content-Type: image/svg+xml`
@@ -381,3 +385,35 @@ O backend implementa **last-write-wins com timestamp**:
- Queries usam **bind parameters** do SQLx — nunca interpolação de string em SQL.
- `user_id` é sempre extraído do token JWT, nunca aceito como parâmetro de URL ou body.
- Presets do sistema (`is_system = true`) são protegidos no nível de serviço: edição ou deleção retorna `403 Forbidden`.
---
## Mudanças Recentes (14/03/2026)
### ✅ Correção: PUT Spool Preset retornava FORBIDDEN
**Local:** `src/adapters/outbound/postgres_spool_preset_repo.rs` — método `update()`
**Problema:**
O SQL UPDATE não validava o `user_id` na cláusula WHERE. Qualquer usuário poderia tentar editar presets de outros usuários ou presets do sistema.
```rust
// ❌ ANTES (inseguro)
UPDATE spool_presets
SET name = $2, spool_weight_g = $3
WHERE id = $1 AND is_system = false
RETURNING ...
```
**Solução:**
Adicionado `AND user_id = $4` para validar propriedade antes de atualizar:
```rust
// ✅ DEPOIS (seguro)
UPDATE spool_presets
SET name = $2, spool_weight_g = $3
WHERE id = $1 AND is_system = false AND user_id = $4
RETURNING ...
```
Agora o repositório valida que o preset pertence ao usuário autenticado (extraído do JWT). Tentativas de editar presets de outro usuário ou do sistema recebem `404 Not Found` (sem vazar que o preset existe).