Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
228 changes: 226 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,226 @@
### Feature in the Development
- Add refresh expired token in the cache ( adding the logic for cache )
The refactoring for the new version of the software altogether
backend/
├── cmd/
│ └── server/
│ └── main.go # Application entrypoint
├── internal/
│ │
│ ├── domain/ # Core domain layer
│ │ │
│ │ ├── entities/ # Database models (shared)
│ │ │ ├── user.go
│ │ │ ├── tenant.go
│ │ │ ├── role.go
│ │ │ ├── route_role.go
│ │ │ ├── token.go
│ │ │ ├── message.go
│ │ │ ├── login.go
│ │ │ └── reset_token.go
│ │ │
│ │ ├── dto/ # Data Transfer Objects
│ │ │ │
│ │ │ ├── customer/ # Customer API contracts
│ │ │ │ ├── requests/
│ │ │ │ │ ├── auth.go # RegisterUserRequest, LoginRequest
│ │ │ │ │ ├── user.go # UpdateProfileRequest
│ │ │ │ │ ├── role.go # RequestRoleRequest
│ │ │ │ │ └── message.go # CreateMessageRequest
│ │ │ │ │
│ │ │ │ └── responses/
│ │ │ │ ├── auth.go # LoginResponse, RegisterResponse
│ │ │ │ ├── user.go # UserResponse, UserListResponse
│ │ │ │ ├── role.go # RoleResponse, RoleListResponse
│ │ │ │ └── message.go # MessageResponse, MessageStatusResponse
│ │ │ │
│ │ │ └── tenant/ # Tenant/Admin API contracts
│ │ │ ├── requests/
│ │ │ │ ├── tenant.go # CreateTenantRequest, LoginTenantRequest
│ │ │ │ ├── user_admin.go # DisableUserRequest, AssignRoleRequest
│ │ │ │ ├── role_admin.go # CreateRoleRequest, UpdatePermissionsRequest
│ │ │ │ ├── token.go # CreateTokenRequest, RevokeTokenRequest
│ │ │ │ ├── message.go # ApproveMessageRequest, RejectMessageRequest
│ │ │ │ └── dashboard.go # DashboardFiltersRequest
│ │ │ │
│ │ │ └── responses/
│ │ │ ├── tenant.go # TenantResponse, TenantDetailsResponse
│ │ │ ├── user_admin.go # UserAdminResponse, UserListAdminResponse
│ │ │ ├── role_admin.go # RoleAdminResponse, PermissionsResponse
│ │ │ ├── token.go # TokenResponse, TokenListResponse
│ │ │ ├── message.go # MessageAdminResponse
│ │ │ └── dashboard.go # DashboardStatsResponse
│ │ │
│ │ └── errors/ # Custom error types
│ │ ├── errors.go # AppError, ValidationError, etc.
│ │ └── codes.go # Error codes
│ │
│ ├── repository/ # Data access layer
│ │ │
│ │ ├── customer/ # Customer-context repositories
│ │ │ ├── user_repository.go
│ │ │ ├── role_repository.go
│ │ │ ├── message_repository.go
│ │ │ ├── login_repository.go
│ │ │ ├── token_repository.go
│ │ │ └── interfaces.go
│ │ │
│ │ ├── tenant/ # Tenant-context repositories
│ │ │ ├── tenant_repository.go
│ │ │ ├── user_repository.go
│ │ │ ├── role_repository.go
│ │ │ ├── message_repository.go
│ │ │ ├── token_repository.go
│ │ │ ├── tenant_login_repository.go
│ │ │ ├── dashboard_repository.go
│ │ │ └── interfaces.go
│ │ │
│ │ └── shared/ # Shared repository utilities
│ │ ├── base_repository.go
│ │ ├── reset_token_repository.go
│ │ └── route_role_repository.go
│ │
│ ├── service/ # Business logic layer
│ │ │
│ │ ├── customer/ # Customer business logic
│ │ │ ├── auth_service.go
│ │ │ ├── user_service.go
│ │ │ ├── role_service.go
│ │ │ ├── message_service.go
│ │ │ └── interfaces.go
│ │ │
│ │ ├── tenant/ # Tenant business logic
│ │ │ ├── tenant_service.go
│ │ │ ├── user_admin_service.go
│ │ │ ├── role_admin_service.go
│ │ │ ├── token_service.go
│ │ │ ├── message_admin_service.go
│ │ │ ├── dashboard_service.go
│ │ │ └── interfaces.go
│ │ │
│ │ └── shared/ # Shared services
│ │ ├── mail_service.go
│ │ ├── cache_service.go
│ │ └── password_service.go
│ │
│ ├── api/ # HTTP API layer
│ │ │
│ │ ├── customer/ # Customer-facing API (Port 8080)
│ │ │ ├── handlers/
│ │ │ │ ├── auth_handler.go
│ │ │ │ ├── user_handler.go
│ │ │ │ ├── role_handler.go
│ │ │ │ ├── message_handler.go
│ │ │ │ └── common.go # Shared response helpers
│ │ │ │
│ │ │ ├── middleware/
│ │ │ │ ├── app_key.go
│ │ │ │ ├── jwt_auth.go
│ │ │ │ ├── permissions.go
│ │ │ │ ├── ratelimit.go
│ │ │ │ └── chain.go # Middleware chains
│ │ │ │
│ │ │ └── routes.go # Customer API routes
│ │ │
│ │ └── tenant/ # Tenant-facing API (Port 8081)
│ │ ├── handlers/
│ │ │ ├── tenant_handler.go
│ │ │ ├── user_admin_handler.go
│ │ │ ├── role_admin_handler.go
│ │ │ ├── token_handler.go
│ │ │ ├── message_admin_handler.go
│ │ │ ├── dashboard_handler.go
│ │ │ └── common.go # Shared response helpers
│ │ │
│ │ ├── middleware/
│ │ │ ├── tenant_auth.go
│ │ │ ├── ratelimit.go
│ │ │ └── chain.go
│ │ │
│ │ └── routes.go # Tenant API routes
│ │
│ ├── bootstrap/ # Application initialization
│ │ ├── app.go # Main app bootstrap
│ │ ├── database.go # Database setup & migrations
│ │ ├── cache.go # Redis setup
│ │ ├── queue.go # RabbitMQ setup
│ │ ├── server.go # HTTP servers setup
│ │ └── dependencies.go # Dependency injection
│ │
│ └── pkg/ # Internal shared packages
│ │
│ ├── cache/ # Cache utilities
│ │ ├── cache.go
│ │ └── redis.go
│ │
│ ├── queue/ # Message queue utilities
│ │ ├── queue.go
│ │ ├── consumer.go
│ │ └── producer.go
│ │
│ ├── mailer/ # Email service
│ │ ├── mailer.go
│ │ └── smtp.go
│ │
│ ├── logger/ # Logging utilities
│ │ └── logger.go
│ │
│ ├── validator/ # Validation utilities
│ │ └── validator.go
│ │
│ ├── crypto/ # Cryptography utilities
│ │ ├── hash.go
│ │ └── jwt.go
│ │
│ └── pagination/ # Pagination utilities
│ ├── pagination.go
│ └── response.go
├── config/ # Configuration files
│ ├── permissions/ # Role permission JSON files
│ │ ├── admin.json
│ │ ├── user.json
│ │ ├── moderator.json
│ │ └── guest.json
│ │
│ └── database/ # Database migrations
│ └── migrations/
│ ├── 001_create_users_table.sql
│ ├── 002_create_roles_table.sql
│ └── ...
├── scripts/ # Utility scripts
│ ├── migrate.sh # Run database migrations
│ ├── seed.sh # Seed initial data
│ └── test.sh # Run tests
├── test/ # Tests
│ ├── integration/
│ │ ├── customer_api_test.go
│ │ ├── tenant_api_test.go
│ │ └── fixtures/
│ │ └── test_data.sql
│ │
│ └── unit/
│ ├── service/
│ │ └── user_service_test.go
│ │
│ └── repository/
│ └── user_repository_test.go
├── docs/ # API documentation
│ ├── swagger/
│ │ ├── docs.go
│ │ ├── swagger.json
│ │ └── swagger.yaml
│ │
│ ├── API_CUSTOMER.md # Customer API docs
│ └── API_TENANT.md # Tenant API docs
├── .env.example # Environment variables template
├── .gitignore
├── Dockerfile # Multi-stage build
├── Makefile # Build automation
├── go.mod
├── go.sum
└── README.md
62 changes: 62 additions & 0 deletions backend/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Makefile

.PHONY: help
help: ## Show this help message
@echo 'Usage: make [target]'
@echo ''
@echo 'Available targets:'
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-20s %s\n", $$1, $$2}'

## Development Commands

compose-build: ## Build Docker images
docker-compose build

compose-with-debug: compose-build ## Start with debug logs
@echo "Starting in the debug mode for container"
@docker compose up

compose-without-app: compose-build ## Start without app container
@echo "Starting in the debug mode for container"
@docker compose up --scale app=0 -d

compose-up: compose-build ## Start all containers in background
@docker compose up -d

compose-stop: ## Stop all containers
@echo "stopping docker compose in background"
@docker compose down

compose-clean: compose-stop ## Stop and remove containers
docker-compose rm -f

compose-build-no-cache: ## Build without cache
docker-compose build --no-cache

## Testing Commands

test-setup: ## Setup test environment (first time only)
@cd test-suite && chmod +x setup.sh && ./setup.sh

test-isolated: ## Run tests with isolated database environment
@cd test-suite && chmod +x run_tests.sh && ./run_tests.sh

test-quick: ## Run tests using existing containers (faster)
@cd test-suite && go test -v -timeout 3m ./...

test-start: ## Start test containers without running tests
@cd test-suite && docker-compose -f test-suite/docker-compose.test.yml up -d

test-stop: ## Stop test containers
@cd test-suite && docker-compose -f test-suite/docker-compose.test.yml down

test-clean: ## Remove test containers and volumes
@cd test-suite && docker-compose -f test-suite/docker-compose.test.yml down -v

test-logs: ## Show test container logs
@cd test-suite && docker-compose -f test-suite/docker-compose.test.yml logs -f

test-status: ## Show test container status
@cd test-suite && docker-compose -f test-suite/docker-compose.test.yml ps

.DEFAULT_GOAL := help
24 changes: 24 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
12 changes: 12 additions & 0 deletions frontend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# React + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
35 changes: 35 additions & 0 deletions frontend/contact.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

<div class="flex justify-center">
<button type="button" data-dui-toggle="modal" data-dui-target="#exampleModalMessage" class="inline-flex items-center justify-center border align-middle select-none font-sans font-medium text-center duration-300 ease-in disabled:opacity-50 disabled:shadow-none disabled:cursor-not-allowed focus:shadow-none text-sm py-2 px-4 shadow-sm hover:shadow-md bg-stone-800 hover:bg-stone-700 relative bg-gradient-to-b from-stone-700 to-stone-800 border-stone-900 text-stone-50 rounded-lg hover:bg-gradient-to-b hover:from-stone-800 hover:to-stone-800 hover:border-stone-900 after:absolute after:inset-0 after:rounded-[inherit] after:box-shadow after:shadow-[inset_0_1px_0px_rgba(255,255,255,0.25),inset_0_-2px_0px_rgba(0,0,0,0.35)] after:pointer-events-none transition antialiased"> Open </button>
<div class="fixed antialiased inset-0 bg-stone-800 bg-opacity-75 flex justify-center items-center opacity-0 pointer-events-none transition-opacity duration-300 ease-out z-[9999]" id="exampleModalMessage" aria-hidden="true">
<div class="bg-white rounded-lg w-9/12 sm:w-7/12 md:w-5/12 lg:w-3/12 scale-95 transition-transform duration-300 ease-out">
<div class="border-b border-stone-200 p-4 flex justify-between items-start">
<div class="flex flex-col">
<h1 class="text-lg text-stone-800 font-semibold">New message to @</h1>
<p class="font-sans text-base text-stone-500">Write the message and then click button.</p>
</div>
<button type="button" data-dui-dismiss="modal" aria-label="Close" class="text-stone-500 hover:text-stone-800">&times;</button>
</div>
<form action="#">
<div class="p-4 text-stone-500">
<div class="mb-4 space-y-1.5">
<label for="username" class="font-sans text-sm text-stone-800 dark:text-white font-semibold mb-2">Username</label>
<div class="relative w-full">
<input placeholder="Username" type="text" class="w-full aria-disabled:cursor-not-allowed outline-none focus:outline-none text-stone-800 dark:text-white placeholder:text-stone-600/60 ring-transparent border border-stone-200 transition-all ease-in disabled:opacity-50 disabled:pointer-events-none select-none text-sm py-2 px-2.5 ring shadow-sm bg-white rounded-lg duration-100 hover:border-stone-300 hover:ring-none focus:border-stone-400 focus:ring-none peer" />
</div>
</div>
<div class="space-y-1.5">
<label for="message" class="font-sans text-sm text-stone-800 dark:text-white font-semibold mb-2">Message</label>
<div class="relative w-full">
<textarea rows="8" placeholder="Your message..." class="w-full aria-disabled:cursor-not-allowed outline-none focus:outline-none text-stone-800 dark:text-white placeholder:text-stone-600/60 ring-transparent border border-stone-200 transition-all ease-in disabled:opacity-50 disabled:pointer-events-none select-none text-sm py-2 px-2.5 ring shadow-sm bg-white rounded-lg duration-100 hover:border-stone-300 hover:ring-none focus:border-stone-400 focus:ring-none peer"></textarea>
</div>
</div>
</div>
<div class="p-4 pt-0 flex justify-between items-center gap-2">
<button type="button" data-dui-dismiss="modal" class="inline-flex items-center justify-center border align-middle select-none font-sans font-medium text-center duration-300 ease-in disabled:opacity-50 disabled:shadow-none disabled:cursor-not-allowed focus:shadow-none text-sm py-2 px-4 shadow-sm hover:shadow-md bg-stone-800 hover:bg-stone-700 relative bg-gradient-to-b from-stone-700 to-stone-800 border-stone-900 text-stone-50 rounded-lg hover:bg-gradient-to-b hover:from-stone-800 hover:to-stone-800 hover:border-stone-900 after:absolute after:inset-0 after:rounded-[inherit] after:box-shadow after:shadow-[inset_0_1px_0px_rgba(255,255,255,0.25),inset_0_-2px_0px_rgba(0,0,0,0.35)] after:pointer-events-none transition antialiased">Cancel</button>
<button type="button" class="inline-flex items-center justify-center border align-middle select-none font-sans font-medium text-center duration-300 ease-in disabled:opacity-50 disabled:shadow-none disabled:cursor-not-allowed focus:shadow-none text-sm py-2 px-4 shadow-sm hover:shadow-md bg-blue-500 hover:bg-info-light relative bg-gradient-to-b from-blue-500 to-blue-600 border-blue-600 text-stone-50 rounded-lg hover:bg-gradient-to-b hover:from-blue-600 hover:to-blue-600 hover:border-blue-600 after:absolute after:inset-0 after:rounded-[inherit] after:box-shadow after:shadow-[inset_0_1px_0px_rgba(255,255,255,0.35),inset_0_-2px_0px_rgba(0,0,0,0.18)] after:pointer-events-none transition antialiased">Send Message</button>
</div>
</form>
</div>
</div>
</div>
29 changes: 29 additions & 0 deletions frontend/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import { defineConfig, globalIgnores } from 'eslint/config'

export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{js,jsx}'],
extends: [
js.configs.recommended,
reactHooks.configs['recommended-latest'],
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
rules: {
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
},
},
])
Loading
Loading