From 3e7f6fea8e5a470be04c53aad01408a983db57fc Mon Sep 17 00:00:00 2001
From: continuist <continuist02@gmail.com>
Date: Sun, 22 Jun 2025 16:19:38 -0400
Subject: [PATCH] Add unit tests for domain and application layers, and update
 licenses to correct license

---
 LICENSE_NOTICE.md                             |  91 ++++
 PROJECT_INDEX.md                              | 415 ++++++++++++++++++
 README.md                                     |   4 +-
 backend/Cargo.toml                            |   2 +-
 backend/crates/api/src/lib.rs                 |  11 +
 backend/crates/application/Cargo.toml         |   4 +
 backend/crates/application/src/lib.rs         | 369 ++++++++++++++++
 backend/crates/cli/src/lib.rs                 |  11 +
 backend/crates/domain/Cargo.toml              |   3 +
 backend/crates/domain/src/lib.rs              | 243 +++++++++-
 backend/crates/memory/src/lib.rs              |  26 +-
 ...c057cc55999d2115521419d00ca57843af046.json |  48 ++
 ...1942a86d7b2edfeea1cfb432758acbfbe6da6.json |  44 ++
 ...b1f9127a3a6b95046bb91bea60a2d6ee6dfc2.json |  46 ++
 ...1277e3b3638412204a2aa5fad7a51c3ce855d.json |  44 ++
 ...ce74e0de9dc8e24ae1d9fa945b9924498a652.json |  14 +
 ...c4be0d99874bee7ffed9d948fc57759f03d61.json |  47 ++
 ...528466926789ff31e9ed2591bb175527ec169.json |  14 +
 ...a7db21d5503ccfb9f9ad788f3897fb8216eee.json |  48 ++
 ...6cf91516f91388d484e398273be3532d8e027.json |  46 ++
 ...9d720cadc68f2d12bed4f46aeb87401ce2de9.json |  47 ++
 backend/crates/postgres/src/lib.rs            |  11 +
 backend/crates/tui/src/lib.rs                 |  11 +
 frontend/package.json                         |   1 +
 frontend/src/app/layout.tsx                   |  11 +
 frontend/src/app/page.tsx                     |  11 +
 frontend/src/app/products/page.tsx            |  13 +-
 frontend/src/app/users/page.tsx               |  11 +
 frontend/src/lib/api.ts                       |  11 +
 29 files changed, 1631 insertions(+), 26 deletions(-)
 create mode 100644 LICENSE_NOTICE.md
 create mode 100644 PROJECT_INDEX.md
 create mode 100644 backend/crates/postgres/.sqlx/query-508d8e56fc561537060a4bf378dc057cc55999d2115521419d00ca57843af046.json
 create mode 100644 backend/crates/postgres/.sqlx/query-54394890f1b4efd6487c5147e9a1942a86d7b2edfeea1cfb432758acbfbe6da6.json
 create mode 100644 backend/crates/postgres/.sqlx/query-5bb95e6a9bea1ac6d4aab08eb63b1f9127a3a6b95046bb91bea60a2d6ee6dfc2.json
 create mode 100644 backend/crates/postgres/.sqlx/query-62874c01dcd85e441608d6d92661277e3b3638412204a2aa5fad7a51c3ce855d.json
 create mode 100644 backend/crates/postgres/.sqlx/query-82746e921edfb33ae6c0f434d96ce74e0de9dc8e24ae1d9fa945b9924498a652.json
 create mode 100644 backend/crates/postgres/.sqlx/query-882fbe26ce3c2f8baf74b89805fc4be0d99874bee7ffed9d948fc57759f03d61.json
 create mode 100644 backend/crates/postgres/.sqlx/query-b69a6f42965b3e7103fcbf46e39528466926789ff31e9ed2591bb175527ec169.json
 create mode 100644 backend/crates/postgres/.sqlx/query-c424e1240a945e7dea975c325a1a7db21d5503ccfb9f9ad788f3897fb8216eee.json
 create mode 100644 backend/crates/postgres/.sqlx/query-ed0fa11d45b99c47dcbf75aa0646cf91516f91388d484e398273be3532d8e027.json
 create mode 100644 backend/crates/postgres/.sqlx/query-ffa2228196655e9f2b8152fc4b79d720cadc68f2d12bed4f46aeb87401ce2de9.json

diff --git a/LICENSE_NOTICE.md b/LICENSE_NOTICE.md
new file mode 100644
index 0000000..87480d2
--- /dev/null
+++ b/LICENSE_NOTICE.md
@@ -0,0 +1,91 @@
+# License Notice
+
+## Sharenet License Information
+
+This project, Sharenet, is licensed under the **Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License** (CC-BY-NC-SA-4.0).
+
+## License Details
+
+- **Full License Text**: See [LICENSE.md](LICENSE.md) for the complete license text
+- **License URL**: https://creativecommons.org/licenses/by-nc-sa/4.0/
+- **SPDX Identifier**: CC-BY-NC-SA-4.0
+
+## What This License Means
+
+### You are free to:
+- **Share**: Copy and redistribute the material in any medium or format
+- **Adapt**: Remix, transform, and build upon the material
+- **Attribution**: You must give appropriate credit, provide a link to the license, and indicate if changes were made
+
+### Under the following terms:
+- **NonCommercial**: You may not use the material for commercial purposes
+- **ShareAlike**: If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original
+
+## Copyright Information
+
+- **Copyright Holder**: Continuist <continuist02@gmail.com>
+- **Year**: 2024
+- **Project**: Sharenet
+
+## License Headers
+
+All source files in this project include license headers that reference this license. The headers follow this format:
+
+### For Rust files:
+```rust
+/*
+ * This file is part of Sharenet.
+ * 
+ * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
+ * 
+ * You may obtain a copy of the license at:
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/
+ * 
+ * Copyright (c) 2024 Continuist <continuist02@gmail.com>
+ */
+```
+
+### For TypeScript/JavaScript files:
+```typescript
+/**
+ * This file is part of Sharenet.
+ * 
+ * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
+ * 
+ * You may obtain a copy of the license at:
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/
+ * 
+ * Copyright (c) 2024 Continuist <continuist02@gmail.com>
+ */
+```
+
+## Package Configuration
+
+### Backend (Rust)
+- **Cargo.toml**: `license = "CC-BY-NC-SA-4.0"`
+
+### Frontend (Node.js)
+- **package.json**: `"license": "CC-BY-NC-SA-4.0"`
+
+## Compliance
+
+To comply with this license when using, modifying, or distributing this software:
+
+1. **Attribution**: Always include the copyright notice and license reference
+2. **Non-Commercial Use**: Do not use for commercial purposes without permission
+3. **Share Alike**: If you create derivatives, license them under the same terms
+4. **License Link**: Include a link to the full license text
+
+## Questions
+
+If you have questions about the license or need permission for commercial use, please contact:
+- **Email**: continuist02@gmail.com
+
+## Third-Party Dependencies
+
+This project includes third-party dependencies that are licensed under their own terms. Please refer to the respective license files for each dependency:
+
+- **Backend Dependencies**: See `backend/Cargo.lock` for dependency licenses
+- **Frontend Dependencies**: See `frontend/package-lock.json` for dependency licenses
+
+The CC-BY-NC-SA-4.0 license applies only to the original Sharenet codebase, not to third-party dependencies. 
\ No newline at end of file
diff --git a/PROJECT_INDEX.md b/PROJECT_INDEX.md
new file mode 100644
index 0000000..fb52449
--- /dev/null
+++ b/PROJECT_INDEX.md
@@ -0,0 +1,415 @@
+# Sharenet Project Index
+
+## Project Overview
+
+Sharenet is a full-stack application for managing users and products, built with Rust (backend) and Next.js (frontend). It demonstrates clean architecture principles with multiple interface options and configurable storage backends.
+
+## Architecture
+
+### Backend Architecture (Clean Architecture)
+
+The backend follows clean architecture principles with clear separation of concerns:
+
+```
+┌─────────────────────────────────────────────────────────────┐
+│                    Interface Layer                          │
+│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
+│  │     API     │  │     CLI     │  │     TUI     │        │
+│  │   (Axum)    │  │   (Clap)    │  │  (Ratatui)  │        │
+│  └─────────────┘  └─────────────┘  └─────────────┘        │
+└─────────────────────────────────────────────────────────────┘
+┌─────────────────────────────────────────────────────────────┐
+│                  Application Layer                          │
+│  ┌─────────────────────────────────────────────────────┐   │
+│  │              Service/UseCase Layer                   │   │
+│  │  - UserService                                      │   │
+│  │  - ProductService                                   │   │
+│  └─────────────────────────────────────────────────────┘   │
+└─────────────────────────────────────────────────────────────┘
+┌─────────────────────────────────────────────────────────────┐
+│                    Domain Layer                            │
+│  ┌─────────────────────────────────────────────────────┐   │
+│  │  - User Entity                                      │   │
+│  │  - Product Entity                                   │   │
+│  │  - Repository Traits                                │   │
+│  │  - Domain Errors                                    │   │
+│  └─────────────────────────────────────────────────────┘   │
+└─────────────────────────────────────────────────────────────┘
+┌─────────────────────────────────────────────────────────────┐
+│                 Infrastructure Layer                       │
+│  ┌─────────────┐  ┌─────────────┐                        │
+│  │   Memory    │  │  PostgreSQL │                        │
+│  │ Repository  │  │ Repository  │                        │
+│  └─────────────┘  └─────────────┘                        │
+└─────────────────────────────────────────────────────────────┘
+```
+
+## Project Structure
+
+```
+sharenet/
+├── backend/                          # Rust backend
+│   ├── Cargo.toml                    # Workspace configuration
+│   ├── README.md                     # Backend documentation
+│   ├── crates/                       # Backend modules
+│   │   ├── domain/                   # Domain entities and traits
+│   │   │   ├── Cargo.toml
+│   │   │   └── src/lib.rs            # Core domain logic
+│   │   ├── application/              # Application services
+│   │   │   ├── Cargo.toml
+│   │   │   └── src/lib.rs            # Use case implementations
+│   │   ├── api/                      # HTTP API (Axum)
+│   │   │   ├── Cargo.toml
+│   │   │   └── src/lib.rs            # REST API endpoints
+│   │   ├── cli/                      # CLI interface (Clap)
+│   │   │   ├── Cargo.toml
+│   │   │   └── src/lib.rs            # Command-line interface
+│   │   ├── tui/                      # TUI interface (Ratatui)
+│   │   │   ├── Cargo.toml
+│   │   │   └── src/lib.rs            # Text user interface
+│   │   ├── memory/                   # In-memory storage
+│   │   │   ├── Cargo.toml
+│   │   │   └── src/lib.rs            # Memory repository implementation
+│   │   ├── postgres/                 # PostgreSQL storage
+│   │   │   ├── Cargo.toml
+│   │   │   └── src/lib.rs            # PostgreSQL repository implementation
+│   │   ├── sharenet-api-memory/      # API binary (memory)
+│   │   │   ├── Cargo.toml
+│   │   │   └── src/main.rs           # API entry point
+│   │   ├── sharenet-api-postgres/    # API binary (PostgreSQL)
+│   │   │   ├── Cargo.toml
+│   │   │   └── src/main.rs           # API entry point
+│   │   ├── sharenet-cli-memory/      # CLI binary (memory)
+│   │   │   ├── Cargo.toml
+│   │   │   └── src/main.rs           # CLI entry point
+│   │   ├── sharenet-cli-postgres/    # CLI binary (PostgreSQL)
+│   │   │   ├── Cargo.toml
+│   │   │   └── src/main.rs           # CLI entry point
+│   │   ├── sharenet-tui-memory/      # TUI binary (memory)
+│   │   │   ├── Cargo.toml
+│   │   │   └── src/main.rs           # TUI entry point
+│   │   └── sharenet-tui-postgres/    # TUI binary (PostgreSQL)
+│   │       ├── Cargo.toml
+│   │       └── src/main.rs           # TUI entry point
+│   ├── migrations/                   # Database migrations
+│   │   └── 20240101000000_create_tables.sql
+│   └── config/                       # Configuration files
+│       ├── api-memory.env            # API with memory storage
+│       ├── api-postgres.env          # API with PostgreSQL
+│       ├── cli-memory.env            # CLI with memory storage
+│       ├── cli-postgres.env          # CLI with PostgreSQL
+│       ├── tui-memory.env            # TUI with memory storage
+│       └── tui-postgres.env          # TUI with PostgreSQL
+├── frontend/                         # Next.js frontend
+│   ├── package.json                  # Frontend dependencies
+│   ├── README.md                     # Frontend documentation
+│   ├── src/                          # Source code
+│   │   ├── app/                      # Next.js app directory
+│   │   │   ├── layout.tsx            # Root layout
+│   │   │   ├── page.tsx              # Dashboard page
+│   │   │   ├── users/                # Users pages
+│   │   │   │   └── page.tsx          # Users management
+│   │   │   └── products/             # Products pages
+│   │   │       └── page.tsx          # Products management
+│   │   ├── components/               # React components
+│   │   │   └── ui/                   # shadcn/ui components
+│   │   │       ├── button.tsx        # Button component
+│   │   │       ├── card.tsx          # Card component
+│   │   │       ├── dialog.tsx        # Dialog component
+│   │   │       ├── form.tsx          # Form component
+│   │   │       ├── input.tsx         # Input component
+│   │   │       ├── label.tsx         # Label component
+│   │   │       └── table.tsx         # Table component
+│   │   └── lib/                      # Utility functions
+│   │       ├── api.ts                # API client
+│   │       └── utils.ts              # Utility functions
+│   ├── public/                       # Static assets
+│   │   ├── file.svg                  # File icon
+│   │   ├── globe.svg                 # Globe icon
+│   │   ├── next.svg                  # Next.js logo
+│   │   ├── vercel.svg                # Vercel logo
+│   │   └── window.svg                # Window icon
+│   ├── components.json               # shadcn/ui configuration
+│   ├── next.config.ts                # Next.js configuration
+│   ├── postcss.config.mjs            # PostCSS configuration
+│   ├── tailwind.config.js            # Tailwind CSS configuration
+│   └── tsconfig.json                 # TypeScript configuration
+├── README.md                         # Project documentation
+├── LICENSE.md                        # Project license
+└── .gitignore                        # Git ignore rules
+```
+
+## Key Components
+
+### Domain Layer (`backend/crates/domain/`)
+
+**Core Entities:**
+- `User`: User entity with id, username, email, timestamps
+- `Product`: Product entity with id, name, description, timestamps
+- `CreateUser`/`UpdateUser`: DTOs for user operations
+- `CreateProduct`/`UpdateProduct`: DTOs for product operations
+
+**Traits:**
+- `Entity`: Base trait for domain entities
+- `Repository<T>`: Generic repository trait for CRUD operations
+
+**Error Handling:**
+- `DomainError`: Domain-specific error types (NotFound, InvalidInput, Internal)
+
+### Application Layer (`backend/crates/application/`)
+
+**Services:**
+- `Service<T, R>`: Generic service implementation
+- `UseCase<T>`: Use case trait for business operations
+- `Repository<T>`: Repository trait for data access
+
+**Features:**
+- Generic implementations for easy extension
+- Static dispatch with generic traits
+- Comprehensive test coverage with mock repositories
+
+### Infrastructure Layer
+
+#### Memory Repository (`backend/crates/memory/`)
+- In-memory storage using `HashMap` and `RwLock`
+- Suitable for development and testing
+- No external dependencies
+
+#### PostgreSQL Repository (`backend/crates/postgres/`)
+- SQLx-based PostgreSQL implementation
+- Connection pooling with PgPool
+- Prepared query caching for performance
+- Migration support
+
+### Interface Layer
+
+#### HTTP API (`backend/crates/api/`)
+- **Framework**: Axum
+- **Features**: 
+  - RESTful endpoints for users and products
+  - CORS support
+  - Request/response logging
+  - JSON serialization/deserialization
+- **Endpoints**:
+  - `POST /users` - Create user
+  - `GET /users/:id` - Get user by ID
+  - `GET /users` - List all users
+  - `PUT /users/:id` - Update user
+  - `DELETE /users/:id` - Delete user
+  - `POST /products` - Create product
+  - `GET /products/:id` - Get product by ID
+  - `GET /products` - List all products
+  - `PUT /products/:id` - Update product
+  - `DELETE /products/:id` - Delete product
+
+#### CLI (`backend/crates/cli/`)
+- **Framework**: Clap
+- **Features**:
+  - Subcommand-based interface
+  - User and product management commands
+  - JSON output support
+- **Commands**:
+  - `user create --username <name> --email <email>`
+  - `user get --id <id>`
+  - `user list`
+  - `user update --id <id> [--username <name>] [--email <email>]`
+  - `user delete --id <id>`
+  - `product create --name <name> --description <desc>`
+  - `product get --id <id>`
+  - `product list`
+  - `product update --id <id> [--name <name>] [--description <desc>]`
+  - `product delete --id <id>`
+
+#### TUI (`backend/crates/tui/`)
+- **Framework**: Ratatui
+- **Features**:
+  - Interactive terminal interface
+  - Table-based data display
+  - Form-based data entry
+  - Navigation between users and products
+
+### Frontend (`frontend/`)
+
+#### Technology Stack
+- **Framework**: Next.js 15.3.3
+- **Language**: TypeScript
+- **UI Library**: React 19
+- **Styling**: Tailwind CSS
+- **Components**: shadcn/ui
+- **Form Handling**: React Hook Form with Zod validation
+- **HTTP Client**: Axios
+
+#### Key Features
+- **Dashboard**: Overview page with navigation to users and products
+- **Users Management**: 
+  - View all users in a table
+  - Create new users via dialog
+  - Edit existing users
+  - Delete users with confirmation
+- **Products Management**:
+  - View all products in a table
+  - Create new products via dialog
+  - Edit existing products
+  - Delete products with confirmation
+
+#### API Integration
+- **Base URL**: `http://127.0.0.1:3000`
+- **Client**: Axios-based API client in `src/lib/api.ts`
+- **Type Safety**: Full TypeScript interfaces for API responses
+
+## Database Schema
+
+### Users Table
+```sql
+CREATE TABLE users (
+    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+    username TEXT NOT NULL,
+    email TEXT NOT NULL,
+    created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+```
+
+### Products Table
+```sql
+CREATE TABLE products (
+    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+    name TEXT NOT NULL,
+    description TEXT NOT NULL,
+    created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+```
+
+## Configuration
+
+### Backend Configuration
+Configuration files are located in `backend/config/`:
+- `api-memory.env` - API server with in-memory storage
+- `api-postgres.env` - API server with PostgreSQL storage
+- `cli-memory.env` - CLI with in-memory storage
+- `cli-postgres.env` - CLI with PostgreSQL storage
+- `tui-memory.env` - TUI with in-memory storage
+- `tui-postgres.env` - TUI with PostgreSQL storage
+
+### Environment Variables
+- `SERVER_ADDR` - Server address (default: 127.0.0.1:3000)
+- `DATABASE_URL` - PostgreSQL connection string
+- `RUST_LOG` - Logging level (default: info)
+
+## Development Workflow
+
+### Backend Development
+1. **Setup**: Install Rust and SQLx CLI
+2. **Database**: Create database and run migrations
+3. **Build**: `cargo build`
+4. **Run**: Choose appropriate binary for your use case
+5. **Test**: `cargo test`
+
+### Frontend Development
+1. **Setup**: Install Node.js and npm
+2. **Install**: `npm install`
+3. **Run**: `npm run dev`
+4. **Build**: `npm run build`
+
+### Running the Full Stack
+1. Start backend: `cargo run --bin sharenet-api-postgres`
+2. Start frontend: `cd frontend && npm run dev`
+3. Access web interface at `http://localhost:3000`
+
+## Testing
+
+### Backend Testing
+- **Unit Tests**: Each crate has comprehensive unit tests
+- **Integration Tests**: Repository implementations are tested
+- **Mock Testing**: Mock repositories for isolated testing
+
+### Frontend Testing
+- **Component Testing**: Individual React components
+- **Integration Testing**: API integration and user flows
+- **E2E Testing**: Full application workflows
+
+## Deployment
+
+### Backend Deployment
+- **Docker**: Containerized deployment
+- **Binary**: Standalone executables
+- **Database**: PostgreSQL with connection pooling
+
+### Frontend Deployment
+- **Vercel**: Optimized for Next.js
+- **Static Export**: Can be deployed to any static hosting
+- **Docker**: Containerized deployment
+
+## Performance Considerations
+
+### Backend
+- **Connection Pooling**: PostgreSQL connection pooling
+- **Query Caching**: SQLx prepared query caching
+- **Async/Await**: Non-blocking I/O operations
+- **Generic Implementations**: Zero-cost abstractions
+
+### Frontend
+- **Code Splitting**: Next.js automatic code splitting
+- **Static Generation**: Pre-rendered pages where possible
+- **Optimized Images**: Next.js image optimization
+- **Bundle Analysis**: Webpack bundle analysis
+
+## Security
+
+### Backend Security
+- **Input Validation**: Domain-level validation
+- **Error Handling**: Secure error messages
+- **CORS**: Configurable CORS policies
+- **SQL Injection**: SQLx prevents SQL injection
+
+### Frontend Security
+- **Type Safety**: TypeScript prevents type-related errors
+- **Input Validation**: Client-side validation with Zod
+- **XSS Prevention**: React automatic escaping
+- **CSRF Protection**: Built-in Next.js protection
+
+## Future Enhancements
+
+### Planned Features
+- **Authentication**: User authentication and authorization
+- **Role-Based Access Control**: User roles and permissions
+- **Product Categories**: Product categorization system
+- **Inventory Tracking**: Stock management
+- **Audit Logging**: Operation logging and history
+- **API Documentation**: OpenAPI/Swagger documentation
+- **Real-time Updates**: WebSocket support
+- **File Uploads**: Product image uploads
+- **Search and Filtering**: Advanced data filtering
+- **Pagination**: Large dataset handling
+
+### Technical Improvements
+- **Caching**: Redis integration for caching
+- **Monitoring**: Application monitoring and metrics
+- **Logging**: Structured logging with correlation IDs
+- **Health Checks**: Application health endpoints
+- **Rate Limiting**: API rate limiting
+- **Compression**: Response compression
+- **CDN**: Static asset delivery optimization
+
+## Contributing
+
+### Development Guidelines
+- **Code Style**: Follow Rust and TypeScript conventions
+- **Testing**: Maintain high test coverage
+- **Documentation**: Keep documentation up to date
+- **Architecture**: Follow clean architecture principles
+- **Error Handling**: Comprehensive error handling
+- **Performance**: Consider performance implications
+
+### Code Review Process
+- **Pull Requests**: All changes via pull requests
+- **Code Review**: Mandatory code review
+- **Testing**: Automated testing on all changes
+- **Documentation**: Update documentation as needed
+
+## License
+
+This project is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License - see the [LICENSE.md](LICENSE.md) file for details.
+
+For more information about the license and compliance requirements, see [LICENSE_NOTICE.md](LICENSE_NOTICE.md). 
\ No newline at end of file
diff --git a/README.md b/README.md
index a07e50e..d56912e 100644
--- a/README.md
+++ b/README.md
@@ -144,4 +144,6 @@ The frontend is configured to connect to the backend at `http://127.0.0.1:3000`
 
 ## License
 
-This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details. 
\ No newline at end of file
+This project is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License - see the [LICENSE.md](LICENSE.md) file for details.
+
+For more information about the license and compliance requirements, see [LICENSE_NOTICE.md](LICENSE_NOTICE.md). 
\ No newline at end of file
diff --git a/backend/Cargo.toml b/backend/Cargo.toml
index 0b1930c..5f3c057 100644
--- a/backend/Cargo.toml
+++ b/backend/Cargo.toml
@@ -8,7 +8,7 @@ resolver = "2"
 version = "0.1.0"
 edition = "2021"
 authors = ["Continuist <continuist02@gmail.com>"]
-license = "CC-BY-NC-4.0"
+license = "CC-BY-NC-SA-4.0"
 
 [workspace.dependencies]
 tokio = { version = "1.36", features = ["full"] }
diff --git a/backend/crates/api/src/lib.rs b/backend/crates/api/src/lib.rs
index 3b3914f..2f2185e 100644
--- a/backend/crates/api/src/lib.rs
+++ b/backend/crates/api/src/lib.rs
@@ -1,3 +1,14 @@
+/*
+ * This file is part of Sharenet.
+ * 
+ * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
+ * 
+ * You may obtain a copy of the license at:
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/
+ * 
+ * Copyright (c) 2024 Continuist <continuist02@gmail.com>
+ */
+
 use std::net::SocketAddr;
 use std::sync::Arc;
 
diff --git a/backend/crates/application/Cargo.toml b/backend/crates/application/Cargo.toml
index bbe9c0f..dfc40c5 100644
--- a/backend/crates/application/Cargo.toml
+++ b/backend/crates/application/Cargo.toml
@@ -9,3 +9,7 @@ license.workspace = true
 domain = { path = "../domain" }
 thiserror = { workspace = true }
 uuid = { workspace = true }
+
+[dev-dependencies]
+tokio = { workspace = true, features = ["full", "macros", "rt-multi-thread"] }
+chrono = { workspace = true }
diff --git a/backend/crates/application/src/lib.rs b/backend/crates/application/src/lib.rs
index a745f01..cbb39fb 100644
--- a/backend/crates/application/src/lib.rs
+++ b/backend/crates/application/src/lib.rs
@@ -1,3 +1,14 @@
+/*
+ * This file is part of Sharenet.
+ * 
+ * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
+ * 
+ * You may obtain a copy of the license at:
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/
+ * 
+ * Copyright (c) 2024 Continuist <continuist02@gmail.com>
+ */
+
 use domain::{Result, Entity};
 use thiserror::Error;
 use uuid::Uuid;
@@ -76,3 +87,361 @@ impl<T: Entity, R: Repository<T> + Clone> UseCase<T> for Service<T, R> {
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use domain::{User, CreateUser, UpdateUser, Product, CreateProduct, UpdateProduct};
+    use std::sync::Arc;
+    use tokio::sync::RwLock;
+    use std::collections::HashMap;
+    use chrono::Utc;
+
+    // Mock repository for testing
+    #[derive(Clone)]
+    struct MockRepository<T: Entity> {
+        data: Arc<RwLock<HashMap<Uuid, T>>>,
+    }
+
+    impl<T: Entity + Clone + Send + Sync> MockRepository<T> {
+        fn new() -> Self {
+            Self {
+                data: Arc::new(RwLock::new(HashMap::new())),
+            }
+        }
+    }
+
+    impl Repository<User> for MockRepository<User> {
+        fn create(&self, data: CreateUser) -> impl Future<Output = Result<User>> + Send {
+            async move {
+                let mut guard = self.data.write().await;
+                let id = Uuid::new_v4();
+                let user = User {
+                    id,
+                    username: data.username,
+                    email: data.email,
+                    created_at: Utc::now(),
+                    updated_at: Utc::now(),
+                };
+                guard.insert(id, user.clone());
+                Ok(user)
+            }
+        }
+
+        fn find_by_id(&self, id: Uuid) -> impl Future<Output = Result<User>> + Send {
+            async move {
+                let guard = self.data.read().await;
+                guard.get(&id)
+                    .cloned()
+                    .ok_or_else(|| domain::DomainError::NotFound(format!("Entity not found: {}", id)))
+            }
+        }
+
+        fn find_all(&self) -> impl Future<Output = Result<Vec<User>>> + Send {
+            async move {
+                let guard = self.data.read().await;
+                Ok(guard.values().cloned().collect())
+            }
+        }
+
+        fn update(&self, id: Uuid, data: UpdateUser) -> impl Future<Output = Result<User>> + Send {
+            async move {
+                let mut guard = self.data.write().await;
+                let user = guard.get_mut(&id)
+                    .ok_or_else(|| domain::DomainError::NotFound(format!("Entity not found: {}", id)))?;
+                
+                if let Some(username) = data.username {
+                    user.username = username;
+                }
+                if let Some(email) = data.email {
+                    user.email = email;
+                }
+                user.updated_at = Utc::now();
+                Ok(user.clone())
+            }
+        }
+
+        fn delete(&self, id: Uuid) -> impl Future<Output = Result<()>> + Send {
+            async move {
+                let mut guard = self.data.write().await;
+                guard.remove(&id)
+                    .ok_or_else(|| domain::DomainError::NotFound(format!("Entity not found: {}", id)))?;
+                Ok(())
+            }
+        }
+    }
+
+    impl Repository<Product> for MockRepository<Product> {
+        fn create(&self, data: CreateProduct) -> impl Future<Output = Result<Product>> + Send {
+            async move {
+                let mut guard = self.data.write().await;
+                let id = Uuid::new_v4();
+                let product = Product {
+                    id,
+                    name: data.name,
+                    description: data.description,
+                    created_at: Utc::now(),
+                    updated_at: Utc::now(),
+                };
+                guard.insert(id, product.clone());
+                Ok(product)
+            }
+        }
+
+        fn find_by_id(&self, id: Uuid) -> impl Future<Output = Result<Product>> + Send {
+            async move {
+                let guard = self.data.read().await;
+                guard.get(&id)
+                    .cloned()
+                    .ok_or_else(|| domain::DomainError::NotFound(format!("Entity not found: {}", id)))
+            }
+        }
+
+        fn find_all(&self) -> impl Future<Output = Result<Vec<Product>>> + Send {
+            async move {
+                let guard = self.data.read().await;
+                Ok(guard.values().cloned().collect())
+            }
+        }
+
+        fn update(&self, id: Uuid, data: UpdateProduct) -> impl Future<Output = Result<Product>> + Send {
+            async move {
+                let mut guard = self.data.write().await;
+                let product = guard.get_mut(&id)
+                    .ok_or_else(|| domain::DomainError::NotFound(format!("Entity not found: {}", id)))?;
+                
+                if let Some(name) = data.name {
+                    product.name = name;
+                }
+                if let Some(description) = data.description {
+                    product.description = description;
+                }
+                product.updated_at = Utc::now();
+                Ok(product.clone())
+            }
+        }
+
+        fn delete(&self, id: Uuid) -> impl Future<Output = Result<()>> + Send {
+            async move {
+                let mut guard = self.data.write().await;
+                guard.remove(&id)
+                    .ok_or_else(|| domain::DomainError::NotFound(format!("Entity not found: {}", id)))?;
+                Ok(())
+            }
+        }
+    }
+
+    mod service_tests {
+        use super::*;
+
+        #[tokio::test]
+        async fn test_user_service_create() {
+            let repo = MockRepository::<User>::new();
+            let service = Service::new(repo);
+
+            let create_user = CreateUser {
+                username: "test_user".to_string(),
+                email: "test@example.com".to_string(),
+            };
+
+            let user = service.create(create_user).await.unwrap();
+            assert_eq!(user.username, "test_user");
+            assert_eq!(user.email, "test@example.com");
+        }
+
+        #[tokio::test]
+        async fn test_user_service_get() {
+            let repo = MockRepository::<User>::new();
+            let service = Service::new(repo);
+
+            let create_user = CreateUser {
+                username: "test_user".to_string(),
+                email: "test@example.com".to_string(),
+            };
+
+            let created = service.create(create_user).await.unwrap();
+            let found = service.get(created.id).await.unwrap();
+            assert_eq!(found.id, created.id);
+        }
+
+        #[tokio::test]
+        async fn test_user_service_list() {
+            let repo = MockRepository::<User>::new();
+            let service = Service::new(repo);
+
+            let user1 = CreateUser {
+                username: "user1".to_string(),
+                email: "user1@example.com".to_string(),
+            };
+            let user2 = CreateUser {
+                username: "user2".to_string(),
+                email: "user2@example.com".to_string(),
+            };
+
+            service.create(user1).await.unwrap();
+            service.create(user2).await.unwrap();
+
+            let users = service.list().await.unwrap();
+            assert_eq!(users.len(), 2);
+        }
+
+        #[tokio::test]
+        async fn test_user_service_update() {
+            let repo = MockRepository::<User>::new();
+            let service = Service::new(repo);
+
+            let create_user = CreateUser {
+                username: "test_user".to_string(),
+                email: "test@example.com".to_string(),
+            };
+
+            let created = service.create(create_user).await.unwrap();
+            let update = UpdateUser {
+                username: Some("updated_user".to_string()),
+                email: None,
+            };
+
+            let updated = service.update(created.id, update).await.unwrap();
+            assert_eq!(updated.username, "updated_user");
+            assert_eq!(updated.email, "test@example.com");
+        }
+
+        #[tokio::test]
+        async fn test_user_service_delete() {
+            let repo = MockRepository::<User>::new();
+            let service = Service::new(repo);
+
+            let create_user = CreateUser {
+                username: "test_user".to_string(),
+                email: "test@example.com".to_string(),
+            };
+
+            let created = service.create(create_user).await.unwrap();
+            service.delete(created.id).await.unwrap();
+            assert!(service.get(created.id).await.is_err());
+        }
+
+        #[tokio::test]
+        async fn test_product_service_create() {
+            let repo = MockRepository::<Product>::new();
+            let service = Service::new(repo);
+
+            let create_product = CreateProduct {
+                name: "Test Product".to_string(),
+                description: "Test Description".to_string(),
+            };
+
+            let product = service.create(create_product).await.unwrap();
+            assert_eq!(product.name, "Test Product");
+            assert_eq!(product.description, "Test Description");
+        }
+
+        #[tokio::test]
+        async fn test_product_service_get() {
+            let repo = MockRepository::<Product>::new();
+            let service = Service::new(repo);
+
+            let create_product = CreateProduct {
+                name: "Test Product".to_string(),
+                description: "Test Description".to_string(),
+            };
+
+            let created = service.create(create_product).await.unwrap();
+            let found = service.get(created.id).await.unwrap();
+            assert_eq!(found.id, created.id);
+        }
+
+        #[tokio::test]
+        async fn test_product_service_list() {
+            let repo = MockRepository::<Product>::new();
+            let service = Service::new(repo);
+
+            let product1 = CreateProduct {
+                name: "Product 1".to_string(),
+                description: "Description 1".to_string(),
+            };
+            let product2 = CreateProduct {
+                name: "Product 2".to_string(),
+                description: "Description 2".to_string(),
+            };
+
+            service.create(product1).await.unwrap();
+            service.create(product2).await.unwrap();
+
+            let products = service.list().await.unwrap();
+            assert_eq!(products.len(), 2);
+        }
+
+        #[tokio::test]
+        async fn test_product_service_update() {
+            let repo = MockRepository::<Product>::new();
+            let service = Service::new(repo);
+
+            let create_product = CreateProduct {
+                name: "Test Product".to_string(),
+                description: "Test Description".to_string(),
+            };
+
+            let created = service.create(create_product).await.unwrap();
+            let update = UpdateProduct {
+                name: Some("Updated Product".to_string()),
+                description: None,
+            };
+
+            let updated = service.update(created.id, update).await.unwrap();
+            assert_eq!(updated.name, "Updated Product");
+            assert_eq!(updated.description, "Test Description");
+        }
+
+        #[tokio::test]
+        async fn test_product_service_delete() {
+            let repo = MockRepository::<Product>::new();
+            let service = Service::new(repo);
+
+            let create_product = CreateProduct {
+                name: "Test Product".to_string(),
+                description: "Test Description".to_string(),
+            };
+
+            let created = service.create(create_product).await.unwrap();
+            service.delete(created.id).await.unwrap();
+            assert!(service.get(created.id).await.is_err());
+        }
+    }
+
+    mod error_tests {
+        use super::*;
+
+        #[tokio::test]
+        async fn test_not_found_error() {
+            let repo = MockRepository::<User>::new();
+            let service = Service::new(repo);
+
+            let result = service.get(Uuid::new_v4()).await;
+            assert!(matches!(result, Err(ApplicationError::Domain(domain::DomainError::NotFound(_)))));
+        }
+
+        #[tokio::test]
+        async fn test_update_nonexistent() {
+            let repo = MockRepository::<User>::new();
+            let service = Service::new(repo);
+
+            let update = UpdateUser {
+                username: Some("new_username".to_string()),
+                email: None,
+            };
+
+            let result = service.update(Uuid::new_v4(), update).await;
+            assert!(matches!(result, Err(ApplicationError::Domain(domain::DomainError::NotFound(_)))));
+        }
+
+        #[tokio::test]
+        async fn test_delete_nonexistent() {
+            let repo = MockRepository::<User>::new();
+            let service = Service::new(repo);
+
+            let result = service.delete(Uuid::new_v4()).await;
+            assert!(matches!(result, Err(ApplicationError::Domain(domain::DomainError::NotFound(_)))));
+        }
+    }
+}
diff --git a/backend/crates/cli/src/lib.rs b/backend/crates/cli/src/lib.rs
index 81b8a7c..cea65cc 100644
--- a/backend/crates/cli/src/lib.rs
+++ b/backend/crates/cli/src/lib.rs
@@ -1,3 +1,14 @@
+/*
+ * This file is part of Sharenet.
+ * 
+ * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
+ * 
+ * You may obtain a copy of the license at:
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/
+ * 
+ * Copyright (c) 2024 Continuist <continuist02@gmail.com>
+ */
+
 use anyhow::Result;
 use clap::Parser;
 use domain::{CreateProduct, CreateUser, Product, User, UpdateProduct, UpdateUser};
diff --git a/backend/crates/domain/Cargo.toml b/backend/crates/domain/Cargo.toml
index 5cae3c0..c093933 100644
--- a/backend/crates/domain/Cargo.toml
+++ b/backend/crates/domain/Cargo.toml
@@ -10,3 +10,6 @@ serde = { workspace = true }
 uuid = { workspace = true }
 chrono = { workspace = true }
 thiserror = { workspace = true }
+
+[dev-dependencies]
+tokio = { workspace = true, features = ["full", "macros", "rt-multi-thread"] }
diff --git a/backend/crates/domain/src/lib.rs b/backend/crates/domain/src/lib.rs
index 7adb64e..4126f23 100644
--- a/backend/crates/domain/src/lib.rs
+++ b/backend/crates/domain/src/lib.rs
@@ -1,3 +1,14 @@
+/*
+ * This file is part of Sharenet.
+ * 
+ * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
+ * 
+ * You may obtain a copy of the license at:
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/
+ * 
+ * Copyright (c) 2024 Continuist <continuist02@gmail.com>
+ */
+
 use chrono::{DateTime, Utc};
 use serde::{Deserialize, Serialize};
 use thiserror::Error;
@@ -89,17 +100,233 @@ where
     fn delete(&self, id: Uuid) -> impl Future<Output = Result<()>> + Send;
 }
 
-pub fn add(left: u64, right: u64) -> u64 {
-    left + right
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
+    use chrono::Utc;
 
-    #[test]
-    fn it_works() {
-        let result = add(2, 2);
-        assert_eq!(result, 4);
+    mod user_tests {
+        use super::*;
+
+        #[test]
+        fn test_user_entity_impl() {
+            let user = User {
+                id: Uuid::new_v4(),
+                username: "test_user".to_string(),
+                email: "test@example.com".to_string(),
+                created_at: Utc::now(),
+                updated_at: Utc::now(),
+            };
+
+            assert_eq!(user.username, "test_user");
+            assert_eq!(user.email, "test@example.com");
+        }
+
+        #[test]
+        fn test_create_user_validation() {
+            let create_user = CreateUser {
+                username: "test_user".to_string(),
+                email: "test@example.com".to_string(),
+            };
+
+            assert_eq!(create_user.username, "test_user");
+            assert_eq!(create_user.email, "test@example.com");
+        }
+
+        #[test]
+        fn test_update_user_partial() {
+            let update_user = UpdateUser {
+                username: Some("new_username".to_string()),
+                email: None,
+            };
+
+            assert_eq!(update_user.username, Some("new_username".to_string()));
+            assert_eq!(update_user.email, None);
+        }
+    }
+
+    mod product_tests {
+        use super::*;
+
+        #[test]
+        fn test_product_entity_impl() {
+            let product = Product {
+                id: Uuid::new_v4(),
+                name: "Test Product".to_string(),
+                description: "Test Description".to_string(),
+                created_at: Utc::now(),
+                updated_at: Utc::now(),
+            };
+
+            assert_eq!(product.name, "Test Product");
+            assert_eq!(product.description, "Test Description");
+        }
+
+        #[test]
+        fn test_create_product_validation() {
+            let create_product = CreateProduct {
+                name: "Test Product".to_string(),
+                description: "Test Description".to_string(),
+            };
+
+            assert_eq!(create_product.name, "Test Product");
+            assert_eq!(create_product.description, "Test Description");
+        }
+
+        #[test]
+        fn test_update_product_partial() {
+            let update_product = UpdateProduct {
+                name: Some("New Product Name".to_string()),
+                description: None,
+            };
+
+            assert_eq!(update_product.name, Some("New Product Name".to_string()));
+            assert_eq!(update_product.description, None);
+        }
+    }
+
+    mod domain_error_tests {
+        use super::*;
+
+        #[test]
+        fn test_not_found_error() {
+            let error = DomainError::NotFound("User not found".to_string());
+            assert_eq!(error.to_string(), "Entity not found: User not found");
+        }
+
+        #[test]
+        fn test_invalid_input_error() {
+            let error = DomainError::InvalidInput("Invalid email format".to_string());
+            assert_eq!(error.to_string(), "Invalid input: Invalid email format");
+        }
+
+        #[test]
+        fn test_internal_error() {
+            let error = DomainError::Internal("Database connection failed".to_string());
+            assert_eq!(error.to_string(), "Internal error: Database connection failed");
+        }
+    }
+
+    mod repository_trait_tests {
+        use super::*;
+        use std::sync::Arc;
+        use tokio::sync::RwLock;
+        use std::collections::HashMap;
+
+        // Mock implementation of Repository for testing
+        struct MockRepository<T> {
+            data: Arc<RwLock<HashMap<Uuid, T>>>,
+        }
+
+        impl<T: Clone + Send + Sync> MockRepository<T> {
+            fn new() -> Self {
+                Self {
+                    data: Arc::new(RwLock::new(HashMap::new())),
+                }
+            }
+        }
+
+        #[tokio::test]
+        async fn test_repository_create() {
+            let repo = MockRepository::<User>::new();
+            let create_user = CreateUser {
+                username: "test_user".to_string(),
+                email: "test@example.com".to_string(),
+            };
+
+            let user = User {
+                id: Uuid::new_v4(),
+                username: create_user.username.clone(),
+                email: create_user.email.clone(),
+                created_at: Utc::now(),
+                updated_at: Utc::now(),
+            };
+
+            repo.data.write().await.insert(user.id, user.clone());
+            let guard = repo.data.read().await;
+            let stored = guard.get(&user.id).unwrap();
+            assert_eq!(stored.username, create_user.username);
+            assert_eq!(stored.email, create_user.email);
+        }
+
+        #[tokio::test]
+        async fn test_repository_find_by_id() {
+            let repo = MockRepository::<User>::new();
+            let user = User {
+                id: Uuid::new_v4(),
+                username: "test_user".to_string(),
+                email: "test@example.com".to_string(),
+                created_at: Utc::now(),
+                updated_at: Utc::now(),
+            };
+
+            repo.data.write().await.insert(user.id, user.clone());
+            let guard = repo.data.read().await;
+            let found = guard.get(&user.id).unwrap();
+            assert_eq!(found.id, user.id);
+        }
+
+        #[tokio::test]
+        async fn test_repository_find_all() {
+            let repo = MockRepository::<User>::new();
+            let user1 = User {
+                id: Uuid::new_v4(),
+                username: "user1".to_string(),
+                email: "user1@example.com".to_string(),
+                created_at: Utc::now(),
+                updated_at: Utc::now(),
+            };
+            let user2 = User {
+                id: Uuid::new_v4(),
+                username: "user2".to_string(),
+                email: "user2@example.com".to_string(),
+                created_at: Utc::now(),
+                updated_at: Utc::now(),
+            };
+
+            repo.data.write().await.insert(user1.id, user1.clone());
+            repo.data.write().await.insert(user2.id, user2.clone());
+            
+            let all = repo.data.read().await;
+            assert_eq!(all.len(), 2);
+        }
+
+        #[tokio::test]
+        async fn test_repository_update() {
+            let repo = MockRepository::<User>::new();
+            let user = User {
+                id: Uuid::new_v4(),
+                username: "test_user".to_string(),
+                email: "test@example.com".to_string(),
+                created_at: Utc::now(),
+                updated_at: Utc::now(),
+            };
+
+            repo.data.write().await.insert(user.id, user.clone());
+            let mut guard = repo.data.write().await;
+            let stored = guard.get_mut(&user.id).unwrap();
+            stored.username = "updated_user".to_string();
+            
+            drop(guard);
+            let read_guard = repo.data.read().await;
+            let updated = read_guard.get(&user.id).unwrap();
+            assert_eq!(updated.username, "updated_user");
+        }
+
+        #[tokio::test]
+        async fn test_repository_delete() {
+            let repo = MockRepository::<User>::new();
+            let user = User {
+                id: Uuid::new_v4(),
+                username: "test_user".to_string(),
+                email: "test@example.com".to_string(),
+                created_at: Utc::now(),
+                updated_at: Utc::now(),
+            };
+
+            repo.data.write().await.insert(user.id, user.clone());
+            repo.data.write().await.remove(&user.id);
+            assert!(repo.data.read().await.get(&user.id).is_none());
+        }
     }
 }
diff --git a/backend/crates/memory/src/lib.rs b/backend/crates/memory/src/lib.rs
index 337ffad..4df1982 100644
--- a/backend/crates/memory/src/lib.rs
+++ b/backend/crates/memory/src/lib.rs
@@ -1,3 +1,14 @@
+/*
+ * This file is part of Sharenet.
+ * 
+ * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
+ * 
+ * You may obtain a copy of the license at:
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/
+ * 
+ * Copyright (c) 2024 Continuist <continuist02@gmail.com>
+ */
+
 use std::collections::HashMap;
 use std::sync::Arc;
 use tokio::sync::RwLock;
@@ -142,20 +153,5 @@ impl Repository<Product> for InMemoryProductRepository {
     }
 }
 
-pub fn add(left: u64, right: u64) -> u64 {
-    left + right
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn it_works() {
-        let result = add(2, 2);
-        assert_eq!(result, 4);
-    }
-}
-
 pub type MemoryUserService = Service<User, InMemoryUserRepository>;
 pub type MemoryProductService = Service<Product, InMemoryProductRepository>;
diff --git a/backend/crates/postgres/.sqlx/query-508d8e56fc561537060a4bf378dc057cc55999d2115521419d00ca57843af046.json b/backend/crates/postgres/.sqlx/query-508d8e56fc561537060a4bf378dc057cc55999d2115521419d00ca57843af046.json
new file mode 100644
index 0000000..206684b
--- /dev/null
+++ b/backend/crates/postgres/.sqlx/query-508d8e56fc561537060a4bf378dc057cc55999d2115521419d00ca57843af046.json
@@ -0,0 +1,48 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "\n            UPDATE users\n            SET\n                username = COALESCE($1, username),\n                email = COALESCE($2, email),\n                updated_at = CURRENT_TIMESTAMP\n            WHERE id = $3\n            RETURNING id, username, email, created_at, updated_at\n            ",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "id",
+        "type_info": "Uuid"
+      },
+      {
+        "ordinal": 1,
+        "name": "username",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 2,
+        "name": "email",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 3,
+        "name": "created_at",
+        "type_info": "Timestamptz"
+      },
+      {
+        "ordinal": 4,
+        "name": "updated_at",
+        "type_info": "Timestamptz"
+      }
+    ],
+    "parameters": {
+      "Left": [
+        "Text",
+        "Text",
+        "Uuid"
+      ]
+    },
+    "nullable": [
+      false,
+      false,
+      false,
+      false,
+      false
+    ]
+  },
+  "hash": "508d8e56fc561537060a4bf378dc057cc55999d2115521419d00ca57843af046"
+}
diff --git a/backend/crates/postgres/.sqlx/query-54394890f1b4efd6487c5147e9a1942a86d7b2edfeea1cfb432758acbfbe6da6.json b/backend/crates/postgres/.sqlx/query-54394890f1b4efd6487c5147e9a1942a86d7b2edfeea1cfb432758acbfbe6da6.json
new file mode 100644
index 0000000..43f6a53
--- /dev/null
+++ b/backend/crates/postgres/.sqlx/query-54394890f1b4efd6487c5147e9a1942a86d7b2edfeea1cfb432758acbfbe6da6.json
@@ -0,0 +1,44 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "\n            SELECT id, username, email, created_at, updated_at\n            FROM users\n            ",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "id",
+        "type_info": "Uuid"
+      },
+      {
+        "ordinal": 1,
+        "name": "username",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 2,
+        "name": "email",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 3,
+        "name": "created_at",
+        "type_info": "Timestamptz"
+      },
+      {
+        "ordinal": 4,
+        "name": "updated_at",
+        "type_info": "Timestamptz"
+      }
+    ],
+    "parameters": {
+      "Left": []
+    },
+    "nullable": [
+      false,
+      false,
+      false,
+      false,
+      false
+    ]
+  },
+  "hash": "54394890f1b4efd6487c5147e9a1942a86d7b2edfeea1cfb432758acbfbe6da6"
+}
diff --git a/backend/crates/postgres/.sqlx/query-5bb95e6a9bea1ac6d4aab08eb63b1f9127a3a6b95046bb91bea60a2d6ee6dfc2.json b/backend/crates/postgres/.sqlx/query-5bb95e6a9bea1ac6d4aab08eb63b1f9127a3a6b95046bb91bea60a2d6ee6dfc2.json
new file mode 100644
index 0000000..be3bf47
--- /dev/null
+++ b/backend/crates/postgres/.sqlx/query-5bb95e6a9bea1ac6d4aab08eb63b1f9127a3a6b95046bb91bea60a2d6ee6dfc2.json
@@ -0,0 +1,46 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "\n            SELECT id, username, email, created_at, updated_at\n            FROM users\n            WHERE id = $1\n            ",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "id",
+        "type_info": "Uuid"
+      },
+      {
+        "ordinal": 1,
+        "name": "username",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 2,
+        "name": "email",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 3,
+        "name": "created_at",
+        "type_info": "Timestamptz"
+      },
+      {
+        "ordinal": 4,
+        "name": "updated_at",
+        "type_info": "Timestamptz"
+      }
+    ],
+    "parameters": {
+      "Left": [
+        "Uuid"
+      ]
+    },
+    "nullable": [
+      false,
+      false,
+      false,
+      false,
+      false
+    ]
+  },
+  "hash": "5bb95e6a9bea1ac6d4aab08eb63b1f9127a3a6b95046bb91bea60a2d6ee6dfc2"
+}
diff --git a/backend/crates/postgres/.sqlx/query-62874c01dcd85e441608d6d92661277e3b3638412204a2aa5fad7a51c3ce855d.json b/backend/crates/postgres/.sqlx/query-62874c01dcd85e441608d6d92661277e3b3638412204a2aa5fad7a51c3ce855d.json
new file mode 100644
index 0000000..534a05a
--- /dev/null
+++ b/backend/crates/postgres/.sqlx/query-62874c01dcd85e441608d6d92661277e3b3638412204a2aa5fad7a51c3ce855d.json
@@ -0,0 +1,44 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "\n            SELECT id, name, description, created_at, updated_at\n            FROM products\n            ",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "id",
+        "type_info": "Uuid"
+      },
+      {
+        "ordinal": 1,
+        "name": "name",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 2,
+        "name": "description",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 3,
+        "name": "created_at",
+        "type_info": "Timestamptz"
+      },
+      {
+        "ordinal": 4,
+        "name": "updated_at",
+        "type_info": "Timestamptz"
+      }
+    ],
+    "parameters": {
+      "Left": []
+    },
+    "nullable": [
+      false,
+      false,
+      false,
+      false,
+      false
+    ]
+  },
+  "hash": "62874c01dcd85e441608d6d92661277e3b3638412204a2aa5fad7a51c3ce855d"
+}
diff --git a/backend/crates/postgres/.sqlx/query-82746e921edfb33ae6c0f434d96ce74e0de9dc8e24ae1d9fa945b9924498a652.json b/backend/crates/postgres/.sqlx/query-82746e921edfb33ae6c0f434d96ce74e0de9dc8e24ae1d9fa945b9924498a652.json
new file mode 100644
index 0000000..d4cf3a3
--- /dev/null
+++ b/backend/crates/postgres/.sqlx/query-82746e921edfb33ae6c0f434d96ce74e0de9dc8e24ae1d9fa945b9924498a652.json
@@ -0,0 +1,14 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "\n            DELETE FROM products\n            WHERE id = $1\n            ",
+  "describe": {
+    "columns": [],
+    "parameters": {
+      "Left": [
+        "Uuid"
+      ]
+    },
+    "nullable": []
+  },
+  "hash": "82746e921edfb33ae6c0f434d96ce74e0de9dc8e24ae1d9fa945b9924498a652"
+}
diff --git a/backend/crates/postgres/.sqlx/query-882fbe26ce3c2f8baf74b89805fc4be0d99874bee7ffed9d948fc57759f03d61.json b/backend/crates/postgres/.sqlx/query-882fbe26ce3c2f8baf74b89805fc4be0d99874bee7ffed9d948fc57759f03d61.json
new file mode 100644
index 0000000..eb65686
--- /dev/null
+++ b/backend/crates/postgres/.sqlx/query-882fbe26ce3c2f8baf74b89805fc4be0d99874bee7ffed9d948fc57759f03d61.json
@@ -0,0 +1,47 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "\n            INSERT INTO products (name, description)\n            VALUES ($1, $2)\n            RETURNING id, name, description, created_at, updated_at\n            ",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "id",
+        "type_info": "Uuid"
+      },
+      {
+        "ordinal": 1,
+        "name": "name",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 2,
+        "name": "description",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 3,
+        "name": "created_at",
+        "type_info": "Timestamptz"
+      },
+      {
+        "ordinal": 4,
+        "name": "updated_at",
+        "type_info": "Timestamptz"
+      }
+    ],
+    "parameters": {
+      "Left": [
+        "Text",
+        "Text"
+      ]
+    },
+    "nullable": [
+      false,
+      false,
+      false,
+      false,
+      false
+    ]
+  },
+  "hash": "882fbe26ce3c2f8baf74b89805fc4be0d99874bee7ffed9d948fc57759f03d61"
+}
diff --git a/backend/crates/postgres/.sqlx/query-b69a6f42965b3e7103fcbf46e39528466926789ff31e9ed2591bb175527ec169.json b/backend/crates/postgres/.sqlx/query-b69a6f42965b3e7103fcbf46e39528466926789ff31e9ed2591bb175527ec169.json
new file mode 100644
index 0000000..5dd9ec9
--- /dev/null
+++ b/backend/crates/postgres/.sqlx/query-b69a6f42965b3e7103fcbf46e39528466926789ff31e9ed2591bb175527ec169.json
@@ -0,0 +1,14 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "\n            DELETE FROM users\n            WHERE id = $1\n            ",
+  "describe": {
+    "columns": [],
+    "parameters": {
+      "Left": [
+        "Uuid"
+      ]
+    },
+    "nullable": []
+  },
+  "hash": "b69a6f42965b3e7103fcbf46e39528466926789ff31e9ed2591bb175527ec169"
+}
diff --git a/backend/crates/postgres/.sqlx/query-c424e1240a945e7dea975c325a1a7db21d5503ccfb9f9ad788f3897fb8216eee.json b/backend/crates/postgres/.sqlx/query-c424e1240a945e7dea975c325a1a7db21d5503ccfb9f9ad788f3897fb8216eee.json
new file mode 100644
index 0000000..716319c
--- /dev/null
+++ b/backend/crates/postgres/.sqlx/query-c424e1240a945e7dea975c325a1a7db21d5503ccfb9f9ad788f3897fb8216eee.json
@@ -0,0 +1,48 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "\n            UPDATE products\n            SET\n                name = COALESCE($1, name),\n                description = COALESCE($2, description),\n                updated_at = CURRENT_TIMESTAMP\n            WHERE id = $3\n            RETURNING id, name, description, created_at, updated_at\n            ",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "id",
+        "type_info": "Uuid"
+      },
+      {
+        "ordinal": 1,
+        "name": "name",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 2,
+        "name": "description",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 3,
+        "name": "created_at",
+        "type_info": "Timestamptz"
+      },
+      {
+        "ordinal": 4,
+        "name": "updated_at",
+        "type_info": "Timestamptz"
+      }
+    ],
+    "parameters": {
+      "Left": [
+        "Text",
+        "Text",
+        "Uuid"
+      ]
+    },
+    "nullable": [
+      false,
+      false,
+      false,
+      false,
+      false
+    ]
+  },
+  "hash": "c424e1240a945e7dea975c325a1a7db21d5503ccfb9f9ad788f3897fb8216eee"
+}
diff --git a/backend/crates/postgres/.sqlx/query-ed0fa11d45b99c47dcbf75aa0646cf91516f91388d484e398273be3532d8e027.json b/backend/crates/postgres/.sqlx/query-ed0fa11d45b99c47dcbf75aa0646cf91516f91388d484e398273be3532d8e027.json
new file mode 100644
index 0000000..c66d48e
--- /dev/null
+++ b/backend/crates/postgres/.sqlx/query-ed0fa11d45b99c47dcbf75aa0646cf91516f91388d484e398273be3532d8e027.json
@@ -0,0 +1,46 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "\n            SELECT id, name, description, created_at, updated_at\n            FROM products\n            WHERE id = $1\n            ",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "id",
+        "type_info": "Uuid"
+      },
+      {
+        "ordinal": 1,
+        "name": "name",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 2,
+        "name": "description",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 3,
+        "name": "created_at",
+        "type_info": "Timestamptz"
+      },
+      {
+        "ordinal": 4,
+        "name": "updated_at",
+        "type_info": "Timestamptz"
+      }
+    ],
+    "parameters": {
+      "Left": [
+        "Uuid"
+      ]
+    },
+    "nullable": [
+      false,
+      false,
+      false,
+      false,
+      false
+    ]
+  },
+  "hash": "ed0fa11d45b99c47dcbf75aa0646cf91516f91388d484e398273be3532d8e027"
+}
diff --git a/backend/crates/postgres/.sqlx/query-ffa2228196655e9f2b8152fc4b79d720cadc68f2d12bed4f46aeb87401ce2de9.json b/backend/crates/postgres/.sqlx/query-ffa2228196655e9f2b8152fc4b79d720cadc68f2d12bed4f46aeb87401ce2de9.json
new file mode 100644
index 0000000..1312ca5
--- /dev/null
+++ b/backend/crates/postgres/.sqlx/query-ffa2228196655e9f2b8152fc4b79d720cadc68f2d12bed4f46aeb87401ce2de9.json
@@ -0,0 +1,47 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "\n            INSERT INTO users (username, email)\n            VALUES ($1, $2)\n            RETURNING id, username, email, created_at, updated_at\n            ",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "id",
+        "type_info": "Uuid"
+      },
+      {
+        "ordinal": 1,
+        "name": "username",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 2,
+        "name": "email",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 3,
+        "name": "created_at",
+        "type_info": "Timestamptz"
+      },
+      {
+        "ordinal": 4,
+        "name": "updated_at",
+        "type_info": "Timestamptz"
+      }
+    ],
+    "parameters": {
+      "Left": [
+        "Text",
+        "Text"
+      ]
+    },
+    "nullable": [
+      false,
+      false,
+      false,
+      false,
+      false
+    ]
+  },
+  "hash": "ffa2228196655e9f2b8152fc4b79d720cadc68f2d12bed4f46aeb87401ce2de9"
+}
diff --git a/backend/crates/postgres/src/lib.rs b/backend/crates/postgres/src/lib.rs
index 06fea97..278dee2 100644
--- a/backend/crates/postgres/src/lib.rs
+++ b/backend/crates/postgres/src/lib.rs
@@ -1,3 +1,14 @@
+/*
+ * This file is part of Sharenet.
+ * 
+ * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
+ * 
+ * You may obtain a copy of the license at:
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/
+ * 
+ * Copyright (c) 2024 Continuist <continuist02@gmail.com>
+ */
+
 use sqlx::PgPool;
 use uuid::Uuid;
 
diff --git a/backend/crates/tui/src/lib.rs b/backend/crates/tui/src/lib.rs
index 03c2803..ff77762 100644
--- a/backend/crates/tui/src/lib.rs
+++ b/backend/crates/tui/src/lib.rs
@@ -1,3 +1,14 @@
+/*
+ * This file is part of Sharenet.
+ * 
+ * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
+ * 
+ * You may obtain a copy of the license at:
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/
+ * 
+ * Copyright (c) 2024 Continuist <continuist02@gmail.com>
+ */
+
 use std::io;
 use std::sync::mpsc;
 use std::thread;
diff --git a/frontend/package.json b/frontend/package.json
index 1bf6348..4a240ec 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -2,6 +2,7 @@
   "name": "frontend",
   "version": "0.1.0",
   "private": true,
+  "license": "CC-BY-NC-SA-4.0",
   "scripts": {
     "dev": "next dev --turbopack",
     "build": "next build",
diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx
index 4d1c5c6..625eb5e 100644
--- a/frontend/src/app/layout.tsx
+++ b/frontend/src/app/layout.tsx
@@ -1,3 +1,14 @@
+/**
+ * This file is part of Sharenet.
+ * 
+ * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
+ * 
+ * You may obtain a copy of the license at:
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/
+ * 
+ * Copyright (c) 2024 Continuist <continuist02@gmail.com>
+ */
+
 import type { Metadata } from "next";
 import { Inter } from "next/font/google";
 import "./globals.css";
diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx
index 6d9b739..62dacba 100644
--- a/frontend/src/app/page.tsx
+++ b/frontend/src/app/page.tsx
@@ -1,3 +1,14 @@
+/**
+ * This file is part of Sharenet.
+ * 
+ * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
+ * 
+ * You may obtain a copy of the license at:
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/
+ * 
+ * Copyright (c) 2024 Continuist <continuist02@gmail.com>
+ */
+
 import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
 import Link from "next/link";
 
diff --git a/frontend/src/app/products/page.tsx b/frontend/src/app/products/page.tsx
index 1fd579d..36c06df 100644
--- a/frontend/src/app/products/page.tsx
+++ b/frontend/src/app/products/page.tsx
@@ -1,3 +1,14 @@
+/**
+ * This file is part of Sharenet.
+ * 
+ * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
+ * 
+ * You may obtain a copy of the license at:
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/
+ * 
+ * Copyright (c) 2024 Continuist <continuist02@gmail.com>
+ */
+
 'use client';
 
 import { useState, useEffect } from 'react';
@@ -69,7 +80,7 @@ export default function ProductsPage() {
     setIsDialogOpen(true);
   };
 
-  const handleDelete = async (id: number) => {
+  const handleDelete = async (id: string) => {
     if (confirm('Are you sure you want to delete this product?')) {
       try {
         await productApi.delete(id);
diff --git a/frontend/src/app/users/page.tsx b/frontend/src/app/users/page.tsx
index 8cefb33..6685d24 100644
--- a/frontend/src/app/users/page.tsx
+++ b/frontend/src/app/users/page.tsx
@@ -1,3 +1,14 @@
+/**
+ * This file is part of Sharenet.
+ * 
+ * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
+ * 
+ * You may obtain a copy of the license at:
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/
+ * 
+ * Copyright (c) 2024 Continuist <continuist02@gmail.com>
+ */
+
 'use client';
 
 import { useState, useEffect } from 'react';
diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts
index efed0e8..7f98fa9 100644
--- a/frontend/src/lib/api.ts
+++ b/frontend/src/lib/api.ts
@@ -1,3 +1,14 @@
+/**
+ * This file is part of Sharenet.
+ * 
+ * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
+ * 
+ * You may obtain a copy of the license at:
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/
+ * 
+ * Copyright (c) 2024 Continuist <continuist02@gmail.com>
+ */
+
 import axios from 'axios';
 
 const API_BASE_URL = 'http://127.0.0.1:3000';