mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 14:52:29 +00:00
refactor(docs/locales): rename project from 'Tуган Як'/'Tugan Yak' to 'Turash' across docs, locales and test fixtures
- Update locales (ru, tt, en) to use 'Turash' and 'Turash AI' - Update metadata, index.html, and pixel-art README - Replace example credentials/emails from @tuganyak.dev -> @turash.dev - Update admin defaults and migration seed to use new admin@turash.dev - Update docs mentioning the old name
This commit is contained in:
parent
624c907a6e
commit
02fad6713c
@ -1,6 +1,7 @@
|
||||
# Admin Panel Concept & Design Specification
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Overview](#overview)
|
||||
2. [Architecture & Navigation](#architecture--navigation)
|
||||
3. [Pages & Functionality](#pages--functionality)
|
||||
@ -13,13 +14,16 @@
|
||||
## Overview
|
||||
|
||||
### Purpose
|
||||
The Admin Panel is a comprehensive management interface for administrators to manage all aspects of the "Tugan Yak" ecosystem, including organizations, content, localizations, users, and system configuration.
|
||||
|
||||
The Admin Panel is a comprehensive management interface for administrators to manage all aspects of the "Turash" ecosystem, including organizations, content, localizations, users, and system configuration.
|
||||
|
||||
### Target Users
|
||||
|
||||
- **Primary**: System Administrators
|
||||
- **Secondary**: Content Managers (with limited permissions)
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Unified Dashboard**: Real-time overview of system health and metrics
|
||||
- **Organization Management**: Full CRUD operations with verification workflow
|
||||
- **Localization Management**: Complete UI and data translation management
|
||||
@ -102,6 +106,7 @@ Admin Panel
|
||||
```
|
||||
|
||||
### Responsive Breakpoints
|
||||
|
||||
- **Desktop**: Full sidebar navigation, multi-column layouts
|
||||
- **Tablet**: Collapsible sidebar, adapted grid layouts
|
||||
- **Mobile**: Bottom navigation bar, single column, stacked cards
|
||||
@ -115,6 +120,7 @@ Admin Panel
|
||||
**Purpose**: Central hub providing overview of system status and key metrics.
|
||||
|
||||
#### Layout
|
||||
|
||||
- **Top Row**: Key Metrics Cards (4 cards)
|
||||
- **Middle Row**: Charts (2 columns)
|
||||
- **Bottom Row**: Recent Activity & Quick Actions
|
||||
@ -122,6 +128,7 @@ Admin Panel
|
||||
#### Components
|
||||
|
||||
**Key Metrics Cards**:
|
||||
|
||||
1. **Total Organizations**
|
||||
- Count with trend indicator (↑/↓ %)
|
||||
- Click to navigate to Organizations list
|
||||
@ -143,6 +150,7 @@ Admin Panel
|
||||
- Color: Warning
|
||||
|
||||
**Charts Section**:
|
||||
|
||||
1. **Economic Connections Graph** (Left, 60% width)
|
||||
- Interactive network visualization
|
||||
- Sector-to-sector connections
|
||||
@ -156,6 +164,7 @@ Admin Panel
|
||||
- Time period selector
|
||||
|
||||
**Recent Activity Feed**:
|
||||
|
||||
- Last 20 system events
|
||||
- Organization verifications
|
||||
- New user registrations
|
||||
@ -164,12 +173,14 @@ Admin Panel
|
||||
- Real-time updates via WebSocket
|
||||
|
||||
**Quick Actions**:
|
||||
|
||||
- Verify pending organizations (with count badge)
|
||||
- Review translation requests
|
||||
- View system alerts
|
||||
- Access help documentation
|
||||
|
||||
#### UX Features
|
||||
|
||||
- **Real-time Updates**: WebSocket connection for live metrics
|
||||
- **Refresh Indicator**: Manual refresh button with last update time
|
||||
- **Export Options**: Download dashboard as PDF/PNG
|
||||
@ -187,6 +198,7 @@ Admin Panel
|
||||
##### 2.1 Organization List (`/admin/organizations`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Advanced Search**:
|
||||
- Full-text search (name, description, sector)
|
||||
- Filter by: Sector, Type, Verification Status, Date Range
|
||||
@ -214,6 +226,7 @@ Admin Panel
|
||||
- Duplicate
|
||||
|
||||
**UX Features**:
|
||||
|
||||
- **Inline Editing**: Quick edit for name, sector (with autocomplete)
|
||||
- **Keyboard Shortcuts**:
|
||||
- `Ctrl+F`: Focus search
|
||||
@ -227,6 +240,7 @@ Admin Panel
|
||||
**Layout**: Multi-step wizard or single-page form (configurable)
|
||||
|
||||
**Sections**:
|
||||
|
||||
1. **Basic Information**
|
||||
- Name (required, with translation fields)
|
||||
- Sector (dropdown with search)
|
||||
@ -263,6 +277,7 @@ Admin Panel
|
||||
- Custom fields
|
||||
|
||||
**UX Features**:
|
||||
|
||||
- **Auto-save**: Draft saved every 30 seconds
|
||||
- **Validation**: Real-time field validation
|
||||
- **Translation Tabs**: Switch between locales (ru, en, tt)
|
||||
@ -275,6 +290,7 @@ Admin Panel
|
||||
**Purpose**: Dedicated interface for reviewing and verifying organizations.
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Queue List**: Organizations pending verification
|
||||
- **Priority Sorting**: By date, user requests, flags
|
||||
- **Quick Actions**: Approve, Reject, Request More Info
|
||||
@ -288,6 +304,7 @@ Admin Panel
|
||||
- **Statistics**: Verification rate, average time
|
||||
|
||||
**UX Features**:
|
||||
|
||||
- **Side-by-side View**: Compare with similar verified organizations
|
||||
- **Keyboard Navigation**: Arrow keys to navigate queue
|
||||
- **Bulk Approve**: Select and approve multiple
|
||||
@ -306,12 +323,14 @@ Admin Panel
|
||||
**Purpose**: Manage all frontend UI text translations.
|
||||
|
||||
**Layout**:
|
||||
|
||||
- **Left Panel**: Translation keys tree (grouped by namespace)
|
||||
- **Right Panel**: Translation editor for selected key
|
||||
|
||||
**Features**:
|
||||
|
||||
**Translation Key Tree**:
|
||||
|
||||
- Hierarchical structure matching frontend structure
|
||||
- `common.*`
|
||||
- `adminPage.*`
|
||||
@ -324,6 +343,7 @@ Admin Panel
|
||||
- Show untranslated keys (red indicator)
|
||||
|
||||
**Translation Editor**:
|
||||
|
||||
- **Key Path**: Full path display (e.g., `adminPage.title`)
|
||||
- **Source Locale** (Russian): Read-only, serves as reference
|
||||
- **Target Locales**: Editable fields for each locale (en, tt)
|
||||
@ -343,6 +363,7 @@ Admin Panel
|
||||
- Word count
|
||||
|
||||
**Bulk Operations**:
|
||||
|
||||
- **Bulk Edit**: Edit multiple keys at once
|
||||
- **Auto-translate**: Translate missing keys using AI/ML
|
||||
- **Import/Export**:
|
||||
@ -353,6 +374,7 @@ Admin Panel
|
||||
- **Copy from Locale**: Copy translations from another locale
|
||||
|
||||
**Translation Tools**:
|
||||
|
||||
- **Translation Memory**: Suggest similar translations
|
||||
- **Spell Check**: Per locale
|
||||
- **Placeholder Validation**: Ensure placeholders match (e.g., `{{name}}`)
|
||||
@ -360,6 +382,7 @@ Admin Panel
|
||||
- **Context Preview**: Show where translation is used in UI
|
||||
|
||||
**UX Features**:
|
||||
|
||||
- **Live Preview**: See translation in context
|
||||
- **Keyboard Shortcuts**:
|
||||
- `Ctrl+S`: Save
|
||||
@ -377,6 +400,7 @@ Admin Panel
|
||||
**Purpose**: Manage translations for dynamic content (organizations, sites, heritage buildings, etc.).
|
||||
|
||||
**Layout**:
|
||||
|
||||
- **Entity Type Selector**: Organizations, Sites, Heritage, etc.
|
||||
- **Entity List**: Searchable, filterable list
|
||||
- **Translation Editor**: Similar to UI translations but entity-specific
|
||||
@ -384,11 +408,13 @@ Admin Panel
|
||||
**Features**:
|
||||
|
||||
**Entity Selection**:
|
||||
|
||||
- Dropdown or tabs for entity types
|
||||
- Search entities by name/ID
|
||||
- Filter by translation status
|
||||
|
||||
**Entity Translation View**:
|
||||
|
||||
- **Entity Info**: Name, ID, source locale values
|
||||
- **Translatable Fields**:
|
||||
- Name
|
||||
@ -400,6 +426,7 @@ Admin Panel
|
||||
- **Copy Entity**: Copy translations from similar entity
|
||||
|
||||
**Translation Workflow**:
|
||||
|
||||
1. Select entity type
|
||||
2. Search/filter entities
|
||||
3. Select entity
|
||||
@ -408,6 +435,7 @@ Admin Panel
|
||||
6. Save with review status
|
||||
|
||||
**Advanced Features**:
|
||||
|
||||
- **Translation Suggestions**: AI-powered suggestions based on similar entities
|
||||
- **Bulk Operations**:
|
||||
- Translate all missing for entity type
|
||||
@ -419,6 +447,7 @@ Admin Panel
|
||||
- Missing translations count
|
||||
|
||||
**UX Features**:
|
||||
|
||||
- **Side-by-side Comparison**: Source vs. translations
|
||||
- **Entity Preview**: See how entity appears in different locales
|
||||
- **Translation Queue**: List of entities needing translation
|
||||
@ -438,6 +467,7 @@ Admin Panel
|
||||
##### 4.1 Static Pages (`/admin/content/pages`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Page List**:
|
||||
- About, Contact, Privacy, Terms, etc.
|
||||
- Custom pages
|
||||
@ -467,6 +497,7 @@ Admin Panel
|
||||
##### 4.2 Announcements (`/admin/content/announcements`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Announcement List**:
|
||||
- Title, Status, Date, Priority
|
||||
- Filter by status, date range
|
||||
@ -483,6 +514,7 @@ Admin Panel
|
||||
##### 4.3 Media Library (`/admin/content/media`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Media Grid View**:
|
||||
- Thumbnails with overlay info
|
||||
- Filter by type (Image, Video, Document)
|
||||
@ -518,6 +550,7 @@ Admin Panel
|
||||
##### 5.1 User List (`/admin/users`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **User Table**:
|
||||
- Columns: Avatar, Name, Email, Role, Status, Last Login, Actions
|
||||
- Sortable, filterable
|
||||
@ -535,6 +568,7 @@ Admin Panel
|
||||
##### 5.2 User Editor (`/admin/users/new`, `/admin/users/:id/edit`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Basic Information**:
|
||||
- Name
|
||||
- Email (unique validation)
|
||||
@ -558,6 +592,7 @@ Admin Panel
|
||||
##### 5.3 Activity Log (`/admin/users/activity`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Activity Feed**:
|
||||
- User actions (login, create org, edit, etc.)
|
||||
- Timestamp
|
||||
@ -581,6 +616,7 @@ Admin Panel
|
||||
##### 6.1 Overview (`/admin/analytics`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Key Metrics Dashboard**:
|
||||
- Total users
|
||||
- Active users (last 30 days)
|
||||
@ -597,6 +633,7 @@ Admin Panel
|
||||
##### 6.2 Organization Analytics (`/admin/analytics/organizations`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Sector Distribution**: Pie/bar chart
|
||||
- **Verification Rate**: Over time
|
||||
- **Top Sectors**: By count, by connections
|
||||
@ -606,6 +643,7 @@ Admin Panel
|
||||
##### 6.3 User Activity (`/admin/analytics/users`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **User Engagement**:
|
||||
- Daily/Monthly active users
|
||||
- Session duration
|
||||
@ -617,6 +655,7 @@ Admin Panel
|
||||
##### 6.4 Matching Statistics (`/admin/analytics/matching`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Match Success Rate**: Over time
|
||||
- **Top Matched Sectors**: Which sectors match most
|
||||
- **Proposal Statistics**: Sent, accepted, rejected
|
||||
@ -625,6 +664,7 @@ Admin Panel
|
||||
##### 6.5 Reports (`/admin/analytics/reports`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Report Templates**:
|
||||
- Monthly summary
|
||||
- User activity report
|
||||
@ -645,6 +685,7 @@ Admin Panel
|
||||
##### 7.1 General Settings (`/admin/settings/general`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Site Information**:
|
||||
- Site name
|
||||
- Site description
|
||||
@ -662,6 +703,7 @@ Admin Panel
|
||||
##### 7.2 Localization Settings (`/admin/settings/localization`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Supported Locales**:
|
||||
- Enable/disable locales
|
||||
- Default locale
|
||||
@ -679,6 +721,7 @@ Admin Panel
|
||||
##### 7.3 Integrations (`/admin/settings/integrations`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **API Keys**:
|
||||
- External services
|
||||
- API key management
|
||||
@ -695,6 +738,7 @@ Admin Panel
|
||||
##### 7.4 Email Templates (`/admin/settings/email`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Template List**:
|
||||
- Welcome email
|
||||
- Verification email
|
||||
@ -711,6 +755,7 @@ Admin Panel
|
||||
##### 7.5 System Maintenance (`/admin/settings/maintenance`)
|
||||
|
||||
**Features**:
|
||||
|
||||
- **Maintenance Mode**:
|
||||
- Enable/disable
|
||||
- Custom message
|
||||
@ -738,12 +783,14 @@ Admin Panel
|
||||
## UX Design Principles
|
||||
|
||||
### 1. Consistency
|
||||
|
||||
- **Design System**: Use consistent components, colors, typography
|
||||
- **Navigation**: Predictable navigation patterns
|
||||
- **Terminology**: Consistent language throughout
|
||||
- **Icons**: Standardized icon set with clear meanings
|
||||
|
||||
### 2. Efficiency
|
||||
|
||||
- **Keyboard Shortcuts**: Power users can work faster
|
||||
- **Bulk Operations**: Perform actions on multiple items
|
||||
- **Quick Actions**: Common actions easily accessible
|
||||
@ -751,6 +798,7 @@ Admin Panel
|
||||
- **Undo/Redo**: Allow mistake correction
|
||||
|
||||
### 3. Feedback
|
||||
|
||||
- **Loading States**: Clear indicators for async operations
|
||||
- **Success Messages**: Confirm successful actions
|
||||
- **Error Messages**: Clear, actionable error messages
|
||||
@ -758,6 +806,7 @@ Admin Panel
|
||||
- **Notifications**: Non-intrusive notifications system
|
||||
|
||||
### 4. Accessibility
|
||||
|
||||
- **WCAG 2.1 AA Compliance**: Meet accessibility standards
|
||||
- **Keyboard Navigation**: Full functionality via keyboard
|
||||
- **Screen Reader Support**: Proper ARIA labels
|
||||
@ -765,12 +814,14 @@ Admin Panel
|
||||
- **Focus Indicators**: Clear focus states
|
||||
|
||||
### 5. Responsiveness
|
||||
|
||||
- **Mobile-First**: Works on all screen sizes
|
||||
- **Touch-Friendly**: Adequate touch targets (44x44px minimum)
|
||||
- **Adaptive Layouts**: Layouts adapt to screen size
|
||||
- **Performance**: Fast loading, smooth interactions
|
||||
|
||||
### 6. Discoverability
|
||||
|
||||
- **Breadcrumbs**: Show current location
|
||||
- **Search**: Global search for quick access
|
||||
- **Tooltips**: Helpful hints on hover
|
||||
@ -778,6 +829,7 @@ Admin Panel
|
||||
- **Onboarding**: Guided tour for new admins
|
||||
|
||||
### 7. Error Prevention
|
||||
|
||||
- **Validation**: Real-time field validation
|
||||
- **Confirmations**: For destructive actions
|
||||
- **Draft Saving**: Auto-save to prevent data loss
|
||||
@ -785,6 +837,7 @@ Admin Panel
|
||||
- **Clear Labels**: Unambiguous field labels
|
||||
|
||||
### 8. Performance
|
||||
|
||||
- **Lazy Loading**: Load content as needed
|
||||
- **Pagination**: Efficient data loading
|
||||
- **Optimistic Updates**: Immediate UI feedback
|
||||
@ -798,6 +851,7 @@ Admin Panel
|
||||
### Frontend Architecture
|
||||
|
||||
**Technology Stack**:
|
||||
|
||||
- **Framework**: React 18+ with TypeScript
|
||||
- **Routing**: React Router v6
|
||||
- **State Management**: React Query for server state, Zustand for client state
|
||||
@ -809,6 +863,7 @@ Admin Panel
|
||||
- **Rich Text**: Tiptap or similar
|
||||
|
||||
**Component Structure**:
|
||||
|
||||
```
|
||||
components/
|
||||
admin/
|
||||
@ -849,6 +904,7 @@ components/
|
||||
```
|
||||
|
||||
**Routing Structure**:
|
||||
|
||||
```typescript
|
||||
/admin
|
||||
/dashboard
|
||||
@ -883,6 +939,7 @@ components/
|
||||
### Backend Architecture
|
||||
|
||||
**API Endpoints Structure**:
|
||||
|
||||
```
|
||||
/api/v1/admin/
|
||||
/organizations
|
||||
@ -951,6 +1008,7 @@ components/
|
||||
```
|
||||
|
||||
**Middleware**:
|
||||
|
||||
- Authentication required for all admin routes
|
||||
- Role check: Must be `admin` role
|
||||
- Rate limiting for admin endpoints
|
||||
@ -961,23 +1019,27 @@ components/
|
||||
## API Requirements
|
||||
|
||||
### Authentication & Authorization
|
||||
|
||||
- All admin endpoints require JWT authentication
|
||||
- Role-based access: Only users with `admin` role
|
||||
- Audit logging for all admin actions
|
||||
|
||||
### Response Formats
|
||||
|
||||
- Consistent JSON response structure
|
||||
- Error responses with proper HTTP status codes
|
||||
- Pagination for list endpoints
|
||||
- Filtering and sorting support
|
||||
|
||||
### Performance
|
||||
|
||||
- Pagination: Default 25 items, max 100
|
||||
- Caching: Cache frequently accessed data
|
||||
- Rate limiting: Prevent abuse
|
||||
- Bulk operations: Support batch processing
|
||||
|
||||
### Data Validation
|
||||
|
||||
- Input validation on all endpoints
|
||||
- Type checking
|
||||
- Business rule validation
|
||||
@ -988,30 +1050,35 @@ components/
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Foundation (Week 1-2)
|
||||
|
||||
- Admin layout and navigation
|
||||
- Dashboard with basic metrics
|
||||
- Organization management (enhance existing)
|
||||
- User management basics
|
||||
|
||||
### Phase 2: Localization (Week 3-4)
|
||||
|
||||
- UI translation management
|
||||
- Data translation management
|
||||
- Translation tools and bulk operations
|
||||
- Import/export functionality
|
||||
|
||||
### Phase 3: Content Management (Week 5-6)
|
||||
|
||||
- Static page management
|
||||
- Announcement system
|
||||
- Media library
|
||||
- Rich text editing
|
||||
|
||||
### Phase 4: Analytics (Week 7-8)
|
||||
|
||||
- Analytics dashboard
|
||||
- Charts and visualizations
|
||||
- Reporting system
|
||||
- Export functionality
|
||||
|
||||
### Phase 5: Settings & Polish (Week 9-10)
|
||||
|
||||
- System settings
|
||||
- Integration management
|
||||
- Email templates
|
||||
@ -1024,17 +1091,20 @@ components/
|
||||
## Success Metrics
|
||||
|
||||
### Usability
|
||||
|
||||
- Task completion rate > 90%
|
||||
- Average time to complete common tasks
|
||||
- User satisfaction score
|
||||
- Error rate < 5%
|
||||
|
||||
### Performance
|
||||
|
||||
- Page load time < 2 seconds
|
||||
- API response time < 500ms (p95)
|
||||
- Zero critical bugs in production
|
||||
|
||||
### Adoption
|
||||
|
||||
- Admin user engagement
|
||||
- Feature usage statistics
|
||||
- Support ticket reduction
|
||||
@ -1059,7 +1129,6 @@ components/
|
||||
|
||||
## Conclusion
|
||||
|
||||
This admin panel concept provides a comprehensive, user-friendly interface for managing all aspects of the "Tugan Yak" ecosystem. The design prioritizes efficiency, usability, and maintainability while providing powerful features for content and localization management.
|
||||
This admin panel concept provides a comprehensive, user-friendly interface for managing all aspects of the "Turash" ecosystem. The design prioritizes efficiency, usability, and maintainability while providing powerful features for content and localization management.
|
||||
|
||||
The phased implementation approach allows for iterative development and early value delivery, while the modular architecture ensures scalability and extensibility for future needs.
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# Community Features Proposal: Making Turash/Tugan Yak a Daily-Use Tool
|
||||
# Community Features Proposal: Making Turash a Daily-Use Tool
|
||||
|
||||
## Executive Summary
|
||||
|
||||
@ -9,6 +9,7 @@ This document proposes community-focused features and services that will transfo
|
||||
## Current State Analysis
|
||||
|
||||
### Existing Features
|
||||
|
||||
- ✅ Business/Organization registration and profiles
|
||||
- ✅ Resource matching engine (heat, water, waste, by-products)
|
||||
- ✅ Interactive map view with organizations
|
||||
@ -17,6 +18,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- ✅ Basic public pages (About, Contact, Privacy)
|
||||
|
||||
### Gaps for Community Engagement
|
||||
|
||||
- ❌ No citizen/community member features
|
||||
- ❌ Limited public engagement beyond business matching
|
||||
- ❌ No regular-use features for non-business users
|
||||
@ -32,6 +34,7 @@ This document proposes community-focused features and services that will transfo
|
||||
**Purpose**: Show citizens the environmental and economic impact of industrial symbiosis in their city.
|
||||
|
||||
#### Features:
|
||||
|
||||
- **Real-time Impact Metrics**
|
||||
- Total CO₂ saved (tonnes)
|
||||
- Total waste diverted from landfills (tonnes)
|
||||
@ -59,6 +62,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- "This Month's Top Connection" feature
|
||||
|
||||
**Why This Works**:
|
||||
|
||||
- Creates transparency and trust
|
||||
- Citizens can see tangible environmental benefits
|
||||
- Encourages businesses to participate (social proof)
|
||||
@ -71,6 +75,7 @@ This document proposes community-focused features and services that will transfo
|
||||
**Purpose**: Extend resource sharing beyond businesses to include community members, creating a circular economy marketplace.
|
||||
|
||||
#### Features:
|
||||
|
||||
- **Community Resource Exchange**
|
||||
- Citizens can list: surplus materials, tools, equipment, food
|
||||
- Categories: Tools, Furniture, Electronics, Building Materials, Food, Textiles
|
||||
@ -96,6 +101,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- Integration with local food banks
|
||||
|
||||
**Why This Works**:
|
||||
|
||||
- Daily-use feature for citizens
|
||||
- Reduces waste, supports circular economy
|
||||
- Builds community connections
|
||||
@ -108,6 +114,7 @@ This document proposes community-focused features and services that will transfo
|
||||
**Purpose**: Become the go-to source for local sustainability and business news.
|
||||
|
||||
#### Features:
|
||||
|
||||
- **Sustainability News Feed**
|
||||
- Local environmental news
|
||||
- Business sustainability initiatives
|
||||
@ -135,6 +142,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- Downloadable PDF reports
|
||||
|
||||
**Why This Works**:
|
||||
|
||||
- Regular content updates drive daily visits
|
||||
- Positions platform as community information hub
|
||||
- Increases SEO and discoverability
|
||||
@ -147,6 +155,7 @@ This document proposes community-focused features and services that will transfo
|
||||
**Purpose**: Engage citizens in data collection and environmental monitoring.
|
||||
|
||||
#### Features:
|
||||
|
||||
- **Air Quality Reporting**
|
||||
- Citizens can report air quality observations
|
||||
- Integration with official air quality sensors (if available)
|
||||
@ -178,6 +187,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- Integration with city environmental department
|
||||
|
||||
**Why This Works**:
|
||||
|
||||
- Engages environmentally conscious citizens
|
||||
- Creates valuable data for city planning
|
||||
- Regular participation opportunities
|
||||
@ -190,6 +200,7 @@ This document proposes community-focused features and services that will transfo
|
||||
**Purpose**: Create spaces for community dialogue about sustainability and local issues.
|
||||
|
||||
#### Features:
|
||||
|
||||
- **Sustainability Discussion Forums**
|
||||
- Topics: Circular economy, waste reduction, energy efficiency
|
||||
- Business-citizen dialogue
|
||||
@ -215,6 +226,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- Community-contributed content
|
||||
|
||||
**Why This Works**:
|
||||
|
||||
- Builds community around platform
|
||||
- Increases time spent on platform
|
||||
- Creates valuable content archive
|
||||
@ -227,6 +239,7 @@ This document proposes community-focused features and services that will transfo
|
||||
**Purpose**: Educate community about circular economy, sustainability, and industrial symbiosis.
|
||||
|
||||
#### Features:
|
||||
|
||||
- **Interactive Learning Modules**
|
||||
- "What is Industrial Symbiosis?" (animated explainer)
|
||||
- "How Circular Economy Works" (interactive diagrams)
|
||||
@ -258,6 +271,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- Interactive games and quizzes
|
||||
|
||||
**Why This Works**:
|
||||
|
||||
- Positions platform as educational resource
|
||||
- Increases time on site
|
||||
- Builds long-term engagement
|
||||
@ -270,6 +284,7 @@ This document proposes community-focused features and services that will transfo
|
||||
**Purpose**: Motivate participation through challenges, competitions, and rewards.
|
||||
|
||||
#### Features:
|
||||
|
||||
- **Monthly Sustainability Challenges**
|
||||
- "Zero Waste Week"
|
||||
- "Energy Saving Month"
|
||||
@ -301,6 +316,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- Community groups
|
||||
|
||||
**Why This Works**:
|
||||
|
||||
- Increases engagement and retention
|
||||
- Creates social motivation
|
||||
- Encourages regular participation
|
||||
@ -313,6 +329,7 @@ This document proposes community-focused features and services that will transfo
|
||||
**Purpose**: Support local economy while promoting sustainability.
|
||||
|
||||
#### Features:
|
||||
|
||||
- **Sustainable Business Directory**
|
||||
- All businesses on platform (with sustainability badges)
|
||||
- Filter by: sustainability practices, certifications, resource types
|
||||
@ -338,6 +355,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- Feedback and suggestions
|
||||
|
||||
**Why This Works**:
|
||||
|
||||
- Supports local economy
|
||||
- Creates value for businesses beyond matching
|
||||
- Increases business participation
|
||||
@ -350,6 +368,7 @@ This document proposes community-focused features and services that will transfo
|
||||
**Purpose**: Facilitate community organizing and volunteer coordination.
|
||||
|
||||
#### Features:
|
||||
|
||||
- **Volunteer Opportunities Board**
|
||||
- Environmental cleanup events
|
||||
- Community garden projects
|
||||
@ -375,6 +394,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- Mentorship programs
|
||||
|
||||
**Why This Works**:
|
||||
|
||||
- Builds active community
|
||||
- Creates offline engagement
|
||||
- Strengthens platform value
|
||||
@ -387,6 +407,7 @@ This document proposes community-focused features and services that will transfo
|
||||
**Purpose**: Enable on-the-go access and location-based features.
|
||||
|
||||
#### Features:
|
||||
|
||||
- **Push Notifications**
|
||||
- New matches for your business
|
||||
- Community events nearby
|
||||
@ -411,6 +432,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- Sync when online
|
||||
|
||||
**Why This Works**:
|
||||
|
||||
- Increases accessibility
|
||||
- Enables real-time engagement
|
||||
- Location-based features add value
|
||||
@ -421,6 +443,7 @@ This document proposes community-focused features and services that will transfo
|
||||
## Implementation Priority
|
||||
|
||||
### Phase 1: Foundation (Weeks 1-4)
|
||||
|
||||
**Goal**: Add basic community features to drive initial engagement
|
||||
|
||||
1. **Community Impact Dashboard**
|
||||
@ -439,6 +462,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- Contact mechanism
|
||||
|
||||
**Expected Outcome**:
|
||||
|
||||
- 50-100 daily active users (citizens)
|
||||
- 2-3 community resource exchanges per week
|
||||
- Increased time on site
|
||||
@ -446,6 +470,7 @@ This document proposes community-focused features and services that will transfo
|
||||
---
|
||||
|
||||
### Phase 2: Engagement (Weeks 5-8)
|
||||
|
||||
**Goal**: Increase engagement and build community
|
||||
|
||||
4. **Community Forums**
|
||||
@ -464,6 +489,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- Resource guides
|
||||
|
||||
**Expected Outcome**:
|
||||
|
||||
- 200-300 daily active users
|
||||
- Active forum discussions
|
||||
- Regular citizen reports
|
||||
@ -471,6 +497,7 @@ This document proposes community-focused features and services that will transfo
|
||||
---
|
||||
|
||||
### Phase 3: Advanced Features (Weeks 9-12)
|
||||
|
||||
**Goal**: Create comprehensive community platform
|
||||
|
||||
7. **Gamification**
|
||||
@ -489,6 +516,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- Community groups
|
||||
|
||||
**Expected Outcome**:
|
||||
|
||||
- 500+ daily active users
|
||||
- Active community participation
|
||||
- Regular challenges and events
|
||||
@ -496,6 +524,7 @@ This document proposes community-focused features and services that will transfo
|
||||
---
|
||||
|
||||
### Phase 4: Mobile & Advanced (Months 4-6)
|
||||
|
||||
**Goal**: Mobile access and advanced features
|
||||
|
||||
10. **Mobile App**
|
||||
@ -514,6 +543,7 @@ This document proposes community-focused features and services that will transfo
|
||||
- API for external developers
|
||||
|
||||
**Expected Outcome**:
|
||||
|
||||
- 1000+ daily active users
|
||||
- Mobile-first engagement
|
||||
- Platform becomes essential tool
|
||||
@ -639,6 +669,7 @@ CREATE TABLE user_badges (
|
||||
## Success Metrics
|
||||
|
||||
### Engagement Metrics
|
||||
|
||||
- **Daily Active Users (DAU)**: Target 1000+ by month 6
|
||||
- **Monthly Active Users (MAU)**: Target 5000+ by month 6
|
||||
- **Average Session Duration**: Target 5+ minutes
|
||||
@ -646,6 +677,7 @@ CREATE TABLE user_badges (
|
||||
- **Return Visitor Rate**: Target 40%+
|
||||
|
||||
### Community Metrics
|
||||
|
||||
- **Community Resource Listings**: Target 100+ active listings
|
||||
- **Environmental Reports**: Target 50+ reports per month
|
||||
- **Forum Posts**: Target 200+ posts per month
|
||||
@ -653,6 +685,7 @@ CREATE TABLE user_badges (
|
||||
- **Challenge Participants**: Target 200+ participants per challenge
|
||||
|
||||
### Business Impact Metrics
|
||||
|
||||
- **Business Registrations**: Increase by 30% due to community visibility
|
||||
- **Resource Connections**: Increase by 25% due to community engagement
|
||||
- **Business-Citizen Interactions**: Track dialogue and feedback
|
||||
@ -662,10 +695,12 @@ CREATE TABLE user_badges (
|
||||
## Monetization Opportunities
|
||||
|
||||
### Community Features (Free)
|
||||
|
||||
- Basic community features remain free to drive engagement
|
||||
- Creates network effects and platform value
|
||||
|
||||
### Premium Community Features (Optional)
|
||||
|
||||
- **Premium Citizen Accounts**: €5/month
|
||||
- Advanced analytics
|
||||
- Priority support
|
||||
@ -673,6 +708,7 @@ CREATE TABLE user_badges (
|
||||
- Exclusive content
|
||||
|
||||
### Business Opportunities
|
||||
|
||||
- **Sponsored Content**: Businesses can sponsor news articles
|
||||
- **Featured Listings**: Businesses can pay for featured placement
|
||||
- **Event Sponsorship**: Businesses can sponsor community events
|
||||
@ -693,27 +729,35 @@ CREATE TABLE user_badges (
|
||||
## Risks & Mitigations
|
||||
|
||||
### Risk 1: Low Initial Engagement
|
||||
|
||||
**Mitigation**:
|
||||
|
||||
- Start with high-value features (Impact Dashboard, News)
|
||||
- Partner with local organizations for content
|
||||
- Active community management
|
||||
|
||||
### Risk 2: Content Moderation Burden
|
||||
|
||||
**Mitigation**:
|
||||
|
||||
- Automated moderation tools
|
||||
- Community moderators
|
||||
- Clear community guidelines
|
||||
- Reporting mechanisms
|
||||
|
||||
### Risk 3: Feature Bloat
|
||||
|
||||
**Mitigation**:
|
||||
|
||||
- Phased rollout
|
||||
- User feedback loops
|
||||
- Analytics-driven feature prioritization
|
||||
- Regular feature audits
|
||||
|
||||
### Risk 4: Resource Requirements
|
||||
|
||||
**Mitigation**:
|
||||
|
||||
- Start with MVP features
|
||||
- Leverage existing infrastructure
|
||||
- Community-contributed content
|
||||
@ -734,7 +778,7 @@ CREATE TABLE user_badges (
|
||||
|
||||
## Conclusion
|
||||
|
||||
By adding community-focused features, Turash/Tugan Yak can transform from a B2B matching platform into a comprehensive community engagement tool. These features will:
|
||||
By adding community-focused features, Turash can transform from a B2B matching platform into a comprehensive community engagement tool. These features will:
|
||||
|
||||
- **Drive Regular Usage**: Daily-use features keep users coming back
|
||||
- **Build Community**: Forums, events, and challenges create engagement
|
||||
@ -750,4 +794,3 @@ The phased approach allows for iterative development, user feedback, and resourc
|
||||
**Last Updated**: 2025-01-27
|
||||
**Author**: AI Assistant
|
||||
**Status**: Proposal - Awaiting Review
|
||||
|
||||
|
||||
@ -145,7 +145,7 @@ curl http://localhost:8080/health
|
||||
# Login (if authentication enabled)
|
||||
curl -X POST http://localhost:8080/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"admin@tuganyak.dev","password":"admin"}'
|
||||
-d '{"email":"admin@turash.dev","password":"admin"}'
|
||||
|
||||
# List businesses
|
||||
curl http://localhost:8080/api/organizations
|
||||
|
||||
@ -36,6 +36,7 @@ backend/
|
||||
## Implemented Features
|
||||
|
||||
### ✅ **Enhanced Match Entity with State Management**
|
||||
|
||||
- **Match Lifecycle**: `suggested` → `negotiating` → `reserved` → `contracted` → `live`
|
||||
- **Negotiation History**: Complete audit trail with timestamps, actors, and notes
|
||||
- **Contract Details**: Signed contracts with terms, effective dates, and attachments
|
||||
@ -43,6 +44,7 @@ backend/
|
||||
- **Event Publishing**: Automatic event publishing on match creation/updates
|
||||
|
||||
### ✅ **Sophisticated Matching Engine**
|
||||
|
||||
Multi-stage pipeline with advanced algorithms:
|
||||
|
||||
1. **Pre-filtering**: Geographic (accurate Haversine/Vincenty distances), type, and basic quality filtering
|
||||
@ -54,6 +56,7 @@ Multi-stage pipeline with advanced algorithms:
|
||||
4. **Weighted Scoring**: Multi-criteria ranking with risk penalties
|
||||
|
||||
### ✅ **Advanced Economic Calculator** ⭐ **EXTENDED**
|
||||
|
||||
Comprehensive financial analysis package with advanced features:
|
||||
|
||||
- **NPV/IRR/Payback**: Industry-standard financial metrics with risk-adjusted calculations
|
||||
@ -67,6 +70,7 @@ Comprehensive financial analysis package with advanced features:
|
||||
- **Configuration-Driven**: All parameters configurable via config
|
||||
|
||||
### ✅ **Geospatial Package** ⭐ **NEW**
|
||||
|
||||
Comprehensive toolkit for geographic calculations:
|
||||
|
||||
- **Distance Calculations**: Haversine (fast, accurate) and Vincenty (high precision) formulas
|
||||
@ -82,6 +86,7 @@ Comprehensive toolkit for geographic calculations:
|
||||
**Impact**: Fixed critical bug where distance calculations were hardcoded to 10km. Matching service now uses accurate geographic calculations.
|
||||
|
||||
### ✅ **Event-Driven Architecture**
|
||||
|
||||
Real-time event processing with Redis Streams:
|
||||
|
||||
- **Event Types**: Resource flow, organization, match lifecycle events
|
||||
@ -91,6 +96,7 @@ Real-time event processing with Redis Streams:
|
||||
- **Graceful Degradation**: Continues without Redis/WebSocket if unavailable
|
||||
|
||||
### ✅ **Clean Architecture**
|
||||
|
||||
- **Single Responsibility**: Each service/component has clear boundaries
|
||||
- **Event Integration**: Services publish events, event handlers react asynchronously
|
||||
- **Context Propagation**: User/org ID extraction from request context
|
||||
@ -99,26 +105,31 @@ Real-time event processing with Redis Streams:
|
||||
### ✅ **API Endpoints**
|
||||
|
||||
#### Authentication
|
||||
- `POST /auth/login` - JWT authentication (`admin@tuganyak.dev` / `admin`)
|
||||
|
||||
- `POST /auth/login` - JWT authentication (`admin@turash.dev` / `admin`)
|
||||
|
||||
#### Organizations (Public)
|
||||
|
||||
- `GET /api/organizations` - List all organizations
|
||||
- `GET /api/organizations/:id` - Get organization by ID
|
||||
- `GET /api/organizations/subtype/:subtype` - Filter by subtype
|
||||
- `GET /api/organizations/sector/:sector` - Filter by sector
|
||||
|
||||
#### Sites (Public)
|
||||
|
||||
- `GET /api/sites` - List all sites
|
||||
- `GET /api/sites/:id` - Get site by ID
|
||||
- `GET /api/sites/nearby` - Find sites within radius
|
||||
- `GET /api/sites/organization/:organizationId` - Get sites by organization
|
||||
|
||||
#### Resource Flows (Public)
|
||||
|
||||
- `GET /api/resources/:id` - Get resource flow by ID
|
||||
- `GET /api/resources/site/:siteId` - Get flows by site
|
||||
- `GET /api/resources/organization/:organizationId` - Get flows by organization
|
||||
|
||||
#### Matching Engine ⭐ (Public)
|
||||
|
||||
- `POST /api/matching/query` - Find matches with criteria
|
||||
- `POST /api/matching/create-from-query` - Create match from query result
|
||||
- `GET /api/matching/:matchId` - Get match details
|
||||
@ -126,9 +137,11 @@ Real-time event processing with Redis Streams:
|
||||
- `GET /api/matching/top` - Get top matches
|
||||
|
||||
#### Real-Time Updates
|
||||
|
||||
- `GET /api/ws?org={orgId}&user={userId}` - WebSocket connection for real-time notifications
|
||||
|
||||
#### Protected Endpoints (Require Authentication)
|
||||
|
||||
- `POST /api/organizations` - Create organization
|
||||
- `PUT /api/organizations/:id` - Update organization
|
||||
- `DELETE /api/organizations/:id` - Delete organization
|
||||
@ -313,6 +326,7 @@ ws.onmessage = (event) => {
|
||||
### ✅ **COMPLETED (85% Complete)**
|
||||
|
||||
#### Core Architecture
|
||||
|
||||
- ✅ **Enhanced Match Entity**: State management, negotiation history, contracts
|
||||
- ✅ **Sophisticated Matching Engine**: Multi-stage pipeline, advanced scoring
|
||||
- ✅ **Advanced Economic Calculator**: NPV/IRR/payback, CO₂ quantification
|
||||
@ -321,13 +335,15 @@ ws.onmessage = (event) => {
|
||||
- ✅ **Clean Architecture**: Proper separation, event integration, context propagation
|
||||
|
||||
#### Database & APIs
|
||||
|
||||
- ✅ **PostgreSQL + PostGIS**: Production database with spatial operations
|
||||
- ✅ **GORM ORM**: Type-safe database operations with auto-migrations
|
||||
- ✅ **REST API**: Complete CRUD operations for all entities
|
||||
- ✅ **Real-Time API**: WebSocket endpoint for live match updates
|
||||
- ✅ **Authentication**: JWT-based auth (admin@tuganyak.dev / admin)
|
||||
- ✅ **Authentication**: JWT-based auth (<admin@turash.dev> / admin)
|
||||
|
||||
#### Advanced Features
|
||||
|
||||
- ✅ **Multi-Criteria Scoring**: Technical, economic, temporal, quality factors
|
||||
- ✅ **Risk Assessment**: Technical, regulatory, market, counterparty risks
|
||||
- ✅ **Geographic Filtering**: Haversine distance calculations
|
||||
@ -339,6 +355,7 @@ ws.onmessage = (event) => {
|
||||
## 🔄 **IN PROGRESS (10%)**
|
||||
|
||||
### Advanced Economic Calculator Extensions
|
||||
|
||||
- ✅ **Basic NPV/IRR/Payback**: Implemented and tested
|
||||
- 🔄 **Sensitivity Analysis**: Framework exists, needs completion
|
||||
- 🔄 **Risk Assessment Integration**: Basic structure, needs enhancement
|
||||
@ -349,18 +366,21 @@ ws.onmessage = (event) => {
|
||||
## ⏳ **REMAINING WORK (5%)**
|
||||
|
||||
### Priority 1: Complete Economic Calculator (2 weeks)
|
||||
|
||||
1. **Sensitivity Analysis**: Generate NPV/IRR variations for key parameters
|
||||
2. **Risk-Adjusted Metrics**: Calculate confidence-adjusted economic values
|
||||
3. **CO₂ Impact Breakdown**: Detailed breakdown by transport, process, waste
|
||||
4. **Implementation Complexity**: Technical feasibility scoring
|
||||
|
||||
### Priority 2: Frontend Real-Time Integration (3 weeks)
|
||||
|
||||
1. **WebSocket Client**: React hooks for WebSocket connections
|
||||
2. **Live Match Updates**: Real-time status indicators and notifications
|
||||
3. **Match Negotiation UI**: Interactive negotiation workflow
|
||||
4. **Real-Time Dashboard**: Live economic impact calculations
|
||||
|
||||
### Priority 3: Enhanced Features (2-3 weeks)
|
||||
|
||||
1. **Facilitator Entity**: External consultant marketplace
|
||||
2. **Enhanced Resource Flows**: Detailed quality parameters and certifications
|
||||
3. **Multi-Party Matching**: Complex supply chain optimization
|
||||
@ -371,6 +391,7 @@ ws.onmessage = (event) => {
|
||||
## 🎯 **PRODUCTION READINESS**
|
||||
|
||||
### Current Status: **PRODUCTION READY** 🚀
|
||||
|
||||
- ✅ **Database**: PostgreSQL + PostGIS (spatial operations)
|
||||
- ✅ **Event Processing**: Redis Streams (optional, graceful degradation)
|
||||
- ✅ **Real-Time**: WebSocket service for live updates
|
||||
@ -380,6 +401,7 @@ ws.onmessage = (event) => {
|
||||
- ✅ **Performance**: <500ms match queries, <100ms economic calculations
|
||||
|
||||
### Deployment Ready Features:
|
||||
|
||||
- **Docker Support**: Containerized deployment
|
||||
- **Environment Config**: 12-factor app configuration
|
||||
- **Health Checks**: Service monitoring endpoints
|
||||
@ -401,6 +423,7 @@ ws.onmessage = (event) => {
|
||||
## 🛠 **TECHNICAL STACK**
|
||||
|
||||
### Backend
|
||||
|
||||
- **Go 1.21+**: High-performance, type-safe backend
|
||||
- **Gin**: Fast HTTP web framework
|
||||
- **GORM + PostgreSQL**: ORM with PostGIS spatial extensions
|
||||
@ -409,6 +432,7 @@ ws.onmessage = (event) => {
|
||||
- **JWT**: Secure authentication
|
||||
|
||||
### Architecture Patterns
|
||||
|
||||
- **Clean Architecture**: Domain-driven design with clear boundaries
|
||||
- **Event-Driven**: Asynchronous processing with event sourcing
|
||||
- **CQRS**: Separate read/write concerns (optional Neo4j for reads)
|
||||
@ -476,7 +500,7 @@ go run ./cmd/cli server
|
||||
# Server available at http://localhost:8080
|
||||
```
|
||||
|
||||
**Default Admin**: `admin@tuganyak.dev` / `admin`
|
||||
**Default Admin**: `admin@turash.dev` / `admin`
|
||||
|
||||
## Technical Stack
|
||||
|
||||
@ -533,11 +557,13 @@ The Bugulma City Resource Graph backend is **fully implemented and production-re
|
||||
- ✅ **Scalability**: Optimized queries and caching infrastructure
|
||||
|
||||
### ✅ Completed Production Enhancements (November 2025)
|
||||
|
||||
- **Redis Cache Implementation** - Full distributed caching with Redis SCAN invalidation
|
||||
- **JWT Authentication** - Production-ready JWT with custom claims and org awareness
|
||||
- **Event Context Enhancement** - Complete context extraction for all event publishing
|
||||
|
||||
### Minor Enhancements (Future Sprints)
|
||||
|
||||
- Enhanced analytics metrics (materials/energy/water tracking)
|
||||
- Peer review scoring system
|
||||
- Advanced graph database operations
|
||||
|
||||
@ -187,25 +187,25 @@ func runUserSetup(cmd *cobra.Command, args []string) error {
|
||||
role domain.UserRole
|
||||
}{
|
||||
{
|
||||
email: "admin@tuganyak.dev",
|
||||
email: "admin@turash.dev",
|
||||
name: "Admin User",
|
||||
password: "admin123",
|
||||
role: domain.UserRoleAdmin,
|
||||
},
|
||||
{
|
||||
email: "user@tuganyak.dev",
|
||||
email: "user@turash.dev",
|
||||
name: "Regular User",
|
||||
password: "user123",
|
||||
role: domain.UserRoleUser,
|
||||
},
|
||||
{
|
||||
email: "content@tuganyak.dev",
|
||||
email: "content@turash.dev",
|
||||
name: "Content Manager",
|
||||
password: "content123",
|
||||
role: domain.UserRoleContentManager,
|
||||
},
|
||||
{
|
||||
email: "viewer@tuganyak.dev",
|
||||
email: "viewer@turash.dev",
|
||||
name: "Viewer User",
|
||||
password: "viewer123",
|
||||
role: domain.UserRoleViewer,
|
||||
@ -268,10 +268,10 @@ func runUserSetup(cmd *cobra.Command, args []string) error {
|
||||
if !isQuiet() {
|
||||
fmt.Println("\nAll users setup complete!")
|
||||
fmt.Println("\nLogin credentials:")
|
||||
fmt.Println(" Admin: admin@tuganyak.dev / admin123")
|
||||
fmt.Println(" User: user@tuganyak.dev / user123")
|
||||
fmt.Println(" Content Mgr: content@tuganyak.dev / content123")
|
||||
fmt.Println(" Viewer: viewer@tuganyak.dev / viewer123")
|
||||
fmt.Println(" Admin: admin@turash.dev / admin123")
|
||||
fmt.Println(" User: user@turash.dev / user123")
|
||||
fmt.Println(" Content Mgr: content@turash.dev / content123")
|
||||
fmt.Println(" Viewer: viewer@turash.dev / viewer123")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
539
bugulma/backend/internal/server/server.go
Normal file
539
bugulma/backend/internal/server/server.go
Normal file
@ -0,0 +1,539 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"bugulma/backend/internal/analysis/regulatory"
|
||||
"bugulma/backend/internal/analysis/risk"
|
||||
"bugulma/backend/internal/analysis/transport"
|
||||
"bugulma/backend/internal/domain"
|
||||
"bugulma/backend/internal/financial"
|
||||
"bugulma/backend/internal/geospatial"
|
||||
"bugulma/backend/internal/graph"
|
||||
"bugulma/backend/internal/handler"
|
||||
"bugulma/backend/internal/matching"
|
||||
"bugulma/backend/internal/middleware"
|
||||
"bugulma/backend/internal/repository"
|
||||
"bugulma/backend/internal/routes"
|
||||
"bugulma/backend/internal/service"
|
||||
"bugulma/backend/pkg/config"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// StartServer initializes and starts the Bugulma backend server
|
||||
func StartServer(port string) error {
|
||||
// Load .env file
|
||||
if err := godotenv.Load(); err != nil {
|
||||
log.Printf("Warning: .env file not found, using environment variables")
|
||||
}
|
||||
|
||||
// Load configuration
|
||||
cfg := config.Load()
|
||||
|
||||
// Override port if provided
|
||||
if port != "" {
|
||||
cfg.ServerPort = port
|
||||
}
|
||||
|
||||
// Initialize database
|
||||
db, err := initializeDatabase(cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize database: %w", err)
|
||||
}
|
||||
|
||||
// Initialize repositories
|
||||
userRepo, orgRepo, siteRepo, _, resourceFlowRepo, matchRepo, negotiationHistoryRepo, sharedAssetRepo, proposalRepo, geoFeatureRepo, productRepo, serviceRepo, communityListingRepo, publicTransportRepo := initializeRepositories(db)
|
||||
|
||||
// Seed default data
|
||||
if err := seedDefaultData(userRepo); err != nil {
|
||||
log.Printf("Warning: Failed to seed default data: %v", err)
|
||||
}
|
||||
|
||||
// (Public transport seeding will occur after services are initialized)
|
||||
|
||||
// Initialize graph database (optional)
|
||||
graphSyncService, graphHandler, graphTraversalHandler, orgGraphRepo, siteGraphRepo, addressGraphRepo, flowGraphRepo, matchGraphRepo, sharedAssetGraphRepo := initializeGraphDatabase(cfg)
|
||||
|
||||
// Initialize services
|
||||
orgService, siteService, resourceFlowService, geospatialService, sharedAssetService, analyticsService, authService, matchingSvc, cacheService, websocketService, aiService, proposalService, spatialMatcher, environmentalSvc, facilityOptimizer, economicService, userService, adminService, i18nService, subscriptionService, verificationService, productRepo, serviceRepo, communityListingRepo, publicTransportService := initializeServices(
|
||||
cfg, userRepo, orgRepo, siteRepo, resourceFlowRepo, matchRepo, negotiationHistoryRepo, sharedAssetRepo, proposalRepo, geoFeatureRepo,
|
||||
orgGraphRepo, siteGraphRepo, addressGraphRepo, flowGraphRepo, matchGraphRepo, sharedAssetGraphRepo, db,
|
||||
productRepo, serviceRepo, communityListingRepo,
|
||||
)
|
||||
|
||||
// Store geographical services for future API endpoints
|
||||
_ = spatialMatcher // Will be used in future API handlers
|
||||
_ = environmentalSvc // Will be used in future API handlers
|
||||
_ = facilityOptimizer // Will be used in future API handlers
|
||||
|
||||
// Seed public transport data (if repository and imported files present)
|
||||
if publicTransportRepo != nil && publicTransportService != nil {
|
||||
if err := service.ImportPublicTransportData(context.Background(), publicTransportService, publicTransportRepo); err != nil {
|
||||
log.Printf("Warning: failed to import public transport data: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Set graph repositories on services that need them
|
||||
if orgGraphRepo != nil {
|
||||
orgService.SetGraphRepository(orgGraphRepo)
|
||||
}
|
||||
|
||||
// Initialize GTFS repository and schedule service
|
||||
gtfsRepo := repository.NewPublicTransportGTFSRepository(db)
|
||||
scheduleService := service.NewScheduleService(gtfsRepo, publicTransportRepo)
|
||||
|
||||
// Initialize handlers (orgHandler is created inside initializeHandlers)
|
||||
orgHandler, siteHandler, resourceFlowHandler, proposalHandler, matchingHandler, authHandler, sharedAssetHandler, geospatialHandler, analyticsHandler, aiHandler, heritageHandler, userHandler, orgAdminHandler, i18nHandler, contentHandler, adminHandler, subscriptionHandler, discoveryHandler, publicTransportHandler := initializeHandlers(
|
||||
cfg, orgService, siteService, resourceFlowService, matchingSvc, authService, sharedAssetService, proposalService,
|
||||
geospatialService, analyticsService, aiService, cacheService, db, userService, adminService, i18nService, subscriptionService, verificationService, publicTransportService, scheduleService,
|
||||
)
|
||||
|
||||
// Setup router
|
||||
router := setupRouter(authService)
|
||||
|
||||
// Initialize event-driven matching service with proper dependencies
|
||||
// Note: eventBus is created in initializeServices, but we need to recreate it here for event-driven service
|
||||
eventBus, err := service.NewRedisEventBus("redis://localhost:6379")
|
||||
if err != nil {
|
||||
log.Printf("Warning: Failed to create Redis event bus for event-driven matching: %v", err)
|
||||
eventBus = nil
|
||||
}
|
||||
|
||||
eventDrivenMatchingService := service.NewEventDrivenMatchingService(
|
||||
eventBus, matchingSvc, resourceFlowRepo, matchRepo, websocketService.GetHub(), economicService,
|
||||
)
|
||||
if eventBus != nil {
|
||||
if err := eventDrivenMatchingService.StartEventProcessing(context.Background()); err != nil {
|
||||
log.Printf("Warning: Failed to start event-driven matching: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Setup routes
|
||||
setupRoutes(router, orgHandler, siteHandler, resourceFlowHandler, proposalHandler, matchingHandler, authHandler,
|
||||
sharedAssetHandler, geospatialHandler, analyticsHandler, aiHandler, heritageHandler, graphHandler,
|
||||
graphTraversalHandler, websocketService, orgService, siteService, geospatialService, graphSyncService,
|
||||
userHandler, orgAdminHandler, i18nHandler, contentHandler, adminHandler, subscriptionHandler, authService, discoveryHandler, publicTransportHandler)
|
||||
|
||||
// Start server
|
||||
log.Printf("Server starting on port %s", cfg.ServerPort)
|
||||
if err := router.Run(fmt.Sprintf(":%s", cfg.ServerPort)); err != nil {
|
||||
return fmt.Errorf("failed to start server: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initializeDatabase sets up the database connection and runs migrations
|
||||
func initializeDatabase(cfg *config.Config) (*gorm.DB, error) {
|
||||
dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s",
|
||||
cfg.PostgresHost,
|
||||
cfg.PostgresPort,
|
||||
cfg.PostgresUser,
|
||||
cfg.PostgresPassword,
|
||||
cfg.PostgresDB,
|
||||
cfg.PostgresSSLMode,
|
||||
)
|
||||
|
||||
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to PostgreSQL: %w", err)
|
||||
}
|
||||
|
||||
log.Println("Successfully connected to PostgreSQL database")
|
||||
|
||||
// Run PostGIS-specific migrations FIRST (before AutoMigrate)
|
||||
if err := domain.RunPostGISMigrations(db); err != nil {
|
||||
log.Printf("Warning: Failed to run PostGIS migrations: %v", err)
|
||||
log.Println("Continuing without PostGIS spatial features")
|
||||
} else {
|
||||
log.Println("PostGIS migrations completed successfully")
|
||||
}
|
||||
|
||||
// Run search migrations (pg_trgm extension and indexes)
|
||||
if err := domain.RunSearchMigrations(db); err != nil {
|
||||
log.Printf("Warning: Failed to run search migrations: %v", err)
|
||||
log.Println("Continuing without fuzzy search features")
|
||||
} else {
|
||||
log.Println("Search migrations completed successfully")
|
||||
}
|
||||
|
||||
// Auto-migrate database schema
|
||||
if err := domain.AutoMigrate(db); err != nil {
|
||||
return nil, fmt.Errorf("failed to migrate database: %w", err)
|
||||
}
|
||||
|
||||
// Create additional indexes after AutoMigrate
|
||||
if err := domain.CreateIndexes(db); err != nil {
|
||||
log.Printf("Warning: Failed to create indexes: %v", err)
|
||||
} else {
|
||||
log.Println("Indexes created successfully")
|
||||
}
|
||||
|
||||
log.Println("Database migration completed successfully")
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// initializeRepositories creates all repository instances
|
||||
func initializeRepositories(db *gorm.DB) (domain.UserRepository, domain.OrganizationRepository, domain.SiteRepository, domain.AddressRepository, domain.ResourceFlowRepository, domain.MatchRepository, domain.NegotiationHistoryRepository, domain.SharedAssetRepository, domain.ProposalRepository, domain.GeographicalFeatureRepository, domain.ProductRepository, domain.ServiceRepository, domain.CommunityListingRepository, domain.PublicTransportRepository) {
|
||||
orgRepo := repository.NewOrganizationRepository(db)
|
||||
siteRepo := repository.NewSiteRepository(db)
|
||||
addressRepo := repository.NewAddressRepository(db)
|
||||
resourceFlowRepo := repository.NewResourceFlowRepository(db)
|
||||
matchRepo := repository.NewMatchRepository(db)
|
||||
negotiationHistoryRepo := repository.NewNegotiationHistoryRepository(db)
|
||||
sharedAssetRepo := repository.NewSharedAssetRepository(db)
|
||||
proposalRepo := repository.NewProposalRepository(db)
|
||||
userRepo := repository.NewUserRepository(db)
|
||||
geoFeatureRepo := repository.NewGeographicalFeatureRepository(db)
|
||||
productRepo := repository.NewProductRepository(db)
|
||||
serviceRepo := repository.NewServiceRepository(db)
|
||||
communityListingRepo := repository.NewCommunityListingRepository(db)
|
||||
publicTransportRepo := repository.NewPublicTransportRepository(db)
|
||||
|
||||
_ = repository.NewResourceFlowVersionRepository(db)
|
||||
|
||||
return userRepo, orgRepo, siteRepo, addressRepo, resourceFlowRepo, matchRepo, negotiationHistoryRepo, sharedAssetRepo, proposalRepo, geoFeatureRepo, productRepo, serviceRepo, communityListingRepo, publicTransportRepo
|
||||
}
|
||||
|
||||
// seedDefaultData seeds initial data like admin user
|
||||
func seedDefaultData(userRepo domain.UserRepository) error {
|
||||
_, err := userRepo.GetByEmail(context.Background(), "admin@turash.dev")
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
adminUser := &domain.User{
|
||||
ID: "admin-1",
|
||||
Email: "admin@turash.dev",
|
||||
Name: "Admin User",
|
||||
Password: "$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", // "password" hashed with bcrypt
|
||||
Role: domain.UserRoleAdmin,
|
||||
}
|
||||
|
||||
return userRepo.Create(context.Background(), adminUser)
|
||||
}
|
||||
|
||||
// initializeGraphDatabase initializes Neo4j graph database if enabled
|
||||
func initializeGraphDatabase(cfg *config.Config) (*service.GraphSyncService, *handler.GraphHandler, *handler.GraphTraversalHandler, *repository.GraphOrganizationRepository, *repository.GraphSiteRepository, *repository.GraphAddressRepository, *repository.GraphResourceFlowRepository, *repository.GraphMatchRepository, *repository.GraphSharedAssetRepository) {
|
||||
if !cfg.Neo4jEnabled {
|
||||
return nil, nil, nil, nil, nil, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
neo4jURI := cfg.Neo4jURI
|
||||
if neo4jURI == "" {
|
||||
log.Println("Warning: Neo4j URI not configured, graph database disabled")
|
||||
return nil, nil, nil, nil, nil, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
auth := neo4j.BasicAuth(cfg.Neo4jUsername, cfg.Neo4jPassword, "")
|
||||
driver, err := neo4j.NewDriverWithContext(neo4jURI, auth)
|
||||
if err != nil {
|
||||
log.Printf("Warning: Failed to create Neo4j driver: %v", err)
|
||||
log.Println("Continuing without graph database features")
|
||||
return nil, nil, nil, nil, nil, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// Verify connectivity
|
||||
ctx := context.Background()
|
||||
if err := driver.VerifyConnectivity(ctx); err != nil {
|
||||
log.Printf("Warning: Failed to connect to Neo4j: %v", err)
|
||||
log.Println("Continuing without graph database features")
|
||||
return nil, nil, nil, nil, nil, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
log.Println("Successfully connected to Neo4j graph database")
|
||||
|
||||
// Initialize graph repositories
|
||||
orgGraphRepo := repository.NewGraphOrganizationRepository(driver, cfg.Neo4jDatabase)
|
||||
siteGraphRepo := repository.NewGraphSiteRepository(driver, cfg.Neo4jDatabase)
|
||||
addressGraphRepo := repository.NewGraphAddressRepository(driver, cfg.Neo4jDatabase)
|
||||
flowGraphRepo := repository.NewGraphResourceFlowRepository(driver, cfg.Neo4jDatabase)
|
||||
matchGraphRepo := repository.NewGraphMatchRepository(driver, cfg.Neo4jDatabase)
|
||||
sharedAssetGraphRepo := repository.NewGraphSharedAssetRepository(driver, cfg.Neo4jDatabase)
|
||||
productGraphRepo := repository.NewGraphProductRepository(driver, cfg.Neo4jDatabase)
|
||||
serviceGraphRepo := repository.NewGraphServiceRepository(driver, cfg.Neo4jDatabase)
|
||||
|
||||
// Initialize graph sync service
|
||||
graphSyncService := service.NewGraphSyncService(
|
||||
orgGraphRepo, siteGraphRepo, addressGraphRepo, flowGraphRepo,
|
||||
matchGraphRepo, sharedAssetGraphRepo, productGraphRepo, serviceGraphRepo,
|
||||
)
|
||||
|
||||
// Initialize graph calculator for traversal service
|
||||
graphCalculator := graph.NewCalculatorWithDefaults(driver, cfg.Neo4jDatabase)
|
||||
|
||||
// Initialize services
|
||||
graphTraversalService := service.NewGraphTraversalService(graphCalculator)
|
||||
|
||||
// Initialize handlers
|
||||
graphHandler := handler.NewGraphHandler(driver, cfg.Neo4jDatabase, graphSyncService)
|
||||
graphTraversalHandler := handler.NewGraphTraversalHandler(graphTraversalService)
|
||||
|
||||
return graphSyncService, graphHandler, graphTraversalHandler, orgGraphRepo, siteGraphRepo, addressGraphRepo, flowGraphRepo, matchGraphRepo, sharedAssetGraphRepo
|
||||
}
|
||||
|
||||
// initializeServices creates all service instances
|
||||
func initializeServices(
|
||||
cfg *config.Config,
|
||||
userRepo domain.UserRepository,
|
||||
orgRepo domain.OrganizationRepository,
|
||||
siteRepo domain.SiteRepository,
|
||||
resourceFlowRepo domain.ResourceFlowRepository,
|
||||
matchRepo domain.MatchRepository,
|
||||
negotiationHistoryRepo domain.NegotiationHistoryRepository,
|
||||
sharedAssetRepo domain.SharedAssetRepository,
|
||||
proposalRepo domain.ProposalRepository,
|
||||
geoFeatureRepo domain.GeographicalFeatureRepository,
|
||||
orgGraphRepo *repository.GraphOrganizationRepository,
|
||||
siteGraphRepo *repository.GraphSiteRepository,
|
||||
addressGraphRepo *repository.GraphAddressRepository,
|
||||
flowGraphRepo *repository.GraphResourceFlowRepository,
|
||||
matchGraphRepo *repository.GraphMatchRepository,
|
||||
sharedAssetGraphRepo *repository.GraphSharedAssetRepository,
|
||||
db *gorm.DB,
|
||||
productRepo domain.ProductRepository,
|
||||
serviceRepo domain.ServiceRepository,
|
||||
communityListingRepo domain.CommunityListingRepository,
|
||||
) (*service.OrganizationService, *service.SiteService, *service.ResourceFlowService, *service.GeospatialService, *service.SharedAssetService, *service.AnalyticsService, *service.AuthService, *matching.Service, service.CacheService, *service.WebSocketService, *service.AIService, *service.ProposalService, *service.SpatialResourceMatcher, *service.EnvironmentalImpactService, *service.FacilityLocationOptimizer, *service.EconomicService, *service.UserService, *service.AdminService, *service.I18nService, *service.SubscriptionService, *service.VerificationService, domain.ProductRepository, domain.ServiceRepository, domain.CommunityListingRepository, *service.PublicTransportService) {
|
||||
|
||||
// Create event bus first
|
||||
eventBus, err := service.NewRedisEventBus("redis://localhost:6379")
|
||||
if err != nil {
|
||||
log.Printf("Warning: Failed to create Redis event bus, using in-memory: %v", err)
|
||||
eventBus = nil
|
||||
}
|
||||
|
||||
// Create services
|
||||
orgService := service.NewOrganizationService(orgRepo, nil) // Graph repo set later if available
|
||||
siteService := service.NewSiteService(siteRepo)
|
||||
resourceFlowService := service.NewResourceFlowService(resourceFlowRepo, eventBus)
|
||||
authService := service.NewAuthService(userRepo, cfg.JWTSecret)
|
||||
sharedAssetService := service.NewSharedAssetService(sharedAssetRepo)
|
||||
geospatialService := service.NewGeospatialService(db, geoFeatureRepo)
|
||||
analyticsService := service.NewAnalyticsService(db, orgRepo, siteRepo, resourceFlowRepo, matchRepo, sharedAssetRepo)
|
||||
proposalService := service.NewProposalService(proposalRepo)
|
||||
|
||||
// Initialize geospatial calculator
|
||||
geoCalc := geospatial.NewCalculatorWithDefaults()
|
||||
|
||||
// Initialize geographical transportation service
|
||||
geoTransportSvc := service.NewTransportationService(geoCalc)
|
||||
|
||||
// Initialize geographical services
|
||||
spatialMatcher := service.NewSpatialResourceMatcher(geoFeatureRepo, siteRepo, resourceFlowRepo, geospatialService, geoTransportSvc, geoCalc)
|
||||
environmentalSvc := service.NewEnvironmentalImpactService(geoFeatureRepo, siteRepo, geospatialService, geoCalc)
|
||||
facilityOptimizer := service.NewFacilityLocationOptimizer(geoFeatureRepo, siteRepo, geospatialService, spatialMatcher, environmentalSvc, geoTransportSvc)
|
||||
|
||||
// Create cache and websocket services
|
||||
var cacheService service.CacheService
|
||||
redisCache, err := service.NewRedisCacheService(cfg.RedisURL)
|
||||
if err != nil {
|
||||
log.Printf("Warning: Failed to initialize Redis cache, using in-memory cache: %v", err)
|
||||
cacheService = service.NewMemoryCacheService()
|
||||
} else {
|
||||
log.Println("Successfully initialized Redis cache service")
|
||||
cacheService = redisCache
|
||||
}
|
||||
|
||||
websocketService := service.NewWebSocketService()
|
||||
|
||||
// Create analysis services for matching
|
||||
riskSvc := risk.NewService()
|
||||
transportSvc := transport.NewService()
|
||||
regulatorySvc := regulatory.NewService()
|
||||
|
||||
// Create matching service
|
||||
matchingSvc := matching.NewService(
|
||||
matchRepo, negotiationHistoryRepo, resourceFlowRepo, siteRepo, orgRepo,
|
||||
productRepo, serviceRepo, communityListingRepo,
|
||||
riskSvc, transportSvc, regulatorySvc, eventBus,
|
||||
)
|
||||
|
||||
// Create financial calculator and economic service
|
||||
financialConfig := financial.DefaultConfig()
|
||||
financialCalculator := financial.NewCalculator(financialConfig)
|
||||
economicService := service.NewEconomicService(financialCalculator)
|
||||
|
||||
aiService := service.NewAIService()
|
||||
|
||||
// Create additional services needed by handlers
|
||||
userService := service.NewUserService(userRepo)
|
||||
|
||||
// Create trust service
|
||||
trustRepo := repository.NewTrustMetricsRepository(db)
|
||||
verifiedRepo := repository.NewVerifiedDataRepository(db)
|
||||
historicalRepo := repository.NewHistoricalSuccessRepository(db)
|
||||
trustService := service.NewTrustService(trustRepo, verifiedRepo, historicalRepo)
|
||||
|
||||
// Create i18n service - simplified initialization
|
||||
locRepo := repository.NewLocalizationRepository(db)
|
||||
i18nService := service.NewI18nService(nil, locRepo, nil, nil) // Simplified - can be enhanced later
|
||||
|
||||
// Create subscription service
|
||||
subscriptionRepo := repository.NewSubscriptionRepository(db)
|
||||
// UsageTrackingRepository can be nil for now - create if needed later
|
||||
subscriptionService := service.NewSubscriptionService(subscriptionRepo, nil, userRepo)
|
||||
|
||||
// Create verification service
|
||||
verificationService := service.NewVerificationService(trustService, orgService)
|
||||
|
||||
// Create admin service
|
||||
adminService := service.NewAdminService(orgService, userService, verificationService, i18nService)
|
||||
|
||||
// Initialize public transport service (reads data/bugulma_public_transport_enriched.json if available)
|
||||
publicTransportService, err := service.NewPublicTransportService("data")
|
||||
if err != nil {
|
||||
log.Printf("Warning: failed to initialize public transport service: %v", err)
|
||||
publicTransportService = nil
|
||||
}
|
||||
|
||||
return orgService, siteService, resourceFlowService, geospatialService, sharedAssetService, analyticsService, authService, matchingSvc, cacheService, websocketService, aiService, proposalService, spatialMatcher, environmentalSvc, facilityOptimizer, economicService, userService, adminService, i18nService, subscriptionService, verificationService, productRepo, serviceRepo, communityListingRepo, publicTransportService
|
||||
}
|
||||
|
||||
// initializeHandlers creates all HTTP handler instances
|
||||
func initializeHandlers(
|
||||
cfg *config.Config,
|
||||
orgService *service.OrganizationService,
|
||||
siteService *service.SiteService,
|
||||
resourceFlowService *service.ResourceFlowService,
|
||||
matchingSvc *matching.Service,
|
||||
authService *service.AuthService,
|
||||
sharedAssetService *service.SharedAssetService,
|
||||
proposalService *service.ProposalService,
|
||||
geospatialService *service.GeospatialService,
|
||||
analyticsService *service.AnalyticsService,
|
||||
aiService *service.AIService,
|
||||
cacheService service.CacheService,
|
||||
db *gorm.DB,
|
||||
userService *service.UserService,
|
||||
adminService *service.AdminService,
|
||||
i18nService *service.I18nService,
|
||||
subscriptionService *service.SubscriptionService,
|
||||
verificationService *service.VerificationService,
|
||||
publicTransportService *service.PublicTransportService,
|
||||
scheduleService *service.ScheduleService,
|
||||
) (*handler.OrganizationHandler, *handler.SiteHandler, *handler.ResourceFlowHandler, *handler.ProposalHandler, *handler.MatchingHandler, *handler.AuthHandler, *handler.SharedAssetHandler, *handler.GeospatialHandler, *handler.AnalyticsHandler, *handler.AIHandler, *handler.HeritageHandler, *handler.UserHandler, *handler.OrganizationAdminHandler, *handler.I18nHandler, *handler.ContentHandler, *handler.AdminHandler, *handler.SubscriptionHandler, *handler.DiscoveryHandler, *handler.PublicTransportHandler) {
|
||||
|
||||
imageService := service.NewImageService(cfg)
|
||||
orgHandler := handler.NewOrganizationHandler(orgService, imageService, resourceFlowService, matchingSvc, proposalService)
|
||||
siteHandler := handler.NewSiteHandler(siteService)
|
||||
resourceFlowHandler := handler.NewResourceFlowHandler(resourceFlowService)
|
||||
proposalHandler := handler.NewProposalHandler(proposalService)
|
||||
matchingHandler := handler.NewMatchingHandler(matchingSvc, nil)
|
||||
authHandler := handler.NewAuthHandler(authService)
|
||||
sharedAssetHandler := handler.NewSharedAssetHandler(sharedAssetService)
|
||||
geospatialHandler := handler.NewGeospatialHandler(geospatialService)
|
||||
analyticsHandler := handler.NewAnalyticsHandler(analyticsService)
|
||||
aiHandler := handler.NewAIHandler(aiService)
|
||||
heritageHandler := handler.NewHeritageHandler(repository.NewHeritageRepository(db))
|
||||
|
||||
// Additional handlers
|
||||
userHandler := handler.NewUserHandler(userService)
|
||||
orgAdminHandler := handler.NewOrganizationAdminHandler(orgHandler, verificationService)
|
||||
i18nHandler := handler.NewI18nHandler(i18nService)
|
||||
contentHandler := handler.NewContentHandler(service.NewContentService(
|
||||
repository.NewStaticPageRepository(db),
|
||||
repository.NewAnnouncementRepository(db),
|
||||
repository.NewMediaAssetRepository(db),
|
||||
))
|
||||
adminHandler := handler.NewAdminHandler(adminService)
|
||||
subscriptionHandler := handler.NewSubscriptionHandler(subscriptionService)
|
||||
discoveryHandler := handler.NewDiscoveryHandler(matchingSvc)
|
||||
publicTransportHandler := handler.NewPublicTransportHandler(publicTransportService, scheduleService)
|
||||
|
||||
return orgHandler, siteHandler, resourceFlowHandler, proposalHandler, matchingHandler, authHandler, sharedAssetHandler, geospatialHandler, analyticsHandler, aiHandler, heritageHandler, userHandler, orgAdminHandler, i18nHandler, contentHandler, adminHandler, subscriptionHandler, discoveryHandler, publicTransportHandler
|
||||
}
|
||||
|
||||
// setupRouter configures the Gin router with middleware
|
||||
func setupRouter(authService *service.AuthService) *gin.Engine {
|
||||
router := gin.Default()
|
||||
|
||||
// Serve static files
|
||||
router.Static("/static", "./static")
|
||||
|
||||
// CORS middleware
|
||||
router.Use(func(c *gin.Context) {
|
||||
c.Header("Access-Control-Allow-Origin", "*")
|
||||
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
||||
c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
||||
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
c.AbortWithStatus(204)
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
})
|
||||
|
||||
// Context middleware for extracting user/org info from JWT or headers
|
||||
router.Use(middleware.ContextMiddleware(authService))
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
// setupRoutes configures all API routes using the organized routes package
|
||||
func setupRoutes(
|
||||
router *gin.Engine,
|
||||
orgHandler *handler.OrganizationHandler,
|
||||
siteHandler *handler.SiteHandler,
|
||||
resourceHandler *handler.ResourceFlowHandler,
|
||||
proposalHandler *handler.ProposalHandler,
|
||||
matchingHandler *handler.MatchingHandler,
|
||||
authHandler *handler.AuthHandler,
|
||||
sharedAssetHandler *handler.SharedAssetHandler,
|
||||
geospatialHandler *handler.GeospatialHandler,
|
||||
analyticsHandler *handler.AnalyticsHandler,
|
||||
aiHandler *handler.AIHandler,
|
||||
heritageHandler *handler.HeritageHandler,
|
||||
graphHandler *handler.GraphHandler,
|
||||
graphTraversalHandler *handler.GraphTraversalHandler,
|
||||
websocketService *service.WebSocketService,
|
||||
orgService *service.OrganizationService,
|
||||
siteService *service.SiteService,
|
||||
geospatialService *service.GeospatialService,
|
||||
graphSyncService *service.GraphSyncService,
|
||||
userHandler *handler.UserHandler,
|
||||
orgAdminHandler *handler.OrganizationAdminHandler,
|
||||
i18nHandler *handler.I18nHandler,
|
||||
contentHandler *handler.ContentHandler,
|
||||
adminHandler *handler.AdminHandler,
|
||||
subscriptionHandler *handler.SubscriptionHandler,
|
||||
authService *service.AuthService,
|
||||
discoveryHandler *handler.DiscoveryHandler,
|
||||
publicTransportHandler *handler.PublicTransportHandler,
|
||||
) {
|
||||
routes.RegisterAllRoutes(
|
||||
router,
|
||||
orgHandler,
|
||||
siteHandler,
|
||||
resourceHandler,
|
||||
proposalHandler,
|
||||
matchingHandler,
|
||||
authHandler,
|
||||
sharedAssetHandler,
|
||||
geospatialHandler,
|
||||
analyticsHandler,
|
||||
aiHandler,
|
||||
heritageHandler,
|
||||
graphHandler,
|
||||
graphTraversalHandler,
|
||||
websocketService,
|
||||
userHandler,
|
||||
orgAdminHandler,
|
||||
i18nHandler,
|
||||
contentHandler,
|
||||
adminHandler,
|
||||
subscriptionHandler,
|
||||
authService,
|
||||
discoveryHandler,
|
||||
publicTransportHandler,
|
||||
)
|
||||
}
|
||||
@ -242,7 +242,7 @@ CREATE (s3)-[:HOSTS]->(r3);
|
||||
// Create admin user
|
||||
CREATE (u1:User {
|
||||
id: "user-admin",
|
||||
email: "admin@tuganyak.dev",
|
||||
email: "admin@turash.dev",
|
||||
password_hash: "$2a$10$example.hash.for.demo.purposes.only",
|
||||
role: "admin",
|
||||
created_at: datetime(),
|
||||
|
||||
@ -3,25 +3,29 @@
|
||||
This document contains the login credentials for test users with different roles.
|
||||
|
||||
## Admin User
|
||||
- **Email**: `admin@tuganyak.dev`
|
||||
|
||||
- **Email**: `admin@turash.dev`
|
||||
- **Password**: `admin123`
|
||||
- **Role**: `admin`
|
||||
- **Access**: Full admin panel access
|
||||
|
||||
## Regular User
|
||||
- **Email**: `user@tuganyak.dev`
|
||||
|
||||
- **Email**: `user@turash.dev`
|
||||
- **Password**: `user12345`
|
||||
- **Role**: `user`
|
||||
- **Access**: Regular user dashboard
|
||||
|
||||
## Content Manager
|
||||
- **Email**: `content@tuganyak.dev`
|
||||
|
||||
- **Email**: `content@turash.dev`
|
||||
- **Password**: `content123`
|
||||
- **Role**: `content_manager`
|
||||
- **Access**: Content and localization management
|
||||
|
||||
## Viewer
|
||||
- **Email**: `viewer@tuganyak.dev`
|
||||
|
||||
- **Email**: `viewer@turash.dev`
|
||||
- **Password**: `viewer123`
|
||||
- **Role**: `viewer`
|
||||
- **Access**: Read-only access
|
||||
@ -32,4 +36,3 @@ This document contains the login credentials for test users with different roles
|
||||
- To update a user's role, use the admin API endpoint: `PATCH /api/v1/admin/users/:id/role`
|
||||
- Or update directly in the database: `UPDATE users SET role = 'admin' WHERE email = 'user@example.com';`
|
||||
- After updating a role in the database, the user needs to log out and log back in to refresh their JWT token
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ SELECT id, email, name, role, is_active FROM users;
|
||||
-- Update existing admin user to ensure it has admin role
|
||||
UPDATE users
|
||||
SET role = 'admin', is_active = true
|
||||
WHERE email = 'admin@tuganyak.dev';
|
||||
WHERE email = 'admin@turash.dev';
|
||||
|
||||
-- Create/update users for each role
|
||||
-- Note: These passwords need to be hashed with bcrypt before inserting
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { createContext, ReactNode, useCallback, useContext, useEffect, useState } from 'react';
|
||||
import { login as apiLogin, signup as apiSignup } from '@/lib/api-client';
|
||||
import { createContext, ReactNode, useCallback, useContext, useEffect, useState } from 'react';
|
||||
|
||||
export type UserRole = 'admin' | 'user' | 'content_manager' | 'viewer';
|
||||
|
||||
@ -45,13 +45,13 @@ function extractUserFromToken(token: string): User | null {
|
||||
try {
|
||||
// Only extract basic info for UI - never trust this data for security decisions
|
||||
const payload = JSON.parse(atob(token.split('.')[1]));
|
||||
return {
|
||||
id: payload.sub || payload.id || '1',
|
||||
email: payload.email || 'user@tuganyak.dev',
|
||||
name: payload.name || payload.firstName || 'User',
|
||||
role: (payload.role || 'user') as UserRole,
|
||||
permissions: payload.permissions,
|
||||
};
|
||||
return {
|
||||
id: payload.sub || payload.id || '1',
|
||||
email: payload.email || 'user@turash.dev',
|
||||
name: payload.name || payload.firstName || 'User',
|
||||
role: (payload.role || 'user') as UserRole,
|
||||
permissions: payload.permissions,
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
@ -66,11 +66,12 @@ async function validateTokenServerSide(token: string): Promise<User | null> {
|
||||
// Make an authenticated request to validate the token
|
||||
// Using a lightweight endpoint to check token validity
|
||||
const isProduction = import.meta.env.PROD;
|
||||
const baseUrl = import.meta.env.VITE_API_BASE_URL || (isProduction ? 'https://api.bugulma.city' : '');
|
||||
const baseUrl =
|
||||
import.meta.env.VITE_API_BASE_URL || (isProduction ? 'https://api.bugulma.city' : '');
|
||||
const response = await fetch(`${baseUrl}/api/v1/auth/me`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
// Add timeout to prevent hanging requests
|
||||
|
||||
@ -5,7 +5,7 @@ export const en = {
|
||||
tt: 'TT',
|
||||
},
|
||||
topBar: {
|
||||
title: 'Tugan Yak',
|
||||
title: 'Turash',
|
||||
subTitle: 'Bugulma Ecosystem',
|
||||
loginButton: 'Login',
|
||||
adminButton: 'Admin',
|
||||
@ -283,7 +283,7 @@ export const en = {
|
||||
ctaNote: 'Available only to authorized users.',
|
||||
},
|
||||
footer: {
|
||||
copyright: '© {{year}} Tugan Yak. All rights reserved.',
|
||||
copyright: '© {{year}} Turash. All rights reserved.',
|
||||
links: {
|
||||
about: 'About',
|
||||
contact: 'Contact',
|
||||
@ -324,9 +324,9 @@ export const en = {
|
||||
},
|
||||
},
|
||||
chatbot: {
|
||||
header: 'Tugan Yak AI',
|
||||
header: 'Turash AI',
|
||||
online: 'Online',
|
||||
initialMessage: 'Hello! I am your assistant for the "Tugan Yak" ecosystem. How can I help you?',
|
||||
initialMessage: 'Hello! I am your assistant for the "Turash" ecosystem. How can I help you?',
|
||||
placeholder: 'Ask something...',
|
||||
sendLabel: 'Send',
|
||||
closeLabel: 'Close chat',
|
||||
@ -542,7 +542,7 @@ export const en = {
|
||||
},
|
||||
adminPage: {
|
||||
title: 'Admin Panel',
|
||||
subtitle: 'Overview and management of the "Tugan Yak" ecosystem',
|
||||
subtitle: 'Overview and management of the "Turash" ecosystem',
|
||||
totalOrgs: 'Total Organizations',
|
||||
verifiedOrgs: 'Verified',
|
||||
connections: 'Symbiotic Links',
|
||||
@ -701,10 +701,10 @@ export const en = {
|
||||
},
|
||||
},
|
||||
aboutPage: {
|
||||
p1: 'The "Tugan Yak" project is a digital platform created to visualize and strengthen economic ties within the city of Bugulma.',
|
||||
p1: 'The "Turash" project is a digital platform created to visualize and strengthen economic ties within the city of Bugulma.',
|
||||
p2: 'Our goal is to promote industrial symbiosis, where the waste of one enterprise becomes a raw material for another. This not only reduces costs for businesses but also improves the environmental situation in the region.',
|
||||
p3: 'Using modern technologies, including artificial intelligence, we help companies find new partners, optimize logistics, and discover non-obvious opportunities for cooperation.',
|
||||
p4: 'We believe that a strong local economy is built on strong connections. "Tugan Yak" is our contribution to the prosperity of our native land.',
|
||||
p4: 'We believe that a strong local economy is built on strong connections. "Turash" is our contribution to the prosperity of our native land.',
|
||||
},
|
||||
contactPage: {
|
||||
lead: 'We are always open to suggestions and collaboration. Contact us in any convenient way.',
|
||||
@ -717,7 +717,7 @@ export const en = {
|
||||
email: {
|
||||
title: 'Email',
|
||||
line1: 'For general questions and suggestions',
|
||||
line2: 'info@tuganyak.dev',
|
||||
line2: 'info@turash.dev',
|
||||
},
|
||||
phone: { title: 'Phone', line1: 'Support and consultations', line2: '+7 (855) 941-23-45' },
|
||||
},
|
||||
@ -728,7 +728,7 @@ export const en = {
|
||||
{
|
||||
title: '1. General Provisions',
|
||||
content:
|
||||
'This personal data processing policy has been compiled in accordance with the requirements of the Federal Law of 27.07.2006. No. 152-FZ "On Personal Data" and determines the procedure for processing personal data and measures to ensure the security of personal data undertaken by the "Tugan Yak" project.',
|
||||
'This personal data processing policy has been compiled in accordance with the requirements of the Federal Law of 27.07.2006. No. 152-FZ "On Personal Data" and determines the procedure for processing personal data and measures to ensure the security of personal data undertaken by the "Turash" project.',
|
||||
},
|
||||
{
|
||||
title: '2. Basic concepts used in the Policy',
|
||||
@ -820,7 +820,7 @@ export const en = {
|
||||
instruction: 'Write a narrative paragraph about this landmark.',
|
||||
},
|
||||
chatSystemInstruction:
|
||||
'You are a helpful AI assistant for the "Tugan Yak" platform. Your name is Tugan Yak AI. Your goal is to help users find information about local businesses, services, and cooperation opportunities within the city of Bugulma. If an image is provided, analyze it in the context of the user\'s question. Use the metaphor of a "compass" or "navigator" to guide users. Be concise, friendly, and focus on providing actionable information relevant to the Tugan Yak platform for industrial symbiosis. Format your responses using basic markdown (bolding with ** and unordered lists with *).',
|
||||
'You are a helpful AI assistant for the "Turash" platform. Your name is Turash AI. Your goal is to help users find information about local businesses, services, and cooperation opportunities within the city of Bugulma. If an image is provided, analyze it in the context of the user\'s question. Use the metaphor of a "compass" or "navigator" to guide users. Be concise, friendly, and focus on providing actionable information relevant to the Turash platform for industrial symbiosis. Format your responses using basic markdown (bolding with ** and unordered lists with *).',
|
||||
},
|
||||
validation: {
|
||||
string: {
|
||||
@ -1123,6 +1123,9 @@ export const en = {
|
||||
dashboard: {
|
||||
title: 'Dashboard',
|
||||
subtitle: 'Welcome back, {{name}}!',
|
||||
noRecentActivityTitle: 'No Recent Activity',
|
||||
noRecentActivityDesc:
|
||||
'Recent activity will appear here as organizations interact on the platform',
|
||||
organizations: 'Organizations',
|
||||
sites: 'Sites',
|
||||
resourceFlows: 'Resource Flows',
|
||||
@ -1153,6 +1156,18 @@ export const en = {
|
||||
matchSuccessRate: 'Match Success Rate',
|
||||
avgMatchTime: 'Avg Match Time (days)',
|
||||
activeResourceTypes: 'Active Resource Types',
|
||||
yourContribution: 'Your Contribution',
|
||||
yourContributionDesc: 'Track your impact on the platform',
|
||||
myProposals: 'My Proposals',
|
||||
myPendingProposals: 'Pending Proposals',
|
||||
platformOverview: 'Platform Overview',
|
||||
platformOverviewDesc: 'Key metrics and activities',
|
||||
filterAll: 'All',
|
||||
filterMatches: 'Matches',
|
||||
filterProposals: 'Proposals',
|
||||
filterOrganizations: 'Organizations',
|
||||
noActiveProposalsTitle: 'No Active Proposals',
|
||||
noActiveProposalsDesc: "You don't have any active proposals at the moment",
|
||||
},
|
||||
analyticsDashboard: {
|
||||
title: 'Analytics Dashboard',
|
||||
@ -1254,9 +1269,11 @@ export const en = {
|
||||
addressShortages: 'Address Shortages',
|
||||
shortageRecommendation: 'Focus on increasing supply for high-demand resources with shortages.',
|
||||
optimizeSurplus: 'Optimize Surplus',
|
||||
surplusRecommendation: 'Connect surplus resources with potential users to maximize utilization.',
|
||||
surplusRecommendation:
|
||||
'Connect surplus resources with potential users to maximize utilization.',
|
||||
monitorTrends: 'Monitor Trends',
|
||||
monitoringRecommendation: 'Continue monitoring supply/demand trends to identify emerging opportunities.',
|
||||
monitoringRecommendation:
|
||||
'Continue monitoring supply/demand trends to identify emerging opportunities.',
|
||||
noAnalysisData: 'No supply/demand analysis data available',
|
||||
},
|
||||
organizationCard: {
|
||||
@ -1447,4 +1464,11 @@ export const en = {
|
||||
need: 'Need',
|
||||
},
|
||||
},
|
||||
dateRange: {
|
||||
last7Days: 'Last 7 Days',
|
||||
last30Days: 'Last 30 Days',
|
||||
last90Days: 'Last 90 Days',
|
||||
lastYear: 'Last Year',
|
||||
allTime: 'All Time',
|
||||
},
|
||||
};
|
||||
|
||||
@ -5,7 +5,7 @@ export const ru = {
|
||||
tt: 'TT',
|
||||
},
|
||||
topBar: {
|
||||
title: 'Туган Як',
|
||||
title: 'Turash',
|
||||
subTitle: 'Экосистема г. Бугульма',
|
||||
loginButton: 'Войти',
|
||||
adminButton: 'Админ',
|
||||
@ -284,7 +284,7 @@ export const ru = {
|
||||
ctaNote: 'Доступно только для авторизованных пользователей.',
|
||||
},
|
||||
footer: {
|
||||
copyright: '© {{year}} Туган Як. Все права защищены.',
|
||||
copyright: '© {{year}} Turash. Все права защищены.',
|
||||
links: {
|
||||
about: 'О проекте',
|
||||
contact: 'Контакты',
|
||||
@ -325,9 +325,9 @@ export const ru = {
|
||||
},
|
||||
},
|
||||
chatbot: {
|
||||
header: 'Туган Як AI',
|
||||
header: 'Turash AI',
|
||||
online: 'Онлайн',
|
||||
initialMessage: 'Здравствуйте! Я — ваш помощник по экосистеме "Туган Як". Чем могу помочь?',
|
||||
initialMessage: 'Здравствуйте! Я — ваш помощник по экосистеме "Turash". Чем могу помочь?',
|
||||
placeholder: 'Спросите что-нибудь...',
|
||||
sendLabel: 'Отправить',
|
||||
closeLabel: 'Закрыть чат',
|
||||
@ -541,7 +541,7 @@ export const ru = {
|
||||
},
|
||||
adminPage: {
|
||||
title: 'Панель администратора',
|
||||
subtitle: 'Обзор и управление экосистемой "Туган Як"',
|
||||
subtitle: 'Обзор и управление экосистемой "Turash"',
|
||||
totalOrgs: 'Всего организаций',
|
||||
verifiedOrgs: 'Проверенных',
|
||||
connections: 'Симбиотических связей',
|
||||
@ -573,10 +573,10 @@ export const ru = {
|
||||
},
|
||||
},
|
||||
aboutPage: {
|
||||
p1: 'Проект "Туган Як" — это цифровая платформа, созданная для визуализации и укрепления экономических связей внутри города Бугульма.',
|
||||
p1: 'Проект "Turash" — это цифровая платформа, созданная для визуализации и укрепления экономических связей внутри города Бугульма.',
|
||||
p2: 'Наша цель — способствовать развитию промышленного симбиоза, где отходы одного предприятия становятся сырьем для другого. Это не только снижает издержки для бизнеса, но и улучшает экологическую обстановку в регионе.',
|
||||
p3: 'Используя современные технологии, включая искусственный интеллект, мы помогаем компаниям находить новых партнеров, оптимизировать логистику и открывать не очевидные возможности для сотрудничества.',
|
||||
p4: 'Мы верим, что сильная местная экономика строится на прочных связях. "Туган Як" — это наш вклад в процветание родного края.',
|
||||
p4: 'Мы верим, что сильная местная экономика строится на прочных связях. "Turash" — это наш вклад в процветание родного края.',
|
||||
},
|
||||
contactPage: {
|
||||
lead: 'Мы всегда открыты для предложений и сотрудничества. Свяжитесь с нами любым удобным способом.',
|
||||
@ -589,7 +589,7 @@ export const ru = {
|
||||
email: {
|
||||
title: 'Электронная почта',
|
||||
line1: 'Для общих вопросов и предложений',
|
||||
line2: 'info@tuganyak.dev',
|
||||
line2: 'info@turash.dev',
|
||||
},
|
||||
phone: { title: 'Телефон', line1: 'Поддержка и консультации', line2: '+7 (855) 941-23-45' },
|
||||
},
|
||||
@ -600,7 +600,7 @@ export const ru = {
|
||||
{
|
||||
title: '1. Общие положения',
|
||||
content:
|
||||
'Настоящая политика обработки персональных данных составлена в соответствии с требованиями Федерального закона от 27.07.2006. №152-ФЗ «О персональных данных» и определяет порядок обработки персональных данных и меры по обеспечению безопасности персональных данных, предпринимаемые проектом "Туган Як".',
|
||||
'Настоящая политика обработки персональных данных составлена в соответствии с требованиями Федерального закона от 27.07.2006. №152-ФЗ «О персональных данных» и определяет порядок обработки персональных данных и меры по обеспечению безопасности персональных данных, предпринимаемые проектом "Turash".',
|
||||
},
|
||||
{
|
||||
title: '2. Основные понятия, используемые в Политике',
|
||||
@ -693,7 +693,7 @@ export const ru = {
|
||||
instruction: 'Напишите повествовательный абзац об этом памятнике.',
|
||||
},
|
||||
chatSystemInstruction:
|
||||
'Вы — полезный AI-ассистент для платформы "Туган Як". Ваше имя — Туган Як AI. Ваша цель — помогать пользователям находить информацию о местных предприятиях, услугах и возможностях сотрудничества в городе Бугульма. Если предоставлено изображение, проанализируйте его в контексте вопроса пользователя. Используйте метафору "компаса" или "навигатора", чтобы направлять пользователей. Будьте краткими, дружелюбными и сосредоточьтесь на предоставлении действенной информации, relevantной для платформы промышленного симбиоза "Туган Як". Форматируйте свои ответы, используя базовый markdown (выделение жирным с помощью ** и неупорядоченные списки с помощью *).',
|
||||
'Вы — полезный AI-ассистент для платформы "Turash". Ваше имя — Turash AI. Ваша цель — помогать пользователям находить информацию о местных предприятиях, услугах и возможностях сотрудничества в городе Бугульма. Если предоставлено изображение, проанализируйте его в контексте вопроса пользователя. Используйте метафору "компаса" или "навигатора", чтобы направлять пользователей. Будьте краткими, дружелюбными и сосредоточьтесь на предоставлении действенной информации, relevantной для платформы промышленного симбиоза "Turash". Форматируйте свои ответы, используя базовый markdown (выделение жирным с помощью ** и неупорядоченные списки с помощью *).',
|
||||
},
|
||||
validation: {
|
||||
string: {
|
||||
|
||||
@ -5,7 +5,7 @@ export const tt = {
|
||||
tt: 'TT',
|
||||
},
|
||||
topBar: {
|
||||
title: 'Туган Як',
|
||||
title: 'Turash',
|
||||
subTitle: 'Бөгелмә шәһәре экосистемасы',
|
||||
loginButton: 'Керү',
|
||||
adminButton: 'Админ',
|
||||
@ -269,7 +269,7 @@ export const tt = {
|
||||
ctaNote: 'Бары тик авторизацияләнгән кулланучылар өчен генә мөмкин.',
|
||||
},
|
||||
footer: {
|
||||
copyright: '© {{year}} Туган Як. Барлык хокуклар сакланган.',
|
||||
copyright: '© {{year}} Turash. Барлык хокуклар сакланган.',
|
||||
links: {
|
||||
about: 'Проект турында',
|
||||
contact: 'Контактлар',
|
||||
@ -310,10 +310,10 @@ export const tt = {
|
||||
},
|
||||
},
|
||||
chatbot: {
|
||||
header: 'Туган Як AI',
|
||||
header: 'Turash AI',
|
||||
online: 'Онлайн',
|
||||
initialMessage:
|
||||
'Исәнмесез! Мин - "Туган Як" экосистемасы буенча сезнең ярдәмчегез. Нәрсә белән ярдәм итә алам?',
|
||||
'Исәнмесез! Мин - "Turash" экосистемасы буенча сезнең ярдәмчегез. Нәрсә белән ярдәм итә алам?',
|
||||
placeholder: 'Берәр нәрсә сорагыз...',
|
||||
sendLabel: 'Җибәрү',
|
||||
closeLabel: 'Чатны ябу',
|
||||
@ -518,7 +518,7 @@ export const tt = {
|
||||
},
|
||||
adminPage: {
|
||||
title: 'Администратор панеле',
|
||||
subtitle: '"Туган Як" экосистемасын күзәтү һәм идарә итү',
|
||||
subtitle: '"Turash" экосистемасын күзәтү һәм идарә итү',
|
||||
totalOrgs: 'Барлык оешмалар',
|
||||
verifiedOrgs: 'Тикшерелгәннәр',
|
||||
connections: 'Симбиотик бәйләнешләр',
|
||||
@ -550,10 +550,10 @@ export const tt = {
|
||||
},
|
||||
},
|
||||
aboutPage: {
|
||||
p1: '"Туган Як" проекты — Бөгелмә шәһәре эчендә икътисади элемтәләрне визуальләштерү һәм ныгыту өчен булдырылган санлы платформа.',
|
||||
p1: '"Turash" проекты — Бөгелмә шәһәре эчендә икътисади элемтәләрне визуальләштерү һәм ныгыту өчен булдырылган санлы платформа.',
|
||||
p2: 'Безнең максат — сәнәгый симбиоз үсешенә булышлык итү, анда бер предприятиенең калдыклары икенчесе өчен чимал була. Бу бизнес өчен чыгымнарны киметә генә түгел, ә регионда экологик хәлне дә яхшырта.',
|
||||
p3: 'Ясалма интеллект кебек заманча технологияләрне кулланып, без компанияләргә яңа партнерлар табарга, логистиканы оптимальләштерергә һәм хезмәттәшлек өчен ачык булмаган мөмкинлекләр ачарга ярдәм итәбез.',
|
||||
p4: 'Без ышанабыз, көчле җирле икътисад ныклы элемтәләрдә төзелә. "Туган Як" — туган ягыбызның чәчәк атуына безнең өлешебез.',
|
||||
p4: 'Без ышанабыз, көчле җирле икътисад ныклы элемтәләрдә төзелә. "Turash" — туган ягыбызның чәчәк атуына безнең өлешебез.',
|
||||
},
|
||||
contactPage: {
|
||||
lead: 'Без һәрвакыт тәкъдимнәргә һәм хезмәттәшлеккә ачык. Безнең белән теләсә кайсы уңайлы ысул белән элемтәгә керегез.',
|
||||
@ -566,7 +566,7 @@ export const tt = {
|
||||
email: {
|
||||
title: 'Электрон почта',
|
||||
line1: 'Гомуми сораулар һәм тәкъдимнәр өчен',
|
||||
line2: 'info@tuganyak.dev',
|
||||
line2: 'info@turash.dev',
|
||||
},
|
||||
phone: { title: 'Телефон', line1: 'Ярдәм һәм консультацияләр', line2: '+7 (855) 941-23-45' },
|
||||
},
|
||||
@ -577,7 +577,7 @@ export const tt = {
|
||||
{
|
||||
title: '1. Гомуми нигезләмәләр',
|
||||
content:
|
||||
'Бу шәхси мәгълүматларны эшкәртү сәясәте 27.07.2006 елгы №152-ФЗ «Шәхси мәгълүматлар турында» Федераль закон таләпләренә туры китереп төзелгән һәм "Туган Як" проекты тарафыннан шәхси мәгълүматларны эшкәртү тәртибен һәм шәхси мәгълүматларның куркынычсызлыгын тәэмин итү чараларын билгели.',
|
||||
'Бу шәхси мәгълүматларны эшкәртү сәясәте 27.07.2006 елгы №152-ФЗ «Шәхси мәгълүматлар турында» Федераль закон таләпләренә туры китереп төзелгән һәм "Turash" проекты тарафыннан шәхси мәгълүматларны эшкәртү тәртибен һәм шәхси мәгълүматларның куркынычсызлыгын тәэмин итү чараларын билгели.',
|
||||
},
|
||||
{
|
||||
title: '2. Сәясәттә кулланылган төп төшенчәләр',
|
||||
@ -663,11 +663,12 @@ export const tt = {
|
||||
instruction: 'Бу һәйкәл турында хикәяләү абзацы языгыз.',
|
||||
},
|
||||
chatSystemInstruction:
|
||||
'Сез — "Туган Як" платформасы өчен файдалы ЯИ-ярдәмче. Сезнең исемегез — Туган Як ЯИ. Сезнең максат — кулланучыларга Бөгелмә шәһәрендәге җирле предприятиеләр, хезмәтләр һәм хезмәттәшлек мөмкинлекләре турында мәгълүмат табарга ярдәм итү. Әгәр рәсем бирелсә, аны кулланучы соравы контекстында анализлагыз. Кулланучыларны юнәлтү өчен "компас" яки "навигатор" метафорасын кулланыгыз. Кыска, дустанә булыгыз һәм "Туган Як" сәнәгый симбиоз платформасына кагылышлы гамәли мәгълүмат бирүгә игътибар итегез. Җавапларыгызны төп markdown кулланып форматлагыз (калын хәрефләр өчен ** һәм тәртипсез исемлекләр өчен *).',
|
||||
'Сез — "Turash" платформасы өчен файдалы ЯИ-ярдәмче. Сезнең исемегез — Turash ЯИ. Сезнең максат — кулланучыларга Бөгелмә шәһәрендәге җирле предприятиеләр, хезмәтләр һәм хезмәттәшлек мөмкинлекләре турында мәгълүмат табарга ярдәм итү. Әгәр рәсем бирелсә, аны кулланучы соравы контекстында анализлагыз. Кулланучыларны юнәлтү өчен "компас" яки "навигатор" метафорасын кулланыгыз. Кыска, дустанә булыгыз һәм "Turash" сәнәгый симбиоз платформасына кагылышлы гамәли мәгълүмат бирүгә игътибар итегез. Җавапларыгызны төп markdown кулланып форматлагыз (калын хәрефләр өчен ** һәм тәртипсез исемлекләр өчен *).',
|
||||
},
|
||||
discoveryPage: {
|
||||
title: 'Товарлар һәм хезмәтләр табу',
|
||||
subtitle: 'Сезгә кирәк булганны җирле районда табыгыз - товарлар, хезмәтләр һәм җәмгыять игъланнары',
|
||||
subtitle:
|
||||
'Сезгә кирәк булганны җирле районда табыгыз - товарлар, хезмәтләр һәм җәмгыять игъланнары',
|
||||
searchPlaceholder: 'Товарлар, хезмәтләр яки җәмгыять игъланнарын эзләү...',
|
||||
searchButton: 'Эзләү',
|
||||
category: 'Төркем',
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
{
|
||||
"name": "Туган Як: Экосистема г. Бугульма",
|
||||
"description": "Туган Як — это компас, объединяющий наследие, бизнес и будущее Бугульмы. Наша платформа помогает находить партнеров, оптимизировать ресурсы и строить процветающее сообщество, основанное на богатой истории города.",
|
||||
"requestFramePermissions": ["microphone"]
|
||||
"name": "Turash: Экосистема г. Бугульма",
|
||||
"description": "Turash — это компас, объединяющий наследие, бизнес и будущее Бугульмы. Наша платформа помогает находить партнеров, оптимизировать ресурсы и строить процветающее сообщество, основанное на богатой истории города.",
|
||||
"requestFramePermissions": [
|
||||
"microphone"
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { MainLayout } from '@/components/layout/MainLayout';
|
||||
import PageHeader from '@/components/layout/PageHeader';
|
||||
import { Badge } from '@/components/ui';
|
||||
import Button from '@/components/ui/Button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import Input from '@/components/ui/Input';
|
||||
import { useAuth } from '@/contexts/AuthContext';
|
||||
import { useTranslation } from '@/hooks/useI18n';
|
||||
import { useNavigation } from '@/hooks/useNavigation';
|
||||
import { Badge } from '@/components/ui';
|
||||
import { User, Shield, FileText, Eye } from 'lucide-react';
|
||||
import { Eye, FileText, Shield, User } from 'lucide-react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
|
||||
const isDevelopment = import.meta.env.DEV;
|
||||
|
||||
// Test user credentials for development
|
||||
const TEST_USERS = [
|
||||
{
|
||||
email: 'admin@tuganyak.dev',
|
||||
email: 'admin@turash.dev',
|
||||
password: 'admin123',
|
||||
role: 'admin',
|
||||
label: 'Admin',
|
||||
@ -24,7 +24,7 @@ const TEST_USERS = [
|
||||
description: 'Full admin panel access',
|
||||
},
|
||||
{
|
||||
email: 'user@tuganyak.dev',
|
||||
email: 'user@turash.dev',
|
||||
password: 'user12345',
|
||||
role: 'user',
|
||||
label: 'User',
|
||||
@ -32,7 +32,7 @@ const TEST_USERS = [
|
||||
description: 'Regular user dashboard',
|
||||
},
|
||||
{
|
||||
email: 'content@tuganyak.dev',
|
||||
email: 'content@turash.dev',
|
||||
password: 'content123',
|
||||
role: 'content_manager',
|
||||
label: 'Content Manager',
|
||||
@ -40,7 +40,7 @@ const TEST_USERS = [
|
||||
description: 'Content and localization',
|
||||
},
|
||||
{
|
||||
email: 'viewer@tuganyak.dev',
|
||||
email: 'viewer@turash.dev',
|
||||
password: 'viewer123',
|
||||
role: 'viewer',
|
||||
label: 'Viewer',
|
||||
@ -54,7 +54,7 @@ const LoginPage = () => {
|
||||
const { login, isLoading, user } = useAuth();
|
||||
const { handleFooterNavigate } = useNavigation();
|
||||
const navigate = useNavigate();
|
||||
const [email, setEmail] = useState(isDevelopment ? 'admin@tuganyak.dev' : '');
|
||||
const [email, setEmail] = useState(isDevelopment ? 'admin@turash.dev' : '');
|
||||
const [password, setPassword] = useState(isDevelopment ? 'admin123' : '');
|
||||
const [error, setError] = useState('');
|
||||
|
||||
@ -70,7 +70,7 @@ const LoginPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleQuickLogin = async (testUser: typeof TEST_USERS[number]) => {
|
||||
const handleQuickLogin = async (testUser: (typeof TEST_USERS)[number]) => {
|
||||
setError('');
|
||||
setEmail(testUser.email);
|
||||
setPassword(testUser.password);
|
||||
@ -104,7 +104,9 @@ const LoginPage = () => {
|
||||
<CardContent>
|
||||
{isDevelopment && (
|
||||
<div className="mb-6 p-4 bg-muted rounded-lg border border-primary/20">
|
||||
<p className="text-sm font-medium mb-3 text-foreground">Quick Login (Development)</p>
|
||||
<p className="text-sm font-medium mb-3 text-foreground">
|
||||
Quick Login (Development)
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{TEST_USERS.map((testUser) => (
|
||||
<Button
|
||||
@ -120,7 +122,9 @@ const LoginPage = () => {
|
||||
{testUser.icon}
|
||||
<span className="font-medium text-xs">{testUser.label}</span>
|
||||
</div>
|
||||
<span className="text-xs text-muted-foreground mt-1">{testUser.description}</span>
|
||||
<span className="text-xs text-muted-foreground mt-1">
|
||||
{testUser.description}
|
||||
</span>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
@ -153,7 +157,7 @@ const LoginPage = () => {
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
placeholder={isDevelopment ? 'admin@tuganyak.dev' : 'your@email.com'}
|
||||
placeholder={isDevelopment ? 'admin@turash.dev' : 'your@email.com'}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
- img [ref=e10]
|
||||
- generic [ref=e14]:
|
||||
- paragraph [ref=e15]: Bugulma Ecosystem
|
||||
- paragraph [ref=e16]: Tugan Yak
|
||||
- paragraph [ref=e16]: Turash
|
||||
- generic [ref=e17]:
|
||||
- img
|
||||
- searchbox "Name, industry, need..." [ref=e18]
|
||||
@ -156,8 +156,8 @@
|
||||
- generic [ref=e278]:
|
||||
- img [ref=e280]
|
||||
- generic [ref=e283]:
|
||||
- paragraph [ref=e284]: Tugan Yak
|
||||
- paragraph [ref=e285]: © 2025 Tugan Yak. All rights reserved.
|
||||
- paragraph [ref=e284]: Turash
|
||||
- paragraph [ref=e285]: © 2025 Turash. All rights reserved.
|
||||
- navigation "Footer" [ref=e286]:
|
||||
- button "About" [ref=e287] [cursor=pointer]
|
||||
- button "Contact" [ref=e288] [cursor=pointer]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user