Delete monorepo-migration-prompt.md
This commit is contained in:
parent
3236ba274c
commit
108b2b99bf
|
|
@ -1,720 +0,0 @@
|
|||
# MASTER PROMPT: Monorepo Migration, Fix, Test & Deploy
|
||||
|
||||
**Role**: Senior DevOps & Full-Stack Architect with QA Automation
|
||||
|
||||
## Current State
|
||||
- Backend: `/root/second-brain-backend`
|
||||
- Frontend: `/root/client`
|
||||
- Target Monorepo: `/root/second-brain`
|
||||
- Remote: `https://forgejo.dffm.it/giuseppe/second-brain.git`
|
||||
- Production URL: `https://ai.dffm.it`
|
||||
|
||||
## Objective
|
||||
Consolidate into monorepo, inject frontend logic, test via remote browser on ai.dffm.it, fix issues, push to Forgejo.
|
||||
|
||||
---
|
||||
|
||||
## PHASE 1: FILE SYSTEM MIGRATION
|
||||
|
||||
```bash
|
||||
# Create monorepo structure
|
||||
mkdir -p /root/second-brain/{server,client}
|
||||
|
||||
# Copy backend (preserve hidden files, exclude heavy dirs)
|
||||
rsync -av --exclude 'node_modules' --exclude '.git' \
|
||||
/root/second-brain-backend/ /root/second-brain/server/
|
||||
|
||||
# Copy frontend (preserve hidden files, exclude heavy dirs)
|
||||
rsync -av --exclude 'node_modules' --exclude '.git' --exclude 'dist' \
|
||||
/root/client/ /root/second-brain/client/
|
||||
|
||||
# Verify structure
|
||||
tree -L 2 /root/second-brain
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PHASE 2: FRONTEND LOGIC INJECTION
|
||||
|
||||
### 2.1 MainLayout.tsx (client/src/components/layout/MainLayout.tsx)
|
||||
|
||||
```typescript
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header
|
||||
onMenuToggle={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
||||
/>
|
||||
<Sidebar
|
||||
isOpen={isMobileMenuOpen}
|
||||
onClose={() => setIsMobileMenuOpen(false)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
```
|
||||
|
||||
### 2.2 Header.tsx
|
||||
|
||||
**Requirements:**
|
||||
|
||||
- Fetch GET /api/me on mount, display user avatar/name
|
||||
|
||||
- Add Hamburger button (visible md:hidden) → triggers onMenuToggle
|
||||
|
||||
- Avatar dropdown with "Sign out" → POST /auth/logout → redirect to /login
|
||||
|
||||
```typescript
|
||||
const handleLogout = async () => {
|
||||
await fetch('/auth/logout', { method: 'POST', credentials: 'include' });
|
||||
window.location.href = '/login';
|
||||
};
|
||||
```
|
||||
|
||||
### 2.3 Sidebar.tsx
|
||||
|
||||
**Requirements:**
|
||||
|
||||
- Mobile drawer: Fixed position with transform -translate-x-full when closed
|
||||
|
||||
- Overlay backdrop: fixed inset-0 bg-black/50 z-40 (visible only when isOpen)
|
||||
|
||||
- Close on backdrop click and on ESC key
|
||||
|
||||
- "+ New Note" button → POST /api/ingest with current workspaceId
|
||||
|
||||
---
|
||||
|
||||
## PHASE 3: BACKEND CONFIGURATION
|
||||
**File:** `server/src/server.ts` (or `app.ts`)
|
||||
|
||||
```typescript
|
||||
// Serve frontend static files in production
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
app.use(express.static(path.join(__dirname, '../../client/dist')));
|
||||
app.get('*', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../../client/dist/index.html'));
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**Ensure:** CORS is configured to allow frontend origin:
|
||||
|
||||
```typescript
|
||||
app.use(cors({ origin: 'https://ai.dffm.it', credentials: true }));
|
||||
```
|
||||
|
||||
---
|
||||
## PHASE 4: INSTALL DEPENDENCIES & BUILD
|
||||
|
||||
```bash
|
||||
# Install server dependencies
|
||||
cd /root/second-brain/server
|
||||
npm install
|
||||
|
||||
# Install client dependencies
|
||||
cd /root/second-brain/client
|
||||
npm install
|
||||
|
||||
# Build client for production
|
||||
npm run build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PHASE 5: REMOTE BROWSER TESTING & AUTO-FIX
|
||||
|
||||
**Objective:** Deploy to production, test via https://ai.dffm.it, identify issues, fix autonomously.
|
||||
|
||||
### 5.1 Deploy to Production Server
|
||||
|
||||
```bash
|
||||
# Build frontend for production
|
||||
cd /root/second-brain/client
|
||||
npm run build
|
||||
|
||||
# Start backend (serving frontend static files)
|
||||
cd /root/second-brain/server
|
||||
NODE_ENV=production npm start
|
||||
# Or use PM2 for persistent process:
|
||||
# pm2 restart second-brain || pm2 start npm --name "second-brain" -- start
|
||||
```
|
||||
|
||||
**Verify** the app is accessible at https://ai.dffm.it before proceeding.
|
||||
|
||||
### 5.2 Browser Testing Protocol (Remote via Chrome)
|
||||
|
||||
Use Antigravity's browser automation/preview to navigate to https://ai.dffm.it.
|
||||
|
||||
**Chrome Configuration:** Already authenticated with Giuseppe's Google account.
|
||||
|
||||
**Test Sequence**
|
||||
|
||||
#### 1. Authentication & Session Verification
|
||||
|
||||
- Navigate to https://ai.dffm.it
|
||||
|
||||
- Check if already logged in (session cookie valid)
|
||||
|
||||
- If redirected to /login:
|
||||
|
||||
- Verify Google SSO button is present
|
||||
|
||||
- Click "Sign in with Google"
|
||||
|
||||
- Verify redirect to Google (should auto-authenticate)
|
||||
|
||||
- Verify redirect back to https://ai.dffm.it/dashboard
|
||||
|
||||
- Verify GET /api/me returns correct user data
|
||||
|
||||
- Check Header displays: Avatar + "Giuseppe" (or your name)
|
||||
|
||||
#### 2. Desktop Layout Testing (viewport: 1920x1080)
|
||||
|
||||
**Header:**
|
||||
|
||||
- ✅ Logo visible
|
||||
|
||||
- ✅ Navigation links present
|
||||
|
||||
- ✅ Avatar dropdown opens on click
|
||||
|
||||
- ✅ "Sign out" option visible in dropdown
|
||||
|
||||
**Sidebar:**
|
||||
|
||||
- ✅ Always visible (not hidden on desktop)
|
||||
|
||||
- ✅ Navigation items clickable
|
||||
|
||||
- ✅ "+ New Note" button visible
|
||||
|
||||
**Main Content:**
|
||||
|
||||
- ✅ Dashboard loads without errors
|
||||
|
||||
- ✅ No layout overflow or broken grids
|
||||
|
||||
#### 3. Mobile Layout Testing (viewport: 375x667)
|
||||
|
||||
Resize browser to mobile viewport or use DevTools device emulation
|
||||
|
||||
**Header:**
|
||||
|
||||
- ✅ Hamburger icon visible (replaces full nav)
|
||||
|
||||
- ✅ Click hamburger → Sidebar slides in from left
|
||||
|
||||
- ✅ Overlay backdrop appears (semi-transparent black)
|
||||
|
||||
**Sidebar behavior:**
|
||||
|
||||
- ✅ Sidebar has transform -translate-x-full when closed
|
||||
|
||||
- ✅ Sidebar slides to transform-none when open
|
||||
|
||||
- ✅ Click overlay → Sidebar closes
|
||||
|
||||
- ✅ Press ESC key → Sidebar closes
|
||||
|
||||
- ✅ Navigation links work on mobile
|
||||
|
||||
**Mobile navigation:**
|
||||
|
||||
- ✅ No horizontal scroll
|
||||
|
||||
- ✅ Touch targets >= 44px (mobile-friendly)
|
||||
|
||||
#### 4. Responsive Breakpoints (test at each):
|
||||
|
||||
- 640px (sm) - Mobile landscape
|
||||
|
||||
- 768px (md) - Tablet portrait (hamburger should disappear, sidebar always visible)
|
||||
|
||||
- 1024px (lg) - Tablet landscape
|
||||
|
||||
- 1280px (xl) - Desktop
|
||||
|
||||
**Verify at each breakpoint:**
|
||||
|
||||
- No layout breaks
|
||||
|
||||
- No content overflow
|
||||
|
||||
- Smooth transitions
|
||||
|
||||
- Sidebar visibility toggles correctly at md breakpoint
|
||||
|
||||
#### 5. Functional Testing
|
||||
|
||||
**5a. "+ New Note" Upload**
|
||||
|
||||
- Click "+ New Note" button
|
||||
|
||||
- File picker should open
|
||||
|
||||
- Select a test file (e.g., .txt, .md, .pdf)
|
||||
|
||||
- Verify upload via DevTools Network tab:
|
||||
|
||||
- Request: POST /api/ingest
|
||||
|
||||
- Body includes workspaceId (current workspace)
|
||||
|
||||
- Response: 200 OK or appropriate success code
|
||||
|
||||
- Verify success feedback (toast/notification)
|
||||
|
||||
- Verify new note appears in notes list
|
||||
|
||||
**5b. Sign Out Flow**
|
||||
|
||||
- Open avatar dropdown
|
||||
|
||||
- Click "Sign out"
|
||||
|
||||
- Verify:
|
||||
|
||||
- Request: POST /auth/logout
|
||||
|
||||
- Response: Clears session cookie
|
||||
|
||||
- Redirect to /login
|
||||
|
||||
- Verify session is cleared (no auto-login on page reload)
|
||||
|
||||
#### 6. Console & Network Monitoring
|
||||
|
||||
Open Chrome DevTools and monitor:
|
||||
|
||||
**Console:** No errors (red messages)
|
||||
|
||||
**Network:**
|
||||
|
||||
- All API calls return 200/201/204 (no 4xx/5xx)
|
||||
|
||||
- No failed asset loads (CSS, JS, images)
|
||||
|
||||
**Performance:**
|
||||
|
||||
- Initial load < 3s
|
||||
|
||||
- No memory leaks during navigation
|
||||
|
||||
- Lighthouse score > 80 (optional but recommended)
|
||||
|
||||
### 5.3 Issue Detection & Auto-Fix Loop
|
||||
|
||||
For each issue discovered:
|
||||
|
||||
**Capture Evidence:**
|
||||
|
||||
- Screenshot of the issue
|
||||
|
||||
- Browser console errors (copy full stack trace)
|
||||
|
||||
- Network tab errors (request/response details)
|
||||
|
||||
- Exact steps to reproduce
|
||||
|
||||
**Diagnose Root Cause:**
|
||||
|
||||
- Identify which component/file is responsible
|
||||
|
||||
- Check if it's frontend (client code) or backend (API) issue
|
||||
|
||||
- Review recent changes that might have introduced it
|
||||
|
||||
**Propose Fix:**
|
||||
|
||||
- Determine exact code change needed
|
||||
|
||||
- Consider side effects of the fix
|
||||
|
||||
- Prefer minimal changes (surgical fixes)
|
||||
|
||||
**Apply Fix:**
|
||||
|
||||
- Edit the relevant file in /root/second-brain/
|
||||
|
||||
- If frontend change: rebuild with `cd /root/second-brain/client && npm run build`
|
||||
|
||||
- If backend change: restart server with `pm2 restart second-brain`
|
||||
|
||||
**Re-Test:**
|
||||
|
||||
- Navigate back to https://ai.dffm.it
|
||||
|
||||
- Reproduce the exact steps
|
||||
|
||||
- Verify issue is resolved
|
||||
|
||||
- Check no new issues introduced
|
||||
|
||||
**Document Fix:**
|
||||
|
||||
- Add entry to TESTING_REPORT.md (format below)
|
||||
|
||||
**Iteration Limit:** Max 3 attempts per issue. If unresolved after 3 attempts, document as "Needs Human Review" and proceed.
|
||||
|
||||
### 5.4 Common Issues & Solutions
|
||||
|
||||
**Issue:** Mobile menu doesn't close on backdrop click
|
||||
|
||||
- **Fix:** Add `onClick={() => onClose()}` to overlay div
|
||||
|
||||
- **File:** `client/src/components/layout/Sidebar.tsx`
|
||||
|
||||
**Issue:** API calls fail with CORS error
|
||||
|
||||
- **Fix:** Add CORS middleware in backend:
|
||||
|
||||
```typescript
|
||||
app.use(cors({ origin: 'https://ai.dffm.it', credentials: true }));
|
||||
```
|
||||
|
||||
- **File:** `server/src/server.ts`
|
||||
|
||||
**Issue:** Avatar dropdown doesn't show user name
|
||||
|
||||
- **Fix:** Verify GET /api/me is called and state is updated
|
||||
|
||||
- **File:** `client/src/components/layout/Header.tsx`
|
||||
|
||||
**Issue:** Sidebar overlaps content on tablet
|
||||
|
||||
- **Fix:** Check Tailwind breakpoint classes (should be `md:translate-x-0`)
|
||||
|
||||
- **File:** `client/src/components/layout/Sidebar.tsx`
|
||||
|
||||
**Issue:** Sign out doesn't clear session
|
||||
|
||||
- **Fix:** Verify `/auth/logout` clears cookies with correct domain
|
||||
|
||||
- **File:** `server/src/routes/auth.ts`
|
||||
|
||||
### 5.5 Testing Report Generation
|
||||
|
||||
Create `/root/second-brain/TESTING_REPORT.md`:
|
||||
|
||||
```markdown
|
||||
# Testing Report - Second Brain (ai.dffm.it)
|
||||
|
||||
**Test Date**: [Current timestamp]
|
||||
**Tested URL**: https://ai.dffm.it
|
||||
**Browser**: Chrome (authenticated with giuseppe@dffm.it)
|
||||
**Tester**: Antigravity Agent
|
||||
|
||||
---
|
||||
|
||||
## Test Environment
|
||||
- Backend: Node.js v[X] on Ubuntu
|
||||
- Frontend: Vite + React + Tailwind CSS
|
||||
- Server: ai.dffm.it (production)
|
||||
|
||||
---
|
||||
|
||||
## Issues Found & Fixed
|
||||
|
||||
### Issue 1: [Title]
|
||||
- **Severity**: 🔴 Critical / 🟡 High / 🟢 Medium / ⚪ Low
|
||||
- **Component**: `client/src/components/...`
|
||||
- **Description**: [What was wrong]
|
||||
- **Steps to Reproduce**:
|
||||
1. [Step 1]
|
||||
2. [Step 2]
|
||||
- **Root Cause**: [Why it happened]
|
||||
- **Fix Applied**:
|
||||
```typescript
|
||||
// Before
|
||||
[old code]
|
||||
|
||||
// After
|
||||
[new code]
|
||||
```
|
||||
- **Files Modified:**
|
||||
- `client/src/components/layout/Header.tsx`
|
||||
- **Status**: ✅ Resolved / ⏳ In Progress / ❌ Needs Review
|
||||
|
||||
[Repeat for each issue]
|
||||
|
||||
---
|
||||
|
||||
## Test Results Summary
|
||||
|
||||
### Authentication ✅
|
||||
- ✅ Google SSO login works
|
||||
|
||||
- ✅ Session persists on refresh
|
||||
|
||||
- ✅ User data loads in Header
|
||||
|
||||
- ✅ Sign out clears session
|
||||
|
||||
### Desktop Layout (1920x1080) ✅
|
||||
- ✅ Header displays correctly
|
||||
|
||||
- ✅ Sidebar always visible
|
||||
|
||||
- ✅ Navigation works
|
||||
|
||||
- ✅ Avatar dropdown functional
|
||||
|
||||
### Mobile Layout (375x667) ✅
|
||||
- ✅ Hamburger menu visible
|
||||
|
||||
- ✅ Sidebar slides in/out
|
||||
|
||||
- ✅ Overlay backdrop works
|
||||
|
||||
- ✅ ESC key closes menu
|
||||
|
||||
- ✅ No horizontal scroll
|
||||
|
||||
### Responsive Breakpoints ✅
|
||||
- ✅ 640px (sm)
|
||||
|
||||
- ✅ 768px (md) - Sidebar transition
|
||||
|
||||
- ✅ 1024px (lg)
|
||||
|
||||
- ✅ 1280px (xl)
|
||||
|
||||
### Functional Features ✅
|
||||
- ✅ New note upload works
|
||||
|
||||
- ✅ Workspace selection
|
||||
|
||||
- ✅ Sign out flow
|
||||
|
||||
### Console & Network ✅
|
||||
- ✅ No console errors
|
||||
|
||||
- ✅ All API calls succeed
|
||||
|
||||
- ✅ No failed asset loads
|
||||
|
||||
---
|
||||
|
||||
## Performance Metrics
|
||||
- Initial Load: [X]ms
|
||||
|
||||
- Time to Interactive: [X]ms
|
||||
|
||||
- Bundle Size: [X]KB
|
||||
|
||||
- Lighthouse Score: [X]/100
|
||||
|
||||
---
|
||||
|
||||
## Browser Compatibility
|
||||
- ✅ Chrome 120+ (primary)
|
||||
|
||||
- ⚠️ Firefox (not tested)
|
||||
|
||||
- ⚠️ Safari (not tested)
|
||||
|
||||
---
|
||||
|
||||
## Recommendations
|
||||
- [Any improvements or optimizations suggested]
|
||||
|
||||
- [Security considerations]
|
||||
|
||||
- [Performance optimizations]
|
||||
|
||||
---
|
||||
|
||||
## Sign-off
|
||||
All critical and high-priority issues resolved. App is production-ready on https://ai.dffm.it.
|
||||
|
||||
**Ready for Git Push:** ✅ Yes / ❌ No (reason: ...)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.6 Execution Checklist
|
||||
|
||||
- [ ] App deployed to `https://ai.dffm.it`
|
||||
- [ ] Chrome browser opened (authenticated session)
|
||||
- [ ] Authentication flow tested
|
||||
- [ ] Desktop layout verified (all breakpoints)
|
||||
- [ ] Mobile layout verified (all interactions)
|
||||
- [ ] Responsive transitions tested
|
||||
- [ ] New note upload functional
|
||||
- [ ] Sign out flow works
|
||||
- [ ] Console clean (no errors)
|
||||
- [ ] Network clean (no failed requests)
|
||||
- [ ] All issues documented and fixed
|
||||
- [ ] `TESTING_REPORT.md` created
|
||||
- [ ] Ready for git commit
|
||||
|
||||
**Only proceed to PHASE 6 when this checklist is 100% complete.**
|
||||
|
||||
---
|
||||
|
||||
## PHASE 6: GIT COMMIT & PUSH
|
||||
|
||||
### 6.1 Root .gitignore (`/root/second-brain/.gitignore`)
|
||||
|
||||
```
|
||||
node_modules/
|
||||
dist/
|
||||
.env
|
||||
.env.local
|
||||
*.log
|
||||
.DS_Store
|
||||
coverage/
|
||||
.vscode/
|
||||
.idea/
|
||||
```
|
||||
|
||||
### 6.2 Git Commands
|
||||
|
||||
```bash
|
||||
cd /root/second-brain
|
||||
|
||||
# Initialize repo
|
||||
git init
|
||||
|
||||
# Add all files
|
||||
git add .
|
||||
|
||||
# Commit with testing report reference
|
||||
git commit -m "refactor: monorepo migration with frontend v2 logic + browser testing fixes
|
||||
|
||||
- Migrated backend and frontend into monorepo structure
|
||||
- Implemented mobile menu with slide-in drawer
|
||||
- Added user authentication with Google SSO
|
||||
- Fixed responsive breakpoints and layout issues
|
||||
- All browser tests passed on ai.dffm.it
|
||||
- See TESTING_REPORT.md for details"
|
||||
|
||||
# Set main branch
|
||||
git branch -M main
|
||||
|
||||
# Add remote (with token)
|
||||
git remote add origin https://giuseppe:ef6966ed330def9b412f584f80a5e8a6c471ed5a@forgejo.dffm.it/giuseppe/second-brain.git
|
||||
|
||||
# Force push (overwrites remote)
|
||||
git push -u origin main --force
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## VALIDATION CHECKLIST
|
||||
|
||||
After execution:
|
||||
|
||||
- ✅ Monorepo structure created (server/, client/)
|
||||
|
||||
- ✅ Frontend logic injected (mobile menu, auth, etc.)
|
||||
|
||||
- ✅ Dependencies installed for both projects
|
||||
|
||||
- ✅ Production build successful
|
||||
|
||||
- ✅ App accessible at https://ai.dffm.it
|
||||
|
||||
- ✅ All browser tests pass
|
||||
|
||||
- ✅ All identified issues fixed and documented
|
||||
|
||||
- ✅ TESTING_REPORT.md created with all green checkmarks
|
||||
|
||||
- ✅ Code committed to git
|
||||
|
||||
- ✅ Code pushed to Forgejo successfully
|
||||
|
||||
- ✅ Remote repo accessible at https://forgejo.dffm.it/giuseppe/second-brain
|
||||
|
||||
---
|
||||
|
||||
## EXECUTION INSTRUCTIONS FOR ANTIGRAVITY
|
||||
|
||||
1. Execute PHASE 1-4 sequentially without pausing
|
||||
|
||||
2. In PHASE 5:
|
||||
|
||||
- Use your browser automation to navigate to https://ai.dffm.it
|
||||
|
||||
- Chrome is already authenticated → leverage for testing auth flows
|
||||
|
||||
- Take screenshots at each test step for documentation
|
||||
|
||||
- Use Chrome DevTools to capture console/network issues
|
||||
|
||||
- For each fix:
|
||||
|
||||
- Rebuild frontend: `cd /root/second-brain/client && npm run build`
|
||||
|
||||
- Restart backend: `pm2 restart second-brain`
|
||||
|
||||
- Wait 5s for server restart
|
||||
|
||||
- Clear browser cache (Ctrl+Shift+R) before re-testing
|
||||
|
||||
- Document everything in TESTING_REPORT.md as you go
|
||||
|
||||
- If a fix breaks something else → rollback and try alternative
|
||||
|
||||
- Only proceed to PHASE 6 when TESTING_REPORT.md shows all checkmarks green
|
||||
|
||||
### Success Criteria:
|
||||
|
||||
- Zero console errors
|
||||
|
||||
- All features work on desktop + mobile
|
||||
|
||||
- TESTING_REPORT.md complete with all tests passing
|
||||
|
||||
- "Ready for Git Push: ✅ Yes" in testing report
|
||||
|
||||
### Fail-safe Rules:
|
||||
|
||||
- Maximum 3 fix iterations per issue before escalating
|
||||
|
||||
- If critical blocker found → stop and request human review
|
||||
|
||||
- If any PHASE fails → stop and report the failure state
|
||||
|
||||
- Never proceed to git push if testing report shows failures
|
||||
|
||||
### Final Deliverables:
|
||||
|
||||
- Working monorepo at `/root/second-brain/`
|
||||
|
||||
- Fully tested app at https://ai.dffm.it
|
||||
|
||||
- Complete TESTING_REPORT.md with all issues documented
|
||||
|
||||
- Git repo pushed to Forgejo with all changes
|
||||
|
||||
---
|
||||
|
||||
## POST-EXECUTION NOTES
|
||||
|
||||
After successful push:
|
||||
|
||||
1. **Verify remote repo:** Visit https://forgejo.dffm.it/giuseppe/second-brain and confirm files are there
|
||||
|
||||
2. **Monitor production:** Check https://ai.dffm.it still works after push
|
||||
|
||||
3. **Update documentation:** Add setup instructions to README.md
|
||||
|
||||
4. **Security review:** Remove token from git remote URL (switch to SSH keys)
|
||||
|
||||
5. **Backup:** Create backup of /root/second-brain/ before cleanup
|
||||
|
||||
6. **Cleanup (optional):**
|
||||
|
||||
```bash
|
||||
# After confirming everything works
|
||||
rm -rf /root/second-brain-backend
|
||||
rm -rf /root/client
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**END OF PROMPT**
|
||||
Loading…
Reference in New Issue