chore: initial project setup
- Cargo init with dependencies (ratatui, crossterm, tokio, reqwest, rusqlite, serde, chrono, dirs) - Module structure: domain/, ui/, infrastructure/ - Domain models (TaskList, Task, TaskStatus, SyncAction, SyncQueueItem) - .gitignore for target/ and *.db - Rustls-based TLS (no OpenSSL dependency)
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
target/
|
||||||
|
*.db
|
||||||
Generated
+1958
File diff suppressed because it is too large
Load Diff
+16
@@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "task_app"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ratatui = "0.28"
|
||||||
|
crossterm = "0.28"
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
|
||||||
|
rusqlite = { version = "0.32", features = ["bundled"] }
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
serde_json = "1"
|
||||||
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
dirs = "6"
|
||||||
|
url = "2"
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# Contexto do Projeto
|
||||||
|
Atua como um programador Rust sénior e especialista em interfaces de terminal (TUI). O teu objetivo é implementar uma aplicação de gestão de tarefas de linha de comandos (CLI/TUI) que se integra com o Google Tasks.
|
||||||
|
|
||||||
|
A aplicação deve adotar a filosofia "Offline-First", guardando as tarefas localmente e sincronizando com a cloud em pano de fundo quando houver ligação à internet.
|
||||||
|
|
||||||
|
# Stack Tecnológica
|
||||||
|
* **Linguagem:** Rust
|
||||||
|
* **UI:** `ratatui` + `crossterm`
|
||||||
|
* **Assincronismo:** `tokio`
|
||||||
|
* **HTTP:** `reqwest`
|
||||||
|
* **Autenticação:** `yup-oauth2` (usando o Device Authorization Flow)
|
||||||
|
* **Base de Dados Local:** `rusqlite` (SQLite local para guardar tarefas e fila de sincronização)
|
||||||
|
* **Serialização:** `serde` + `serde_json`
|
||||||
|
|
||||||
|
# Arquitetura de Ficheiros (Clean Architecture + MVU)
|
||||||
|
Organiza o código estritamente com a seguinte estrutura:
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/
|
||||||
|
├── main.rs # Ponto de entrada, inicialização do terminal e DB
|
||||||
|
├── app.rs # Estado da aplicação (App struct) e processamento de eventos
|
||||||
|
├── domain/ # Lógica pura e modelos de dados
|
||||||
|
│ ├── mod.rs
|
||||||
|
│ └── models.rs # Structs de Tarefa, Lista e Eventos de Sincronização
|
||||||
|
├── ui/ # Renderização Ratatui
|
||||||
|
│ ├── mod.rs # Layout principal
|
||||||
|
│ └── components.rs # Widgets (Tabs, Listas, Pop-ups)
|
||||||
|
└── infrastructure/ # Efeitos colaterais e I/O
|
||||||
|
├── mod.rs
|
||||||
|
├── db.rs # Inicialização do SQLite, queries CRUD e fila offline
|
||||||
|
└── api.rs # Integração com Google Tasks API e OAuth2
|
||||||
|
```
|
||||||
|
|
||||||
|
# Requisitos Principais
|
||||||
|
|
||||||
|
## 1. Interface de Utilizador (UI) e Layout
|
||||||
|
* O ecrã deve estar dividido numa grelha rigorosa:
|
||||||
|
* **Topo (Tabs):** Uma linha horizontal a representar as **Listas de Tarefas**. Deve ser possível navegar entre elas e adicionar novas listas.
|
||||||
|
* **Corpo Principal (Split View):** Abaixo das listas, o ecrã divide-se em dois painéis verticais:
|
||||||
|
* **Painel da Esquerda (Lista de Tasks):** Apresenta as tarefas da lista atualmente selecionada. A data e hora dos lembretes (`due dates`) devem ser visíveis diretamente nesta lista, ao lado ou por baixo do título da tarefa.
|
||||||
|
* **Painel da Direita (Detalhes):** Mostra as notas, descrição longa e/ou sub-tarefas da tarefa atualmente selecionada no painel esquerdo.
|
||||||
|
|
||||||
|
## 2. Interação e Atalhos (UX)
|
||||||
|
* **Navegação de Painéis:** A mudança de foco entre os três grandes blocos (Tabs no Topo, Painel Esquerdo e Painel Direito) deve ser feita usando a combinação de teclas `Tab + Setas`.
|
||||||
|
* **Navegação Interna:** Uma vez dentro de um painel, a navegação entre os itens faz-se apenas com as setas do teclado (não usar atalhos tipo Vim com `j/k`).
|
||||||
|
* **Reordenação Persistente:** O utilizador deve conseguir organizar as tarefas na lista usando o atalho `Alt + Setas` (Cima/Baixo). Esta ordenação customizada tem de ficar gravada na base de dados para se manter exatamente igual entre sessões.
|
||||||
|
* **Operações CRUD:** Deve ser possível Adicionar, Editar e Apagar qualquer Lista ou Tarefa.
|
||||||
|
* **Edição de Datas (Pop-up):** Quando o utilizador for editar a data/hora de uma tarefa, a aplicação deve abrir um modal/Pop-up interativo sobreposto ao centro do ecrã para facilitar a introdução desses dados.
|
||||||
|
* O estado da rede ("Online" / "Offline" / "A Sincronizar...") deve ser apresentado num rodapé discreto.
|
||||||
|
|
||||||
|
## 3. Base de Dados Local (Offline-First)
|
||||||
|
* Usa o SQLite para criar um ficheiro local (ex: `tasks.db`).
|
||||||
|
* **Tabela `tasks`:** Deve espelhar a estrutura de uma Google Task (ID, Title, Notes, Status, Due, Position/Order). A coluna de posição é crítica para garantir que a ordenação do utilizador não se perde ao reiniciar a aplicação.
|
||||||
|
* **Tabela `sync_queue`:** Fundamental para o funcionamento offline. Deve registar a ação pendente (CREATE, UPDATE, DELETE, REORDER), o ID local/remoto e o payload em JSON.
|
||||||
|
* A interface (`app.rs` e `ui/`) lê **exclusivamente** do SQLite, garantindo que o carregamento da interface é imediato e não bloqueia à espera de respostas de rede.
|
||||||
|
|
||||||
|
## 4. Motor de Sincronização (Sync Engine)
|
||||||
|
* Quando o utilizador cria, edita, apaga ou reordena uma tarefa, a ação e a nova ordem (position) são registadas no SQLite.
|
||||||
|
* Uma *task* assíncrona do Tokio processa a fila de sincronização em pano de fundo quando deteta ligação à internet, chamando a API oficial do Google Tasks via `reqwest`. A reordenação deve refletir-se também na cloud.
|
||||||
|
* Se não houver token de acesso guardado, a TUI deve apresentar um Pop-up a pedir para o utilizador visitar o URL de autorização e introduzir o código gerado pelo `yup-oauth2`.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pub mod models;
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
use chrono::NaiveDateTime;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct TaskList {
|
||||||
|
pub id: String,
|
||||||
|
pub title: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Task {
|
||||||
|
pub id: String,
|
||||||
|
pub list_id: String,
|
||||||
|
pub title: String,
|
||||||
|
pub notes: Option<String>,
|
||||||
|
pub status: TaskStatus,
|
||||||
|
pub due: Option<NaiveDateTime>,
|
||||||
|
pub position: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum TaskStatus {
|
||||||
|
NeedsAction,
|
||||||
|
Completed,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum SyncAction {
|
||||||
|
Create,
|
||||||
|
Update,
|
||||||
|
Delete,
|
||||||
|
Reorder,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct SyncQueueItem {
|
||||||
|
pub id: i64,
|
||||||
|
pub action: SyncAction,
|
||||||
|
pub task_id: String,
|
||||||
|
pub list_id: String,
|
||||||
|
pub payload: String,
|
||||||
|
pub created_at: String,
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
// TODO: Fase 5 - Google Tasks API integration
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
// TODO: Fase 2 - SQLite storage implementation
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod db;
|
||||||
|
pub mod api;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
mod domain;
|
||||||
|
mod ui;
|
||||||
|
mod infrastructure;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Task App - Google Tasks TUI");
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
// TODO: Fase 3 - Ratatui widgets
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pub mod components;
|
||||||
Reference in New Issue
Block a user