Initial commit
This commit is contained in:
534
commands/add-deployment.md
Normal file
534
commands/add-deployment.md
Normal file
@@ -0,0 +1,534 @@
|
||||
Add a new deployment target to your existing Odoo PWA project.
|
||||
|
||||
## What this command does:
|
||||
- Adds deployment configuration for new platforms
|
||||
- Creates necessary config files
|
||||
- Sets up CI/CD workflows
|
||||
- Provides deployment instructions
|
||||
- Configures environment variables
|
||||
|
||||
## Supported Deployment Targets
|
||||
|
||||
### Primary (Recommended)
|
||||
- ✅ **Vercel** - Best for full-stack PWAs (API routes work)
|
||||
- ✅ **Netlify** - Great for static + serverless functions
|
||||
- ✅ **Cloudflare Pages** - Fast global CDN, edge functions
|
||||
|
||||
### Secondary (Static Only)
|
||||
- ⚠️ **GitHub Pages** - Free, but no server-side code
|
||||
- ⚠️ **Cloudflare Pages (Static)** - Without edge functions
|
||||
- ⚠️ **AWS S3 + CloudFront** - Static hosting only
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before adding deployment:
|
||||
|
||||
```
|
||||
□ Project builds successfully (npm run build)
|
||||
□ Odoo connection tested and working
|
||||
□ Environment variables documented
|
||||
□ Git repository initialized
|
||||
□ Code committed to version control
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Add Vercel Deployment 🔷
|
||||
|
||||
### What You'll Get:
|
||||
- Automatic deployments from Git
|
||||
- Serverless API routes
|
||||
- Preview deployments for PRs
|
||||
- Environment variable management
|
||||
- Custom domains
|
||||
- Analytics and logs
|
||||
|
||||
### Steps:
|
||||
|
||||
#### 1. Install Vercel CLI (Optional)
|
||||
```bash
|
||||
npm install -g vercel
|
||||
```
|
||||
|
||||
#### 2. Create `vercel.json`
|
||||
```json
|
||||
{
|
||||
"buildCommand": "npm run build",
|
||||
"outputDirectory": "build",
|
||||
"framework": "sveltekit",
|
||||
"installCommand": "npm install",
|
||||
"devCommand": "npm run dev",
|
||||
"env": {
|
||||
"VITE_ODOO_URL": "@vite_odoo_url",
|
||||
"VITE_ODOO_DB": "@vite_odoo_db",
|
||||
"VITE_MODEL_NAME": "@vite_model_name",
|
||||
"VITE_MODEL_DISPLAY_NAME": "@vite_model_display_name"
|
||||
},
|
||||
"build": {
|
||||
"env": {
|
||||
"ODOO_API_KEY": "@odoo_api_key",
|
||||
"ODOO_USERNAME": "@odoo_username"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For React/Vue:
|
||||
```json
|
||||
{
|
||||
"buildCommand": "npm run build",
|
||||
"outputDirectory": "dist",
|
||||
"framework": "vite"
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Create `.vercelignore`
|
||||
```
|
||||
node_modules
|
||||
.env
|
||||
.env.local
|
||||
*.log
|
||||
.DS_Store
|
||||
```
|
||||
|
||||
#### 4. Deployment Options
|
||||
|
||||
**Option A: Vercel Dashboard (Recommended for first time)**
|
||||
1. Go to https://vercel.com/new
|
||||
2. Connect your Git repository
|
||||
3. Vercel auto-detects framework
|
||||
4. Add environment variables:
|
||||
- `VITE_ODOO_URL`
|
||||
- `VITE_ODOO_DB`
|
||||
- `ODOO_API_KEY`
|
||||
- `ODOO_USERNAME`
|
||||
- `VITE_MODEL_NAME`
|
||||
- `VITE_MODEL_DISPLAY_NAME`
|
||||
5. Click "Deploy"
|
||||
|
||||
**Option B: Vercel CLI**
|
||||
```bash
|
||||
vercel login
|
||||
vercel
|
||||
|
||||
# Follow prompts
|
||||
# Add environment variables when asked
|
||||
# Or add them later in dashboard
|
||||
```
|
||||
|
||||
**Option C: Continuous Deployment**
|
||||
1. Connect repository to Vercel
|
||||
2. Every push to `main` auto-deploys
|
||||
3. PRs get preview deployments
|
||||
|
||||
#### 5. Configure Environment Variables
|
||||
In Vercel Dashboard:
|
||||
1. Go to Project Settings
|
||||
2. Environment Variables tab
|
||||
3. Add each variable:
|
||||
- Production
|
||||
- Preview (optional)
|
||||
- Development (optional)
|
||||
|
||||
#### 6. Test Deployment
|
||||
1. Wait for build to complete
|
||||
2. Visit deployed URL
|
||||
3. Test Odoo connection
|
||||
4. Verify all features work
|
||||
5. Check browser console for errors
|
||||
|
||||
---
|
||||
|
||||
## Add Netlify Deployment 🟢
|
||||
|
||||
### What You'll Get:
|
||||
- Git-based deployments
|
||||
- Serverless functions
|
||||
- Form handling
|
||||
- Split testing
|
||||
- Deploy previews
|
||||
- Custom domains
|
||||
|
||||
### Steps:
|
||||
|
||||
#### 1. Create `netlify.toml`
|
||||
```toml
|
||||
[build]
|
||||
command = "npm run build"
|
||||
publish = "build"
|
||||
|
||||
[build.environment]
|
||||
NODE_VERSION = "18"
|
||||
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
status = 200
|
||||
|
||||
[functions]
|
||||
directory = "netlify/functions"
|
||||
```
|
||||
|
||||
For React/Vue:
|
||||
```toml
|
||||
[build]
|
||||
command = "npm run build"
|
||||
publish = "dist"
|
||||
```
|
||||
|
||||
#### 2. Convert API Routes to Netlify Functions
|
||||
|
||||
Create `netlify/functions/odoo.js`:
|
||||
```javascript
|
||||
// Copy your API route logic here
|
||||
// Netlify functions use different format
|
||||
|
||||
exports.handler = async (event, context) => {
|
||||
// Parse request
|
||||
const body = JSON.parse(event.body);
|
||||
|
||||
// Your Odoo logic here
|
||||
// (copy from src/routes/api/odoo/+server.js)
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
body: JSON.stringify(result)
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
#### 3. Update Client to Use Netlify Function
|
||||
```javascript
|
||||
// Change API endpoint
|
||||
const response = await fetch('/.netlify/functions/odoo', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
```
|
||||
|
||||
#### 4. Deploy
|
||||
|
||||
**Option A: Netlify Dashboard**
|
||||
1. Go to https://app.netlify.com/start
|
||||
2. Connect repository
|
||||
3. Configure build settings
|
||||
4. Add environment variables
|
||||
5. Deploy
|
||||
|
||||
**Option B: Netlify CLI**
|
||||
```bash
|
||||
npm install -g netlify-cli
|
||||
netlify login
|
||||
netlify init
|
||||
netlify deploy --prod
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Add Cloudflare Pages Deployment 🟠
|
||||
|
||||
### What You'll Get:
|
||||
- Global CDN
|
||||
- Unlimited bandwidth
|
||||
- Edge functions
|
||||
- Preview deployments
|
||||
- Web Analytics
|
||||
- Fast performance
|
||||
|
||||
### Steps:
|
||||
|
||||
#### 1. Create `wrangler.toml` (for edge functions)
|
||||
```toml
|
||||
name = "odoo-pwa"
|
||||
compatibility_date = "2025-01-01"
|
||||
|
||||
[build]
|
||||
command = "npm run build"
|
||||
|
||||
[build.upload]
|
||||
format = "service-worker"
|
||||
```
|
||||
|
||||
#### 2. Convert API Routes to Workers
|
||||
|
||||
Create `functions/odoo.js`:
|
||||
```javascript
|
||||
export async function onRequest(context) {
|
||||
const { request, env } = context;
|
||||
|
||||
// Parse request
|
||||
const body = await request.json();
|
||||
|
||||
// Odoo logic here
|
||||
// Access env vars via env.ODOO_API_KEY
|
||||
|
||||
return new Response(JSON.stringify(result), {
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Deploy
|
||||
|
||||
**Option A: Cloudflare Dashboard**
|
||||
1. Go to Cloudflare Pages
|
||||
2. Connect Git repository
|
||||
3. Configure build:
|
||||
- Build command: `npm run build`
|
||||
- Output: `build` or `dist`
|
||||
4. Add environment variables
|
||||
5. Deploy
|
||||
|
||||
**Option B: Wrangler CLI**
|
||||
```bash
|
||||
npm install -g wrangler
|
||||
wrangler login
|
||||
wrangler pages project create odoo-pwa
|
||||
wrangler pages publish build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Add GitHub Pages Deployment 📘
|
||||
|
||||
### ⚠️ Limitations:
|
||||
- Static hosting only
|
||||
- No server-side API routes
|
||||
- Must modify Odoo client for direct API calls
|
||||
- CORS issues possible
|
||||
|
||||
### When to Use:
|
||||
- Demo projects
|
||||
- Public apps (no sensitive data)
|
||||
- Frontend-only versions
|
||||
|
||||
### Steps:
|
||||
|
||||
#### 1. Update Base Path
|
||||
|
||||
**SvelteKit** (`svelte.config.js`):
|
||||
```javascript
|
||||
const config = {
|
||||
kit: {
|
||||
adapter: adapter({
|
||||
pages: 'build',
|
||||
assets: 'build',
|
||||
fallback: 'index.html'
|
||||
}),
|
||||
paths: {
|
||||
base: process.env.NODE_ENV === 'production'
|
||||
? '/your-repo-name'
|
||||
: ''
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**React/Vue** (`vite.config.js`):
|
||||
```javascript
|
||||
export default {
|
||||
base: '/your-repo-name/'
|
||||
};
|
||||
```
|
||||
|
||||
#### 2. Create `.github/workflows/deploy.yml`
|
||||
```yaml
|
||||
name: Deploy to GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- run: npm install
|
||||
|
||||
- run: npm run build
|
||||
env:
|
||||
VITE_ODOO_URL: ${{ secrets.VITE_ODOO_URL }}
|
||||
VITE_ODOO_DB: ${{ secrets.VITE_ODOO_DB }}
|
||||
VITE_MODEL_NAME: ${{ secrets.VITE_MODEL_NAME }}
|
||||
|
||||
- uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: build
|
||||
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
|
||||
steps:
|
||||
- uses: actions/deploy-pages@v4
|
||||
```
|
||||
|
||||
#### 3. Configure Repository
|
||||
1. Go to Settings → Pages
|
||||
2. Source: GitHub Actions
|
||||
3. Save
|
||||
|
||||
#### 4. Add Secrets
|
||||
1. Settings → Secrets and variables → Actions
|
||||
2. Add each environment variable
|
||||
|
||||
#### 5. Push to Deploy
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Add GitHub Pages deployment"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables Reference
|
||||
|
||||
### Required for All Platforms:
|
||||
```bash
|
||||
# Public (VITE_ prefix for client access)
|
||||
VITE_ODOO_URL=https://yourcompany.odoo.com
|
||||
VITE_ODOO_DB=yourcompany-main
|
||||
VITE_MODEL_NAME=x_expense
|
||||
VITE_MODEL_DISPLAY_NAME=Expense
|
||||
|
||||
# Private (server-side only)
|
||||
ODOO_API_KEY=your_production_api_key
|
||||
ODOO_USERNAME=your.email@company.com
|
||||
```
|
||||
|
||||
### Platform-Specific:
|
||||
|
||||
**Vercel:**
|
||||
- Add in Project Settings → Environment Variables
|
||||
- Separate for Production/Preview/Development
|
||||
|
||||
**Netlify:**
|
||||
- Add in Site Settings → Environment Variables
|
||||
- Or in `netlify.toml`
|
||||
|
||||
**Cloudflare:**
|
||||
- Add in Pages → Settings → Environment Variables
|
||||
- Or use Wrangler secrets
|
||||
|
||||
**GitHub Pages:**
|
||||
- Add in Repository Settings → Secrets
|
||||
- Used in GitHub Actions workflow
|
||||
|
||||
---
|
||||
|
||||
## Post-Deployment Checklist ✅
|
||||
|
||||
After deploying to new platform:
|
||||
|
||||
```
|
||||
□ Build completed successfully
|
||||
□ Application loads at deployment URL
|
||||
□ Odoo connection works
|
||||
□ Data syncs correctly
|
||||
□ CRUD operations work
|
||||
□ Offline mode functions
|
||||
□ Service worker registered
|
||||
□ PWA installs correctly
|
||||
□ Environment variables set correctly
|
||||
□ No console errors
|
||||
□ Tested on mobile
|
||||
□ Custom domain configured (if needed)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Multi-Platform Deployment
|
||||
|
||||
### Deploy to Multiple Platforms:
|
||||
You can deploy the same app to multiple platforms for:
|
||||
- Redundancy
|
||||
- A/B testing
|
||||
- Different regions
|
||||
- Different audiences
|
||||
|
||||
### Example Setup:
|
||||
```
|
||||
main branch → Vercel (primary production)
|
||||
staging branch → Netlify (staging)
|
||||
PRs → Vercel preview deployments
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting Deployment
|
||||
|
||||
### Build Fails
|
||||
- Check build logs
|
||||
- Test `npm run build` locally
|
||||
- Verify Node version matches
|
||||
- Check for missing env vars
|
||||
|
||||
### App Loads but Doesn't Work
|
||||
- Check environment variables are set
|
||||
- Look at browser console errors
|
||||
- Verify API routes deployed correctly
|
||||
- Test Odoo connection
|
||||
|
||||
### API Routes Not Working
|
||||
- Verify platform supports server-side code
|
||||
- Check function logs
|
||||
- Ensure correct paths used
|
||||
- Test API endpoint directly
|
||||
|
||||
---
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/add-deployment` - Add new deployment target
|
||||
- User: "Deploy to Netlify"
|
||||
- User: "Add Cloudflare deployment"
|
||||
- User: "Set up continuous deployment"
|
||||
|
||||
## Related Commands:
|
||||
- `/deploy-vercel` - Deploy to Vercel
|
||||
- `/deploy-github` - Deploy to GitHub Pages
|
||||
- `/test-connection` - Test before deploying
|
||||
- `/optimize` - Optimize before production
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use Git-Based Deployment**
|
||||
- Automatic on push
|
||||
- Preview deployments
|
||||
- Easy rollbacks
|
||||
|
||||
2. **Separate Environments**
|
||||
- Development
|
||||
- Staging
|
||||
- Production
|
||||
|
||||
3. **Secure Secrets**
|
||||
- Never commit API keys
|
||||
- Use platform secret management
|
||||
- Rotate keys regularly
|
||||
|
||||
4. **Monitor Deployments**
|
||||
- Set up error tracking
|
||||
- Monitor performance
|
||||
- Watch build times
|
||||
|
||||
5. **Test Before Merging**
|
||||
- Use preview deployments
|
||||
- Test all features
|
||||
- Check on real devices
|
||||
46
commands/add-model.md
Normal file
46
commands/add-model.md
Normal file
@@ -0,0 +1,46 @@
|
||||
Add integration for a new Odoo Studio model to an existing PWA project.
|
||||
|
||||
## What this command does:
|
||||
- Invokes the `add-odoo-model` skill
|
||||
- Creates cache store for the new model
|
||||
- Adds API methods to the Odoo client
|
||||
- Generates form and list pages (optional)
|
||||
- Updates navigation and routing
|
||||
- Maintains consistency with existing project structure
|
||||
|
||||
## Required Information:
|
||||
Before starting, gather:
|
||||
1. **Current working directory** - Must be inside an existing Odoo PWA project
|
||||
2. **Framework** - Detect from project files (SvelteKit/React/Vue)
|
||||
3. **New model name** (without `x_` prefix, e.g., "task", "product")
|
||||
4. **Model display name** (human-readable, e.g., "Task", "Product")
|
||||
5. **Generate UI?** - Whether to create form and list pages (yes/no)
|
||||
|
||||
## Steps:
|
||||
1. Verify the current directory is an Odoo PWA project (check for odoo.js, cache stores)
|
||||
2. Detect the framework from project structure
|
||||
3. Ask the user for the new model details
|
||||
4. Create cache store for the model in `src/lib/stores/` or equivalent
|
||||
5. Update the Odoo API client with methods for the new model
|
||||
6. If requested, generate form and list pages/components
|
||||
7. Update navigation/routing if UI was generated
|
||||
8. Update documentation with the new model
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/add-model` - Interactive mode, will ask for all parameters
|
||||
- User: "Add a task model to my PWA"
|
||||
- User: "Integrate product catalog from Odoo"
|
||||
|
||||
## Validation:
|
||||
Before proceeding, check:
|
||||
- Project has `src/lib/odoo.js` or equivalent
|
||||
- Project has existing cache stores
|
||||
- `.env` file exists with Odoo configuration
|
||||
- Framework can be detected
|
||||
|
||||
## After adding model:
|
||||
Remind the user to:
|
||||
1. Update `.env` with any new model-specific configuration
|
||||
2. Test the new model's CRUD operations
|
||||
3. Verify sync functionality works correctly
|
||||
4. Update any necessary business logic or calculations
|
||||
734
commands/api-reference.md
Normal file
734
commands/api-reference.md
Normal file
@@ -0,0 +1,734 @@
|
||||
Complete API reference for the Odoo client and cache stores in generated PWAs.
|
||||
|
||||
## What this command does:
|
||||
- Provides comprehensive API documentation
|
||||
- Lists all available methods and functions
|
||||
- Shows parameter types and return values
|
||||
- Includes code examples for each method
|
||||
- Helps developers use the generated code effectively
|
||||
|
||||
---
|
||||
|
||||
## Odoo API Client Reference 🔌
|
||||
|
||||
The Odoo API client (`src/lib/odoo.js` or equivalent) provides methods for interacting with Odoo Studio models.
|
||||
|
||||
### Configuration
|
||||
|
||||
#### Environment Variables
|
||||
```bash
|
||||
VITE_ODOO_URL=https://yourcompany.odoo.com
|
||||
VITE_ODOO_DB=yourcompany-main
|
||||
ODOO_API_KEY=your_api_key
|
||||
ODOO_USERNAME=your.email@company.com
|
||||
VITE_MODEL_NAME=x_expense
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CRUD Operations
|
||||
|
||||
### createRecord()
|
||||
Create a new record in Odoo.
|
||||
|
||||
**Signature:**
|
||||
```javascript
|
||||
async function createRecord(model, fields)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `model` (string) - Odoo model name (e.g., 'x_expense')
|
||||
- `fields` (object) - Field values to set
|
||||
|
||||
**Returns:** Promise<number> - ID of created record
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
const newId = await odoo.createRecord('x_expense', {
|
||||
x_studio_description: 'Team lunch',
|
||||
x_studio_amount: 45.50,
|
||||
x_studio_date: '2025-01-15',
|
||||
x_studio_category: 'meal',
|
||||
x_studio_employee: odoo.formatMany2one(12)
|
||||
});
|
||||
|
||||
console.log(`Created expense with ID: ${newId}`);
|
||||
```
|
||||
|
||||
**Error Handling:**
|
||||
```javascript
|
||||
try {
|
||||
const id = await odoo.createRecord('x_expense', fields);
|
||||
} catch (error) {
|
||||
console.error('Failed to create:', error.message);
|
||||
// Handle error (show message to user, retry, etc.)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### searchRecords()
|
||||
Search and read records from Odoo.
|
||||
|
||||
**Signature:**
|
||||
```javascript
|
||||
async function searchRecords(model, domain, fields, limit = null, offset = null)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `model` (string) - Odoo model name
|
||||
- `domain` (array) - Odoo domain filter (e.g., [['id', '>', 100]])
|
||||
- `fields` (array) - List of field names to fetch
|
||||
- `limit` (number, optional) - Maximum number of records
|
||||
- `offset` (number, optional) - Number of records to skip
|
||||
|
||||
**Returns:** Promise<Array<Object>> - Array of record objects
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
// Get all expenses
|
||||
const allExpenses = await odoo.searchRecords(
|
||||
'x_expense',
|
||||
[],
|
||||
['x_studio_description', 'x_studio_amount', 'x_studio_date']
|
||||
);
|
||||
|
||||
// Get expenses > $100
|
||||
const largeExpenses = await odoo.searchRecords(
|
||||
'x_expense',
|
||||
[['x_studio_amount', '>', 100]],
|
||||
['x_studio_description', 'x_studio_amount']
|
||||
);
|
||||
|
||||
// Get recent 10 expenses
|
||||
const recentExpenses = await odoo.searchRecords(
|
||||
'x_expense',
|
||||
[],
|
||||
['x_studio_description', 'x_studio_date'],
|
||||
10 // limit
|
||||
);
|
||||
|
||||
// Get expenses with pagination
|
||||
const page2 = await odoo.searchRecords(
|
||||
'x_expense',
|
||||
[],
|
||||
fields,
|
||||
20, // limit: 20 per page
|
||||
20 // offset: skip first 20 (page 2)
|
||||
);
|
||||
```
|
||||
|
||||
**Domain Syntax:**
|
||||
```javascript
|
||||
// Equals
|
||||
[['x_studio_status', '=', 'draft']]
|
||||
|
||||
// Greater than
|
||||
[['x_studio_amount', '>', 100]]
|
||||
|
||||
// In list
|
||||
[['x_studio_category', 'in', ['meal', 'travel']]]
|
||||
|
||||
// Multiple conditions (AND)
|
||||
[
|
||||
['x_studio_amount', '>', 50],
|
||||
['x_studio_status', '=', 'draft']
|
||||
]
|
||||
|
||||
// OR conditions
|
||||
['|',
|
||||
['x_studio_amount', '>', 100],
|
||||
['x_studio_category', '=', 'travel']
|
||||
]
|
||||
|
||||
// Complex: (amount > 100 OR category = travel) AND status = draft
|
||||
['&',
|
||||
'|',
|
||||
['x_studio_amount', '>', 100],
|
||||
['x_studio_category', '=', 'travel'],
|
||||
['x_studio_status', '=', 'draft']
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### updateRecord()
|
||||
Update an existing record.
|
||||
|
||||
**Signature:**
|
||||
```javascript
|
||||
async function updateRecord(model, id, values)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `model` (string) - Odoo model name
|
||||
- `id` (number) - Record ID to update
|
||||
- `values` (object) - Fields to update
|
||||
|
||||
**Returns:** Promise<boolean> - true if successful
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
await odoo.updateRecord('x_expense', 123, {
|
||||
x_studio_status: 'approved',
|
||||
x_studio_amount: 55.00
|
||||
});
|
||||
|
||||
// Update multiple fields
|
||||
await odoo.updateRecord('x_expense', 123, {
|
||||
x_studio_description: 'Updated description',
|
||||
x_studio_date: '2025-01-20',
|
||||
x_studio_notes: 'Added receipt'
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### deleteRecord()
|
||||
Delete a record from Odoo.
|
||||
|
||||
**Signature:**
|
||||
```javascript
|
||||
async function deleteRecord(model, id)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `model` (string) - Odoo model name
|
||||
- `id` (number) - Record ID to delete
|
||||
|
||||
**Returns:** Promise<boolean> - true if successful
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
await odoo.deleteRecord('x_expense', 123);
|
||||
|
||||
// With confirmation
|
||||
if (confirm('Are you sure you want to delete this expense?')) {
|
||||
await odoo.deleteRecord('x_expense', expenseId);
|
||||
}
|
||||
```
|
||||
|
||||
**Error Handling:**
|
||||
```javascript
|
||||
try {
|
||||
await odoo.deleteRecord('x_expense', id);
|
||||
console.log('Deleted successfully');
|
||||
} catch (error) {
|
||||
console.error('Failed to delete:', error.message);
|
||||
alert('Could not delete: ' + error.message);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Helper Methods
|
||||
|
||||
### fetchPartners()
|
||||
Fetch partner (res.partner) records.
|
||||
|
||||
**Signature:**
|
||||
```javascript
|
||||
async function fetchPartners(ids = null)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `ids` (array, optional) - Specific partner IDs to fetch. If null, fetches all.
|
||||
|
||||
**Returns:** Promise<Array<Object>> - Array of partner objects
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
// Fetch all partners
|
||||
const allPartners = await odoo.fetchPartners();
|
||||
|
||||
// Fetch specific partners
|
||||
const somePartners = await odoo.fetchPartners([1, 2, 3]);
|
||||
|
||||
// Use in dropdown
|
||||
const partners = await odoo.fetchPartners();
|
||||
// Display: partners.map(p => ({ value: p.id, label: p.name }))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### formatMany2one()
|
||||
Format a Many2one field value for Odoo.
|
||||
|
||||
**Signature:**
|
||||
```javascript
|
||||
function formatMany2one(id)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `id` (number | null) - Partner/record ID
|
||||
|
||||
**Returns:** Array<number, boolean> | false - Odoo-formatted value
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
// Set employee field
|
||||
const fields = {
|
||||
x_studio_employee: odoo.formatMany2one(12)
|
||||
// Result: [12, false]
|
||||
};
|
||||
|
||||
// Clear employee field
|
||||
const fields = {
|
||||
x_studio_employee: odoo.formatMany2one(null)
|
||||
// Result: false
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### formatMany2many()
|
||||
Format a Many2many field value for Odoo.
|
||||
|
||||
**Signature:**
|
||||
```javascript
|
||||
function formatMany2many(ids)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `ids` (array) - Array of record IDs
|
||||
|
||||
**Returns:** Array - Odoo command format
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
// Set tags (replace all)
|
||||
const fields = {
|
||||
x_studio_tags: odoo.formatMany2many([1, 2, 3])
|
||||
// Result: [[6, 0, [1, 2, 3]]]
|
||||
};
|
||||
|
||||
// Clear tags
|
||||
const fields = {
|
||||
x_studio_tags: odoo.formatMany2many([])
|
||||
// Result: [[6, 0, []]]
|
||||
};
|
||||
```
|
||||
|
||||
**Odoo Many2many Commands:**
|
||||
```javascript
|
||||
// (6, 0, [ids]) - Replace all (what formatMany2many uses)
|
||||
// (4, id) - Add link to id
|
||||
// (3, id) - Remove link to id
|
||||
// (5, 0) - Remove all links
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cache Store API Reference 💾
|
||||
|
||||
The cache store provides reactive state management with offline-first capabilities.
|
||||
|
||||
### Properties
|
||||
|
||||
#### records
|
||||
**Type:** Reactive Array<Object>
|
||||
|
||||
Current cached records.
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
// SvelteKit
|
||||
$: totalAmount = $expenseCache.reduce((sum, e) => sum + e.x_studio_amount, 0);
|
||||
|
||||
// React
|
||||
const totalAmount = useMemo(() =>
|
||||
records.reduce((sum, e) => sum + e.x_studio_amount, 0),
|
||||
[records]
|
||||
);
|
||||
|
||||
// Vue
|
||||
const totalAmount = computed(() =>
|
||||
expenseStore.records.reduce((sum, e) => sum + e.x_studio_amount, 0)
|
||||
);
|
||||
```
|
||||
|
||||
#### isLoading
|
||||
**Type:** Reactive Boolean
|
||||
|
||||
Loading state indicator.
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
{#if $expenseCache.isLoading}
|
||||
<LoadingSpinner />
|
||||
{:else}
|
||||
<ExpenseList />
|
||||
{/if}
|
||||
```
|
||||
|
||||
#### error
|
||||
**Type:** Reactive String | null
|
||||
|
||||
Current error message, if any.
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
{#if $expenseCache.error}
|
||||
<ErrorAlert message={$expenseCache.error} />
|
||||
{/if}
|
||||
```
|
||||
|
||||
#### lastSync
|
||||
**Type:** Reactive Number (timestamp)
|
||||
|
||||
Timestamp of last successful sync.
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
const timeSinceSync = Date.now() - $expenseCache.lastSync;
|
||||
const minutes = Math.floor(timeSinceSync / 60000);
|
||||
// Display: "Last synced ${minutes} minutes ago"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Methods
|
||||
|
||||
### load()
|
||||
Load records from cache and trigger background sync.
|
||||
|
||||
**Signature:**
|
||||
```javascript
|
||||
async function load()
|
||||
```
|
||||
|
||||
**Returns:** Promise<void>
|
||||
|
||||
**Behavior:**
|
||||
1. Loads from cache immediately (instant UI update)
|
||||
2. Checks if cache is stale (> 5 minutes)
|
||||
3. If stale, syncs in background
|
||||
4. Updates UI when new data arrives
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
// SvelteKit
|
||||
$effect(() => {
|
||||
expenseCache.load();
|
||||
});
|
||||
|
||||
// React
|
||||
useEffect(() => {
|
||||
expenseCache.load();
|
||||
}, []);
|
||||
|
||||
// Vue
|
||||
onMounted(() => {
|
||||
expenseStore.load();
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### create()
|
||||
Create a new record with optimistic update.
|
||||
|
||||
**Signature:**
|
||||
```javascript
|
||||
async function create(data)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `data` (object) - Field values for new record
|
||||
|
||||
**Returns:** Promise<number> - ID of created record
|
||||
|
||||
**Behavior:**
|
||||
1. Generates temporary ID
|
||||
2. Adds to cache immediately (optimistic)
|
||||
3. Creates in Odoo (background)
|
||||
4. Replaces temp ID with real ID
|
||||
5. Rolls back on error
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
try {
|
||||
const newId = await expenseCache.create({
|
||||
x_studio_description: 'Lunch meeting',
|
||||
x_studio_amount: 45.50,
|
||||
x_studio_date: '2025-01-15',
|
||||
x_studio_category: 'meal'
|
||||
});
|
||||
|
||||
console.log('Created:', newId);
|
||||
navigate(`/expenses/${newId}`);
|
||||
} catch (error) {
|
||||
alert('Failed to create: ' + error.message);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### update()
|
||||
Update an existing record.
|
||||
|
||||
**Signature:**
|
||||
```javascript
|
||||
async function update(id, data)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `id` (number) - Record ID
|
||||
- `data` (object) - Fields to update
|
||||
|
||||
**Returns:** Promise<boolean>
|
||||
|
||||
**Behavior:**
|
||||
1. Updates cache immediately (optimistic)
|
||||
2. Updates in Odoo (background)
|
||||
3. Rolls back on error
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
await expenseCache.update(123, {
|
||||
x_studio_amount: 50.00,
|
||||
x_studio_status: 'submitted'
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### delete()
|
||||
Delete a record.
|
||||
|
||||
**Signature:**
|
||||
```javascript
|
||||
async function remove(id)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `id` (number) - Record ID to delete
|
||||
|
||||
**Returns:** Promise<boolean>
|
||||
|
||||
**Behavior:**
|
||||
1. Removes from cache immediately
|
||||
2. Deletes from Odoo (background)
|
||||
3. Restores on error
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
if (confirm('Delete this expense?')) {
|
||||
try {
|
||||
await expenseCache.remove(123);
|
||||
navigate('/expenses');
|
||||
} catch (error) {
|
||||
alert('Failed to delete: ' + error.message);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### refresh()
|
||||
Force refresh from Odoo.
|
||||
|
||||
**Signature:**
|
||||
```javascript
|
||||
async function refresh()
|
||||
```
|
||||
|
||||
**Returns:** Promise<void>
|
||||
|
||||
**Behavior:**
|
||||
1. Fetches all records from Odoo
|
||||
2. Replaces cache
|
||||
3. Updates UI
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
// Manual refresh button
|
||||
<button onclick={() => expenseCache.refresh()}>
|
||||
Refresh
|
||||
</button>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### clearCache()
|
||||
Clear all cached data.
|
||||
|
||||
**Signature:**
|
||||
```javascript
|
||||
function clearCache()
|
||||
```
|
||||
|
||||
**Returns:** void
|
||||
|
||||
**Behavior:**
|
||||
1. Clears localStorage
|
||||
2. Clears IndexedDB
|
||||
3. Resets records to empty array
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
// Logout function
|
||||
async function logout() {
|
||||
expenseCache.clearCache();
|
||||
// Clear other caches
|
||||
navigate('/login');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Advanced Patterns
|
||||
|
||||
### Custom Filters
|
||||
```javascript
|
||||
// Derived store (SvelteKit)
|
||||
import { derived } from 'svelte/store';
|
||||
|
||||
export const draftExpenses = derived(
|
||||
expenseCache,
|
||||
$cache => $cache.filter(e => e.x_studio_status === 'draft')
|
||||
);
|
||||
|
||||
// Hook (React)
|
||||
function useDraftExpenses() {
|
||||
const { records } = useExpense();
|
||||
return useMemo(
|
||||
() => records.filter(e => e.x_studio_status === 'draft'),
|
||||
[records]
|
||||
);
|
||||
}
|
||||
|
||||
// Computed (Vue)
|
||||
const draftExpenses = computed(() =>
|
||||
expenseStore.records.filter(e => e.x_studio_status === 'draft')
|
||||
);
|
||||
```
|
||||
|
||||
### Sorting
|
||||
```javascript
|
||||
export const sortedExpenses = derived(
|
||||
expenseCache,
|
||||
$cache => [...$cache].sort((a, b) =>
|
||||
b.x_studio_date.localeCompare(a.x_studio_date)
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
### Search
|
||||
```javascript
|
||||
function searchExpenses(query) {
|
||||
return records.filter(e =>
|
||||
e.x_studio_description.toLowerCase().includes(query.toLowerCase())
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Grouping
|
||||
```javascript
|
||||
function groupByCategory(records) {
|
||||
return records.reduce((groups, record) => {
|
||||
const category = record.x_studio_category;
|
||||
if (!groups[category]) groups[category] = [];
|
||||
groups[category].push(record);
|
||||
return groups;
|
||||
}, {});
|
||||
}
|
||||
```
|
||||
|
||||
### Aggregation
|
||||
```javascript
|
||||
function getTotalByCategory(records) {
|
||||
return records.reduce((totals, record) => {
|
||||
const cat = record.x_studio_category;
|
||||
totals[cat] = (totals[cat] || 0) + record.x_studio_amount;
|
||||
return totals;
|
||||
}, {});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Server Route API Reference 🔐
|
||||
|
||||
The server route (`src/routes/api/odoo/+server.js`) handles Odoo communication.
|
||||
|
||||
### Endpoint
|
||||
**URL:** `/api/odoo`
|
||||
**Method:** POST
|
||||
**Content-Type:** application/json
|
||||
|
||||
### Request Format
|
||||
```json
|
||||
{
|
||||
"action": "create|search|update|delete",
|
||||
"model": "x_expense",
|
||||
...parameters
|
||||
}
|
||||
```
|
||||
|
||||
### Actions
|
||||
|
||||
#### create
|
||||
```json
|
||||
{
|
||||
"action": "create",
|
||||
"model": "x_expense",
|
||||
"fields": {
|
||||
"x_studio_description": "Lunch",
|
||||
"x_studio_amount": 45.50
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:** `{ "id": 123 }`
|
||||
|
||||
#### search
|
||||
```json
|
||||
{
|
||||
"action": "search",
|
||||
"model": "x_expense",
|
||||
"domain": [["id", ">", 100]],
|
||||
"fields": ["x_studio_description", "x_studio_amount"]
|
||||
}
|
||||
```
|
||||
|
||||
**Response:** `{ "records": [...] }`
|
||||
|
||||
#### update
|
||||
```json
|
||||
{
|
||||
"action": "update",
|
||||
"model": "x_expense",
|
||||
"id": 123,
|
||||
"values": {
|
||||
"x_studio_amount": 50.00
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:** `{ "success": true }`
|
||||
|
||||
#### delete
|
||||
```json
|
||||
{
|
||||
"action": "delete",
|
||||
"model": "x_expense",
|
||||
"id": 123
|
||||
}
|
||||
```
|
||||
|
||||
**Response:** `{ "success": true }`
|
||||
|
||||
---
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/api-reference` - Show complete API documentation
|
||||
- User: "What methods are available in the Odoo client?"
|
||||
- User: "How do I use the cache store?"
|
||||
- User: "Show me API examples"
|
||||
|
||||
## Next Steps:
|
||||
- Try the methods in your project
|
||||
- Review `/examples` for practical use cases
|
||||
- See `/architecture` for design patterns
|
||||
- Check `/help` for more information
|
||||
634
commands/architecture.md
Normal file
634
commands/architecture.md
Normal file
@@ -0,0 +1,634 @@
|
||||
Detailed explanation of the Odoo PWA architecture, patterns, and design decisions.
|
||||
|
||||
## What this command does:
|
||||
- Explains the architectural patterns used in generated PWAs
|
||||
- Details the data flow and state management
|
||||
- Describes the caching strategy
|
||||
- Explains offline-first design principles
|
||||
- Provides insights into technical decisions
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview 🏗️
|
||||
|
||||
The Odoo PWA Generator creates **offline-first Progressive Web Apps** with a **three-layer architecture** that ensures data availability, performance, and seamless Odoo integration.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ UI Layer (Components) │
|
||||
│ - Forms, Lists, Navigation │
|
||||
│ - Framework-specific (Svelte/React/Vue)│
|
||||
└──────────────┬──────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ State Layer (Cache Stores) │
|
||||
│ - Smart Caching Logic │
|
||||
│ - Dual Storage (localStorage + IndexedDB) │
|
||||
│ - Background Sync │
|
||||
│ - Optimistic Updates │
|
||||
└──────────────┬──────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ API Layer (Odoo Client) │
|
||||
│ - JSON-RPC Communication │
|
||||
│ - CRUD Operations │
|
||||
│ - Field Formatting │
|
||||
└──────────────┬──────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Server Layer (API Routes) │
|
||||
│ - Credential Management │
|
||||
│ - UID Caching │
|
||||
│ - Error Handling │
|
||||
└──────────────┬──────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Odoo Backend │
|
||||
│ - Studio Models │
|
||||
│ - Business Logic │
|
||||
│ - Data Persistence │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Layer 1: UI Components 🎨
|
||||
|
||||
### Purpose:
|
||||
Present data to users and capture user input.
|
||||
|
||||
### Responsibilities:
|
||||
- Render data from cache stores
|
||||
- Handle user interactions
|
||||
- Validate form inputs
|
||||
- Display loading and error states
|
||||
- Provide responsive, mobile-friendly interface
|
||||
|
||||
### Framework-Specific Implementation:
|
||||
|
||||
#### SvelteKit
|
||||
```javascript
|
||||
<script>
|
||||
import { expenseCache } from '$lib/stores/expenseCache';
|
||||
|
||||
// Reactive to cache updates
|
||||
$effect(() => {
|
||||
expenseCache.load();
|
||||
});
|
||||
</script>
|
||||
|
||||
{#each $expenseCache as expense}
|
||||
<ExpenseCard {expense} />
|
||||
{/each}
|
||||
```
|
||||
|
||||
#### React
|
||||
```javascript
|
||||
import { useExpense } from './contexts/ExpenseContext';
|
||||
|
||||
function ExpenseList() {
|
||||
const { records, isLoading } = useExpense();
|
||||
|
||||
useEffect(() => {
|
||||
// Load on mount
|
||||
}, []);
|
||||
|
||||
return records.map(expense => (
|
||||
<ExpenseCard key={expense.id} expense={expense} />
|
||||
));
|
||||
}
|
||||
```
|
||||
|
||||
#### Vue
|
||||
```javascript
|
||||
<script setup>
|
||||
import { useExpenseStore } from '@/stores/expenseStore';
|
||||
|
||||
const expenseStore = useExpenseStore();
|
||||
expenseStore.load();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ExpenseCard
|
||||
v-for="expense in expenseStore.records"
|
||||
:key="expense.id"
|
||||
:expense="expense"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
### Design Principles:
|
||||
- **Reactive by default** - UI updates automatically when data changes
|
||||
- **Loading states** - Show skeleton loaders while data fetches
|
||||
- **Error boundaries** - Graceful error handling
|
||||
- **Optimistic UI** - Show changes immediately, sync in background
|
||||
|
||||
---
|
||||
|
||||
## Layer 2: Cache Stores (State Management) 💾
|
||||
|
||||
### Purpose:
|
||||
Manage application state with offline-first caching.
|
||||
|
||||
### The Smart Caching Pattern:
|
||||
|
||||
```javascript
|
||||
// Two-phase load strategy
|
||||
export async function load() {
|
||||
// Phase 1: Load from cache (instant)
|
||||
const cached = await loadFromCache();
|
||||
records.set(cached); // UI shows data immediately
|
||||
|
||||
// Phase 2: Check if stale and sync
|
||||
if (isCacheStale()) {
|
||||
await syncInBackground(); // Update in background
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Dual Storage Strategy:
|
||||
|
||||
#### localStorage (Metadata)
|
||||
Stores lightweight metadata:
|
||||
- `lastSyncTime` - When was last successful sync
|
||||
- `lastRecordId` - Highest ID fetched so far
|
||||
- `version` - Cache schema version
|
||||
|
||||
```javascript
|
||||
localStorage.setItem('expenseCache', JSON.stringify({
|
||||
lastSyncTime: Date.now(),
|
||||
lastRecordId: 123,
|
||||
version: 1
|
||||
}));
|
||||
```
|
||||
|
||||
#### IndexedDB (Master Data)
|
||||
Stores actual records:
|
||||
- All record data
|
||||
- Larger storage capacity
|
||||
- Async API
|
||||
- Structured data
|
||||
|
||||
```javascript
|
||||
await db.expenses.bulkPut(records);
|
||||
```
|
||||
|
||||
### Stale Detection:
|
||||
|
||||
```javascript
|
||||
function isCacheStale() {
|
||||
const cacheData = JSON.parse(localStorage.getItem('expenseCache'));
|
||||
const CACHE_VALIDITY = 5 * 60 * 1000; // 5 minutes
|
||||
|
||||
return !cacheData ||
|
||||
(Date.now() - cacheData.lastSyncTime) > CACHE_VALIDITY;
|
||||
}
|
||||
```
|
||||
|
||||
### Incremental Sync Pattern:
|
||||
|
||||
```javascript
|
||||
// Only fetch new records, not everything
|
||||
async function syncInBackground() {
|
||||
const { lastRecordId } = getCacheMetadata();
|
||||
|
||||
// Fetch only records with id > lastRecordId
|
||||
const newRecords = await odoo.searchRecords(
|
||||
'x_expense',
|
||||
[['id', '>', lastRecordId]],
|
||||
fields
|
||||
);
|
||||
|
||||
if (newRecords.length > 0) {
|
||||
await appendToCache(newRecords);
|
||||
updateLastRecordId(newRecords[newRecords.length - 1].id);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Optimistic Updates:
|
||||
|
||||
```javascript
|
||||
export async function create(data) {
|
||||
// 1. Generate temporary ID
|
||||
const tempId = `temp-${Date.now()}`;
|
||||
const tempRecord = { id: tempId, ...data };
|
||||
|
||||
// 2. Update UI immediately
|
||||
records.update(r => [...r, tempRecord]);
|
||||
|
||||
// 3. Create in Odoo (background)
|
||||
try {
|
||||
const realId = await odoo.createRecord('x_expense', data);
|
||||
|
||||
// 4. Replace temp ID with real ID
|
||||
records.update(r =>
|
||||
r.map(rec => rec.id === tempId ? { ...rec, id: realId } : rec)
|
||||
);
|
||||
} catch (error) {
|
||||
// 5. Rollback on error
|
||||
records.update(r => r.filter(rec => rec.id !== tempId));
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Background Sync Timer:
|
||||
|
||||
```javascript
|
||||
let syncInterval;
|
||||
|
||||
export function startAutoSync() {
|
||||
syncInterval = setInterval(() => {
|
||||
syncInBackground();
|
||||
}, 3 * 60 * 1000); // Every 3 minutes
|
||||
}
|
||||
|
||||
export function stopAutoSync() {
|
||||
clearInterval(syncInterval);
|
||||
}
|
||||
```
|
||||
|
||||
### Partner Resolution Pattern:
|
||||
|
||||
```javascript
|
||||
// Many2one fields return [id, name] or just id
|
||||
// Resolve partner names and cache them
|
||||
|
||||
async function resolvePartnerNames(records) {
|
||||
const partnerIds = new Set();
|
||||
|
||||
// Collect all unique partner IDs
|
||||
records.forEach(record => {
|
||||
if (record.x_studio_employee) {
|
||||
if (Array.isArray(record.x_studio_employee)) {
|
||||
partnerIds.add(record.x_studio_employee[0]);
|
||||
} else {
|
||||
partnerIds.add(record.x_studio_employee);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Fetch partner names in batch
|
||||
const partners = await odoo.fetchPartners(Array.from(partnerIds));
|
||||
const partnerMap = new Map(partners.map(p => [p.id, p.name]));
|
||||
|
||||
// Cache for future use
|
||||
localStorage.setItem('partnerCache', JSON.stringify(
|
||||
Array.from(partnerMap.entries())
|
||||
));
|
||||
|
||||
return partnerMap;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Layer 3: API Client (Odoo Communication) 🔌
|
||||
|
||||
### Purpose:
|
||||
Abstract Odoo API communication with clean, reusable methods.
|
||||
|
||||
### JSON-RPC Communication:
|
||||
|
||||
```javascript
|
||||
async function jsonRpc(url, params) {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
method: 'call',
|
||||
params: params,
|
||||
id: Math.random()
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.error) {
|
||||
throw new Error(data.error.message);
|
||||
}
|
||||
|
||||
return data.result;
|
||||
}
|
||||
```
|
||||
|
||||
### CRUD Methods:
|
||||
|
||||
#### Create
|
||||
```javascript
|
||||
export async function createRecord(model, fields) {
|
||||
return await fetch('/api/odoo', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'create',
|
||||
model,
|
||||
fields
|
||||
})
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### Read
|
||||
```javascript
|
||||
export async function searchRecords(model, domain, fields) {
|
||||
return await fetch('/api/odoo', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'search',
|
||||
model,
|
||||
domain,
|
||||
fields
|
||||
})
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### Update
|
||||
```javascript
|
||||
export async function updateRecord(model, id, values) {
|
||||
return await fetch('/api/odoo', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'update',
|
||||
model,
|
||||
id,
|
||||
values
|
||||
})
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### Delete
|
||||
```javascript
|
||||
export async function deleteRecord(model, id) {
|
||||
return await fetch('/api/odoo', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'delete',
|
||||
model,
|
||||
id
|
||||
})
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Field Formatting Helpers:
|
||||
|
||||
```javascript
|
||||
// Many2one: Convert to Odoo format [id, false]
|
||||
export function formatMany2one(id) {
|
||||
return id ? [id, false] : false;
|
||||
}
|
||||
|
||||
// Many2many: Convert to Odoo command [(6, 0, [ids])]
|
||||
export function formatMany2many(ids) {
|
||||
return ids && ids.length > 0 ? [[6, 0, ids]] : [[6, 0, []]];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Layer 4: Server Routes (API Proxy) 🔐
|
||||
|
||||
### Purpose:
|
||||
Securely handle Odoo authentication and proxy requests.
|
||||
|
||||
### Why Server-Side?
|
||||
1. **Security** - API keys never exposed to client
|
||||
2. **CORS** - Bypass cross-origin restrictions
|
||||
3. **Caching** - Cache UIDs to reduce auth calls
|
||||
4. **Error Handling** - Centralized error management
|
||||
|
||||
### UID Caching Pattern:
|
||||
|
||||
```javascript
|
||||
let cachedUid = null;
|
||||
|
||||
async function authenticate() {
|
||||
if (cachedUid) {
|
||||
return cachedUid;
|
||||
}
|
||||
|
||||
// Authenticate with Odoo
|
||||
cachedUid = await odooClient.authenticate(
|
||||
db, username, apiKey
|
||||
);
|
||||
|
||||
return cachedUid;
|
||||
}
|
||||
```
|
||||
|
||||
### Action Routing:
|
||||
|
||||
```javascript
|
||||
export async function POST({ request }) {
|
||||
const { action, model, ...params } = await request.json();
|
||||
const uid = await authenticate();
|
||||
|
||||
switch (action) {
|
||||
case 'create':
|
||||
return odooClient.create(model, params.fields);
|
||||
case 'search':
|
||||
return odooClient.searchRead(model, params.domain, params.fields);
|
||||
case 'update':
|
||||
return odooClient.write(model, params.id, params.values);
|
||||
case 'delete':
|
||||
return odooClient.unlink(model, params.id);
|
||||
default:
|
||||
throw new Error(`Unknown action: ${action}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Flow Examples 🔄
|
||||
|
||||
### Example 1: Loading Data on Page Load
|
||||
|
||||
```
|
||||
1. User navigates to page
|
||||
↓
|
||||
2. Component calls expenseCache.load()
|
||||
↓
|
||||
3. Cache store loads from localStorage/IndexedDB
|
||||
↓
|
||||
4. UI updates with cached data (instant)
|
||||
↓
|
||||
5. Cache checks if data is stale (> 5 min)
|
||||
↓
|
||||
6. If stale, triggers background sync
|
||||
↓
|
||||
7. API client calls /api/odoo
|
||||
↓
|
||||
8. Server authenticates and calls Odoo
|
||||
↓
|
||||
9. New records returned
|
||||
↓
|
||||
10. Cache updated (localStorage + IndexedDB)
|
||||
↓
|
||||
11. UI reactively updates with new data
|
||||
```
|
||||
|
||||
### Example 2: Creating a Record
|
||||
|
||||
```
|
||||
1. User submits form
|
||||
↓
|
||||
2. Component calls expenseCache.create(data)
|
||||
↓
|
||||
3. Cache creates temp record with temp-ID
|
||||
↓
|
||||
4. UI updates immediately (optimistic)
|
||||
↓
|
||||
5. API client calls /api/odoo (background)
|
||||
↓
|
||||
6. Server creates record in Odoo
|
||||
↓
|
||||
7. Real ID returned
|
||||
↓
|
||||
8. Cache replaces temp-ID with real ID
|
||||
↓
|
||||
9. localStorage and IndexedDB updated
|
||||
↓
|
||||
10. UI shows success message
|
||||
```
|
||||
|
||||
### Example 3: Offline Create → Online Sync
|
||||
|
||||
```
|
||||
1. User creates record (offline)
|
||||
↓
|
||||
2. Record saved to cache with temp-ID
|
||||
↓
|
||||
3. API call fails (no network)
|
||||
↓
|
||||
4. Record marked as "pending sync"
|
||||
↓
|
||||
5. UI shows "Will sync when online"
|
||||
↓
|
||||
[User goes online]
|
||||
↓
|
||||
6. Background sync detects pending records
|
||||
↓
|
||||
7. Retries API call
|
||||
↓
|
||||
8. Success! Real ID received
|
||||
↓
|
||||
9. Cache updated
|
||||
↓
|
||||
10. UI shows "Synced" status
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Design Patterns 🎯
|
||||
|
||||
### 1. Offline-First
|
||||
- Always load from cache first
|
||||
- Sync in background
|
||||
- Queue operations when offline
|
||||
- Retry on reconnection
|
||||
|
||||
### 2. Optimistic UI
|
||||
- Update UI immediately
|
||||
- Sync with server in background
|
||||
- Rollback on error
|
||||
- Show pending states
|
||||
|
||||
### 3. Incremental Sync
|
||||
- Don't re-fetch all data
|
||||
- Only fetch new records (id > lastRecordId)
|
||||
- Reduces bandwidth
|
||||
- Faster sync times
|
||||
|
||||
### 4. Dual Storage
|
||||
- localStorage for metadata (fast)
|
||||
- IndexedDB for data (large)
|
||||
- Best of both worlds
|
||||
|
||||
### 5. Partner Resolution
|
||||
- Batch fetch related records
|
||||
- Cache partner names
|
||||
- Avoid N+1 queries
|
||||
- Display human-readable names
|
||||
|
||||
### 6. Reactive State
|
||||
- Framework-native reactivity
|
||||
- UI updates automatically
|
||||
- No manual DOM manipulation
|
||||
- Cleaner code
|
||||
|
||||
---
|
||||
|
||||
## Performance Considerations ⚡
|
||||
|
||||
### Initial Load:
|
||||
- Cache-first: Instant data display
|
||||
- Background sync: Fetch updates without blocking
|
||||
- IndexedDB: Fast access to large datasets
|
||||
|
||||
### Network Usage:
|
||||
- Incremental sync: Only new data
|
||||
- Batch operations: Combine requests
|
||||
- UID caching: Reduce auth calls
|
||||
|
||||
### Memory Usage:
|
||||
- Store large data in IndexedDB, not memory
|
||||
- Clean up old data periodically
|
||||
- Lazy load related data
|
||||
|
||||
### Bundle Size:
|
||||
- Framework-specific optimizations
|
||||
- Tree shaking
|
||||
- Code splitting
|
||||
- Lazy load routes
|
||||
|
||||
---
|
||||
|
||||
## Security Patterns 🔒
|
||||
|
||||
### Credential Management:
|
||||
- API keys in environment variables
|
||||
- Server-side authentication
|
||||
- Never expose keys to client
|
||||
- Rotate keys periodically
|
||||
|
||||
### Data Validation:
|
||||
- Validate on client (UX)
|
||||
- Validate on server (security)
|
||||
- Sanitize inputs
|
||||
- Check permissions
|
||||
|
||||
### Error Handling:
|
||||
- Don't expose internal errors to user
|
||||
- Log errors securely
|
||||
- Graceful degradation
|
||||
- User-friendly messages
|
||||
|
||||
---
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/architecture` - Show architecture details
|
||||
- User: "How does the caching work?"
|
||||
- User: "Explain the data flow"
|
||||
- User: "What design patterns are used?"
|
||||
|
||||
## Next Steps:
|
||||
After understanding the architecture:
|
||||
1. Review generated code in your project
|
||||
2. Read CLAUDE.md in your project for specific details
|
||||
3. Customize patterns for your use case
|
||||
4. Optimize for your specific needs
|
||||
|
||||
For more information, see `/help` or `/examples`!
|
||||
597
commands/clear-cache.md
Normal file
597
commands/clear-cache.md
Normal file
@@ -0,0 +1,597 @@
|
||||
Clear all cached data from your Odoo PWA application.
|
||||
|
||||
## What this command does:
|
||||
- Clears localStorage cache
|
||||
- Clears IndexedDB data
|
||||
- Clears browser cache
|
||||
- Resets service worker cache
|
||||
- Forces fresh data fetch from Odoo
|
||||
- Provides selective clearing options
|
||||
|
||||
## When to Use This Command
|
||||
|
||||
### ✅ Good Reasons:
|
||||
- Data appears corrupted or inconsistent
|
||||
- Testing fresh installation
|
||||
- After Odoo schema changes
|
||||
- Debugging sync issues
|
||||
- After major updates
|
||||
- Stuck with old data
|
||||
|
||||
### ⚠️ Caution:
|
||||
- Clears all offline data
|
||||
- May lose unsyncedchanges
|
||||
- Requires re-download of all data
|
||||
- User will need to be online
|
||||
|
||||
---
|
||||
|
||||
## Quick Clear Options
|
||||
|
||||
### Option 1: Clear from Browser Console (Fastest)
|
||||
```javascript
|
||||
// Clear localStorage
|
||||
localStorage.clear();
|
||||
|
||||
// Clear and refresh
|
||||
localStorage.clear();
|
||||
location.reload();
|
||||
```
|
||||
|
||||
### Option 2: Clear from Cache Store
|
||||
```javascript
|
||||
// Using cache store method
|
||||
expenseCache.clearCache();
|
||||
expenseCache.refresh();
|
||||
```
|
||||
|
||||
### Option 3: Clear from UI
|
||||
Add a button to your app:
|
||||
```javascript
|
||||
<button onclick={() => {
|
||||
if (confirm('Clear all cached data?')) {
|
||||
expenseCache.clearCache();
|
||||
expenseCache.refresh();
|
||||
}
|
||||
}}>
|
||||
Clear Cache
|
||||
</button>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Clear Procedure
|
||||
|
||||
### Step 1: Prepare
|
||||
```
|
||||
□ Save any unsaved work
|
||||
□ Ensure internet connection
|
||||
□ Note current state (for comparison)
|
||||
□ Close other tabs with same app
|
||||
```
|
||||
|
||||
### Step 2: Clear localStorage
|
||||
```javascript
|
||||
// Clear all
|
||||
localStorage.clear();
|
||||
|
||||
// Or clear specific keys
|
||||
localStorage.removeItem('expenseCache');
|
||||
localStorage.removeItem('taskCache');
|
||||
localStorage.removeItem('partnerCache');
|
||||
```
|
||||
|
||||
### Step 3: Clear IndexedDB
|
||||
```javascript
|
||||
// Via DevTools:
|
||||
// 1. Open DevTools (F12)
|
||||
// 2. Go to Application tab
|
||||
// 3. Expand IndexedDB in left sidebar
|
||||
// 4. Right-click on database → Delete
|
||||
|
||||
// Or programmatically:
|
||||
indexedDB.deleteDatabase('odoo-pwa-db');
|
||||
```
|
||||
|
||||
### Step 4: Clear Service Worker Cache
|
||||
```javascript
|
||||
// Unregister service worker
|
||||
navigator.serviceWorker.getRegistrations()
|
||||
.then(registrations => {
|
||||
registrations.forEach(reg => reg.unregister());
|
||||
});
|
||||
|
||||
// Clear all caches
|
||||
caches.keys()
|
||||
.then(keys => Promise.all(
|
||||
keys.map(key => caches.delete(key))
|
||||
));
|
||||
```
|
||||
|
||||
### Step 5: Clear Browser Cache
|
||||
```
|
||||
Chrome/Edge: Ctrl+Shift+Delete → Select cache → Clear
|
||||
Firefox: Ctrl+Shift+Delete → Select cache → Clear now
|
||||
Safari: Cmd+Option+E
|
||||
```
|
||||
|
||||
### Step 6: Hard Refresh
|
||||
```
|
||||
Windows/Linux: Ctrl+Shift+R or Ctrl+F5
|
||||
Mac: Cmd+Shift+R
|
||||
```
|
||||
|
||||
### Step 7: Verify
|
||||
```javascript
|
||||
// Check localStorage is empty
|
||||
console.log('localStorage size:', localStorage.length);
|
||||
|
||||
// Check IndexedDB
|
||||
// DevTools → Application → IndexedDB
|
||||
// Should be empty or recreated
|
||||
|
||||
// Check cache stores
|
||||
console.log('Records:', $expenseCache.length);
|
||||
// Should be 0 or freshly fetched
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Selective Clearing
|
||||
|
||||
### Clear Only Specific Model Cache
|
||||
```javascript
|
||||
// Clear just expense cache
|
||||
localStorage.removeItem('expenseCache');
|
||||
|
||||
// Refresh that cache
|
||||
expenseCache.refresh();
|
||||
```
|
||||
|
||||
### Clear Only Metadata (Keep Records)
|
||||
```javascript
|
||||
// Get current cache data
|
||||
const cacheData = JSON.parse(localStorage.getItem('expenseCache'));
|
||||
|
||||
// Reset only metadata
|
||||
cacheData.lastSyncTime = 0;
|
||||
cacheData.lastRecordId = 0;
|
||||
|
||||
// Save back
|
||||
localStorage.setItem('expenseCache', JSON.stringify(cacheData));
|
||||
|
||||
// Force sync
|
||||
expenseCache.refresh();
|
||||
```
|
||||
|
||||
### Clear Only Old Records
|
||||
```javascript
|
||||
// Keep only recent records (last 30 days)
|
||||
const thirtyDaysAgo = new Date();
|
||||
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
|
||||
|
||||
expenseCache.records.update(records =>
|
||||
records.filter(r => new Date(r.x_studio_date) > thirtyDaysAgo)
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Framework-Specific Clearing
|
||||
|
||||
### SvelteKit
|
||||
```javascript
|
||||
// Clear and reset store
|
||||
import { expenseCache } from '$lib/stores/expenseCache';
|
||||
|
||||
expenseCache.clearCache();
|
||||
expenseCache.load(); // Reload fresh data
|
||||
```
|
||||
|
||||
### React
|
||||
```javascript
|
||||
// Using Context
|
||||
import { useExpense } from './contexts/ExpenseContext';
|
||||
|
||||
function ClearCacheButton() {
|
||||
const { clearCache, refresh } = useExpense();
|
||||
|
||||
return (
|
||||
<button onClick={() => {
|
||||
clearCache();
|
||||
refresh();
|
||||
}}>
|
||||
Clear Cache
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Vue
|
||||
```javascript
|
||||
// Using Pinia store
|
||||
import { useExpenseStore } from '@/stores/expenseStore';
|
||||
|
||||
const expenseStore = useExpenseStore();
|
||||
|
||||
function clearAndRefresh() {
|
||||
expenseStore.clearCache();
|
||||
expenseStore.load();
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Advanced Cache Management
|
||||
|
||||
### Schedule Automatic Cache Clear
|
||||
```javascript
|
||||
// Clear cache older than 7 days
|
||||
const CACHE_MAX_AGE = 7 * 24 * 60 * 60 * 1000; // 7 days
|
||||
|
||||
function checkCacheAge() {
|
||||
const cacheData = JSON.parse(localStorage.getItem('expenseCache'));
|
||||
|
||||
if (cacheData && cacheData.lastSyncTime) {
|
||||
const age = Date.now() - cacheData.lastSyncTime;
|
||||
|
||||
if (age > CACHE_MAX_AGE) {
|
||||
console.log('Cache too old, clearing...');
|
||||
expenseCache.clearCache();
|
||||
expenseCache.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check on app load
|
||||
checkCacheAge();
|
||||
```
|
||||
|
||||
### Clear on Version Change
|
||||
```javascript
|
||||
// In cache store
|
||||
const CACHE_VERSION = 2; // Increment when schema changes
|
||||
|
||||
function checkCacheVersion() {
|
||||
const cacheData = JSON.parse(localStorage.getItem('expenseCache'));
|
||||
|
||||
if (!cacheData || cacheData.version !== CACHE_VERSION) {
|
||||
console.log('Cache version mismatch, clearing...');
|
||||
clearCache();
|
||||
|
||||
// Set new version
|
||||
localStorage.setItem('expenseCache', JSON.stringify({
|
||||
version: CACHE_VERSION,
|
||||
lastSyncTime: 0,
|
||||
lastRecordId: 0
|
||||
}));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Clear Based on Storage Quota
|
||||
```javascript
|
||||
// Check storage usage
|
||||
if (navigator.storage && navigator.storage.estimate) {
|
||||
navigator.storage.estimate().then(estimate => {
|
||||
const percentUsed = (estimate.usage / estimate.quota) * 100;
|
||||
|
||||
console.log(`Storage: ${percentUsed.toFixed(2)}% used`);
|
||||
|
||||
if (percentUsed > 90) {
|
||||
console.warn('Storage almost full, clearing old cache...');
|
||||
clearOldestRecords();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function clearOldestRecords() {
|
||||
// Keep only most recent 100 records
|
||||
expenseCache.records.update(records =>
|
||||
records
|
||||
.sort((a, b) => b.id - a.id)
|
||||
.slice(0, 100)
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cache Verification
|
||||
|
||||
### After Clearing, Verify:
|
||||
|
||||
#### 1. Storage is Empty
|
||||
```javascript
|
||||
console.log('localStorage keys:', Object.keys(localStorage));
|
||||
// Should be [] or minimal
|
||||
|
||||
console.log('localStorage size:', localStorage.length);
|
||||
// Should be 0 or very small
|
||||
```
|
||||
|
||||
#### 2. IndexedDB is Clear
|
||||
```
|
||||
DevTools → Application → IndexedDB
|
||||
- Check if database exists
|
||||
- Check if tables are empty
|
||||
```
|
||||
|
||||
#### 3. Fresh Data Loads
|
||||
```javascript
|
||||
// Refresh and watch console
|
||||
location.reload();
|
||||
|
||||
// Should see:
|
||||
// "Cache miss, fetching from Odoo..."
|
||||
// "Fetched X records"
|
||||
```
|
||||
|
||||
#### 4. Functionality Works
|
||||
```
|
||||
□ Data loads correctly
|
||||
□ CRUD operations work
|
||||
□ Sync happens
|
||||
□ Offline mode works after re-caching
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting Clear Issues
|
||||
|
||||
### Issue: Cache Won't Clear
|
||||
|
||||
**Solution 1: Force with DevTools**
|
||||
```
|
||||
1. Open DevTools (F12)
|
||||
2. Application tab
|
||||
3. Clear storage section
|
||||
4. Check all boxes
|
||||
5. Click "Clear site data"
|
||||
```
|
||||
|
||||
**Solution 2: Use Private/Incognito**
|
||||
```
|
||||
Open app in private browsing mode
|
||||
- Fresh session, no cache
|
||||
- Test functionality
|
||||
```
|
||||
|
||||
**Solution 3: Different Browser**
|
||||
```
|
||||
Test in different browser
|
||||
- Rules out browser-specific issues
|
||||
```
|
||||
|
||||
### Issue: Data Reappears After Clear
|
||||
|
||||
**Solution: Check Multiple Sources**
|
||||
```javascript
|
||||
// Clear all possible locations
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
indexedDB.deleteDatabase('odoo-pwa-db');
|
||||
|
||||
// Unregister service workers
|
||||
navigator.serviceWorker.getRegistrations()
|
||||
.then(regs => regs.forEach(reg => reg.unregister()));
|
||||
|
||||
// Clear all caches
|
||||
caches.keys()
|
||||
.then(keys => Promise.all(keys.map(k => caches.delete(k))));
|
||||
```
|
||||
|
||||
### Issue: App Breaks After Clear
|
||||
|
||||
**Solution: Ensure Graceful Degradation**
|
||||
```javascript
|
||||
// In cache store, handle missing cache
|
||||
function loadFromCache() {
|
||||
try {
|
||||
const cached = localStorage.getItem('expenseCache');
|
||||
|
||||
if (!cached) {
|
||||
console.log('No cache, will fetch from Odoo');
|
||||
return { records: [], lastRecordId: 0, lastSyncTime: 0 };
|
||||
}
|
||||
|
||||
return JSON.parse(cached);
|
||||
} catch (error) {
|
||||
console.error('Error loading cache:', error);
|
||||
return { records: [], lastRecordId: 0, lastSyncTime: 0 };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## User-Facing Clear Options
|
||||
|
||||
### Settings Page Example
|
||||
```javascript
|
||||
<script>
|
||||
import { expenseCache, taskCache } from '$lib/stores';
|
||||
|
||||
async function clearAll() {
|
||||
if (confirm('Clear all cached data? This cannot be undone.')) {
|
||||
expenseCache.clearCache();
|
||||
taskCache.clearCache();
|
||||
|
||||
alert('Cache cleared! Refreshing...');
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
async function clearExpenses() {
|
||||
if (confirm('Clear expense cache?')) {
|
||||
expenseCache.clearCache();
|
||||
await expenseCache.refresh();
|
||||
alert('Expense cache cleared!');
|
||||
}
|
||||
}
|
||||
|
||||
function getCacheInfo() {
|
||||
const size = new Blob(Object.values(localStorage)).size;
|
||||
const sizeKB = (size / 1024).toFixed(2);
|
||||
return { count: localStorage.length, sizeKB };
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="settings">
|
||||
<h2>Cache Management</h2>
|
||||
|
||||
<div class="cache-info">
|
||||
<p>Items: {getCacheInfo().count}</p>
|
||||
<p>Size: {getCacheInfo().sizeKB} KB</p>
|
||||
<p>Last sync: {new Date($expenseCache.lastSync).toLocaleString()}</p>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button on:click={clearExpenses}>Clear Expense Cache</button>
|
||||
<button on:click={clearAll} class="danger">Clear All Cache</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.danger {
|
||||
background: red;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cache Clear Checklist ✅
|
||||
|
||||
Before clearing:
|
||||
```
|
||||
□ Save any unsaved work
|
||||
□ Note current state
|
||||
□ Ensure internet connection
|
||||
□ Close duplicate tabs
|
||||
```
|
||||
|
||||
After clearing:
|
||||
```
|
||||
□ localStorage is empty
|
||||
□ IndexedDB is cleared
|
||||
□ Service worker cache cleared
|
||||
□ Fresh data loaded
|
||||
□ Functionality tested
|
||||
□ Sync works correctly
|
||||
□ Offline mode re-enabled (after cache rebuilt)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Clear Strategically
|
||||
- Don't clear unnecessarily
|
||||
- Clear only what's needed
|
||||
- Keep user data when possible
|
||||
|
||||
### 2. Warn Users
|
||||
```javascript
|
||||
function clearCache() {
|
||||
const message = `
|
||||
This will clear all cached data.
|
||||
You'll need to re-download everything from Odoo.
|
||||
Continue?
|
||||
`;
|
||||
|
||||
if (confirm(message)) {
|
||||
// Proceed
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Provide Progress
|
||||
```javascript
|
||||
async function clearAndRefresh() {
|
||||
alert('Clearing cache...');
|
||||
|
||||
localStorage.clear();
|
||||
|
||||
alert('Fetching fresh data...');
|
||||
|
||||
await expenseCache.refresh();
|
||||
|
||||
alert('Done! Cache rebuilt.');
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Log for Debugging
|
||||
```javascript
|
||||
function clearCache() {
|
||||
console.log('Before clear:', {
|
||||
localStorage: localStorage.length,
|
||||
records: $expenseCache.length
|
||||
});
|
||||
|
||||
localStorage.clear();
|
||||
expenseCache.clearCache();
|
||||
|
||||
console.log('After clear:', {
|
||||
localStorage: localStorage.length,
|
||||
records: $expenseCache.length
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Test Regularly
|
||||
- Test cache clear functionality
|
||||
- Ensure app works after clear
|
||||
- Verify data re-downloads
|
||||
- Check offline mode recovers
|
||||
|
||||
---
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/clear-cache` - Clear all cached data
|
||||
- User: "Clear my cache"
|
||||
- User: "Data looks wrong, clear everything"
|
||||
- User: "Reset the app"
|
||||
|
||||
## Related Commands:
|
||||
- `/fix-sync` - If sync issues persist
|
||||
- `/test-connection` - Test after clearing
|
||||
- `/troubleshoot` - For other issues
|
||||
- `/help` - Full documentation
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Clear Everything (Nuclear Option)
|
||||
```javascript
|
||||
// Copy-paste into console
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
indexedDB.databases().then(dbs =>
|
||||
dbs.forEach(db => indexedDB.deleteDatabase(db.name))
|
||||
);
|
||||
navigator.serviceWorker.getRegistrations().then(regs =>
|
||||
regs.forEach(reg => reg.unregister())
|
||||
);
|
||||
caches.keys().then(keys =>
|
||||
keys.forEach(key => caches.delete(key))
|
||||
);
|
||||
location.reload(true);
|
||||
```
|
||||
|
||||
### Clear Specific Model
|
||||
```javascript
|
||||
localStorage.removeItem('expenseCache');
|
||||
expenseCache.refresh();
|
||||
```
|
||||
|
||||
### Reset Metadata Only
|
||||
```javascript
|
||||
const cache = JSON.parse(localStorage.getItem('expenseCache'));
|
||||
cache.lastSyncTime = 0;
|
||||
cache.lastRecordId = 0;
|
||||
localStorage.setItem('expenseCache', JSON.stringify(cache));
|
||||
expenseCache.refresh();
|
||||
```
|
||||
89
commands/create-cache-store.md
Normal file
89
commands/create-cache-store.md
Normal file
@@ -0,0 +1,89 @@
|
||||
Create a smart cache store for an Odoo model with offline-first capabilities.
|
||||
|
||||
## What this command does:
|
||||
- Creates a framework-specific cache store (Svelte store, React Context, or Vue Pinia)
|
||||
- Implements dual storage (localStorage + IndexedDB)
|
||||
- Adds smart caching with stale detection (5-minute validity)
|
||||
- Implements background sync (3-minute intervals)
|
||||
- Includes incremental fetching (only new records)
|
||||
- Adds partner name resolution and caching
|
||||
- Implements optimistic updates
|
||||
|
||||
## Required Information:
|
||||
Before starting, gather:
|
||||
1. **Current working directory** - Must be inside an Odoo PWA project
|
||||
2. **Framework** - Detect from project files (SvelteKit/React/Vue)
|
||||
3. **Model name** (without `x_` prefix, e.g., "expense", "task")
|
||||
4. **Model display name** (human-readable, e.g., "Expense", "Task")
|
||||
5. **Fields to fetch** - Array of Odoo fields (e.g., ["x_studio_name", "x_studio_amount"])
|
||||
|
||||
## Store Features:
|
||||
The generated cache store will include:
|
||||
- `records` - Reactive array of cached records
|
||||
- `isLoading` - Loading state indicator
|
||||
- `error` - Error state
|
||||
- `lastSync` - Timestamp of last successful sync
|
||||
- `load()` - Load from cache and trigger background sync
|
||||
- `create(data)` - Create new record with optimistic update
|
||||
- `update(id, data)` - Update record with optimistic update
|
||||
- `delete(id)` - Delete record with optimistic update
|
||||
- `refresh()` - Force refresh from Odoo
|
||||
- `clearCache()` - Clear all cached data
|
||||
|
||||
## Storage Strategy:
|
||||
1. **localStorage**: Stores metadata (lastSyncTime, lastRecordId, version)
|
||||
2. **IndexedDB**: Stores master data (all records)
|
||||
3. **Stale detection**: Cache considered stale after 5 minutes
|
||||
4. **Background sync**: Automatic sync every 3 minutes
|
||||
5. **Incremental fetch**: Only fetches records with `id > lastRecordId`
|
||||
|
||||
## Steps:
|
||||
1. Verify the current directory is an Odoo PWA project
|
||||
2. Detect the framework from project structure
|
||||
3. Ask the user for model details and fields
|
||||
4. Create cache store file in appropriate location:
|
||||
- SvelteKit: `src/lib/stores/{model}Cache.js`
|
||||
- React: `src/contexts/{Model}Context.jsx`
|
||||
- Vue: `src/stores/{model}Store.js`
|
||||
5. Import and register the store in the appropriate location
|
||||
6. Provide usage examples and documentation
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/create-cache-store` - Interactive mode
|
||||
- User: "Create a cache store for the task model"
|
||||
- User: "Add caching for product catalog"
|
||||
|
||||
## After creation:
|
||||
Remind the user to:
|
||||
1. Import the store in components that need it
|
||||
2. Call the `load()` method when the component mounts
|
||||
3. Use reactive data bindings to display records
|
||||
4. Test create, update, and delete operations
|
||||
5. Verify offline functionality works correctly
|
||||
|
||||
## Usage Examples:
|
||||
|
||||
### SvelteKit
|
||||
```javascript
|
||||
import { taskCache } from '$lib/stores/taskCache';
|
||||
|
||||
// In +page.svelte
|
||||
$effect(() => {
|
||||
taskCache.load();
|
||||
});
|
||||
```
|
||||
|
||||
### React
|
||||
```javascript
|
||||
import { useTask } from './contexts/TaskContext';
|
||||
|
||||
const { records, create, update } = useTask();
|
||||
```
|
||||
|
||||
### Vue
|
||||
```javascript
|
||||
import { useTaskStore } from '@/stores/taskStore';
|
||||
|
||||
const taskStore = useTaskStore();
|
||||
taskStore.load();
|
||||
```
|
||||
182
commands/deploy-github.md
Normal file
182
commands/deploy-github.md
Normal file
@@ -0,0 +1,182 @@
|
||||
Deploy your Odoo PWA to GitHub Pages with GitHub Actions for continuous deployment.
|
||||
|
||||
## What this command does:
|
||||
- Sets up GitHub Actions workflow for automated deployment
|
||||
- Configures GitHub Pages in repository settings
|
||||
- Sets up repository secrets for environment variables
|
||||
- Deploys the application to GitHub Pages
|
||||
- Provides custom domain setup instructions
|
||||
|
||||
## Prerequisites:
|
||||
Before deploying, verify:
|
||||
1. ✅ Project builds successfully locally (`npm run build`)
|
||||
2. ✅ Git repository exists and is pushed to GitHub
|
||||
3. ✅ User has admin access to the repository
|
||||
4. ✅ GitHub Pages is enabled in repository settings
|
||||
5. ✅ Base URL configuration is correct for GitHub Pages
|
||||
|
||||
## Important: GitHub Pages Limitations
|
||||
⚠️ Note: GitHub Pages is static hosting only. Server-side API routes won't work.
|
||||
|
||||
**Recommendation**: For full Odoo PWA functionality with server-side API proxy:
|
||||
- Use Vercel, Cloudflare Pages, or Netlify instead
|
||||
- Or deploy API routes separately (e.g., Vercel Serverless Functions)
|
||||
|
||||
## If Continuing with GitHub Pages:
|
||||
You'll need to modify the Odoo client to use CORS-enabled direct Odoo API calls or deploy API routes separately.
|
||||
|
||||
## Steps:
|
||||
|
||||
### 1. Configure GitHub Repository
|
||||
```bash
|
||||
# Ensure you're on main branch
|
||||
git checkout main
|
||||
git pull origin main
|
||||
```
|
||||
|
||||
### 2. Set Up GitHub Actions Workflow
|
||||
Check if `.github/workflows/deploy.yml` exists:
|
||||
- If yes: Review and update if needed
|
||||
- If no: Create the workflow file
|
||||
|
||||
### 3. Configure Repository Secrets
|
||||
Go to: Repository → Settings → Secrets and variables → Actions
|
||||
|
||||
Add these secrets:
|
||||
```
|
||||
ODOO_API_KEY=your_production_api_key
|
||||
ODOO_USERNAME=your.email@company.com
|
||||
VITE_ODOO_URL=https://yourcompany.odoo.com
|
||||
VITE_ODOO_DB=yourcompany-main
|
||||
VITE_MODEL_NAME=x_expense
|
||||
VITE_MODEL_DISPLAY_NAME=Expense
|
||||
```
|
||||
|
||||
### 4. Enable GitHub Pages
|
||||
Repository → Settings → Pages:
|
||||
- Source: Deploy from a branch
|
||||
- Branch: `gh-pages` (will be created by Actions)
|
||||
- Folder: `/ (root)`
|
||||
|
||||
### 5. Update Base Path
|
||||
For framework-specific configuration:
|
||||
|
||||
**SvelteKit** (`svelte.config.js`):
|
||||
```javascript
|
||||
paths: {
|
||||
base: process.env.NODE_ENV === 'production' ? '/your-repo-name' : ''
|
||||
}
|
||||
```
|
||||
|
||||
**React/Vue** (`vite.config.js`):
|
||||
```javascript
|
||||
base: process.env.NODE_ENV === 'production' ? '/your-repo-name/' : '/'
|
||||
```
|
||||
|
||||
### 6. Commit and Push
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Configure GitHub Pages deployment"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### 7. Monitor Deployment
|
||||
- Go to Actions tab in GitHub
|
||||
- Watch the deployment workflow
|
||||
- Check for any errors
|
||||
|
||||
## GitHub Actions Workflow
|
||||
The workflow should:
|
||||
1. Trigger on push to `main` branch
|
||||
2. Install dependencies
|
||||
3. Build the project with environment variables
|
||||
4. Deploy to `gh-pages` branch
|
||||
5. GitHub Pages automatically serves from `gh-pages`
|
||||
|
||||
## Example Workflow (.github/workflows/deploy.yml):
|
||||
```yaml
|
||||
name: Deploy to GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
- run: npm install
|
||||
- run: npm run build
|
||||
env:
|
||||
VITE_ODOO_URL: ${{ secrets.VITE_ODOO_URL }}
|
||||
VITE_ODOO_DB: ${{ secrets.VITE_ODOO_DB }}
|
||||
VITE_MODEL_NAME: ${{ secrets.VITE_MODEL_NAME }}
|
||||
VITE_MODEL_DISPLAY_NAME: ${{ secrets.VITE_MODEL_DISPLAY_NAME }}
|
||||
- uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./build
|
||||
```
|
||||
|
||||
## Custom Domain Setup (Optional):
|
||||
1. Add `CNAME` file to `static` folder with your domain
|
||||
2. Configure DNS records:
|
||||
- A record: Points to GitHub Pages IPs
|
||||
- Or CNAME: Points to `username.github.io`
|
||||
3. Enable HTTPS in repository settings (automatic)
|
||||
|
||||
## Post-Deployment Checks:
|
||||
After deployment, verify:
|
||||
1. ✅ Application loads at `https://username.github.io/repo-name`
|
||||
2. ✅ All assets load correctly (check browser console)
|
||||
3. ✅ Base path is correct for all routes
|
||||
4. ✅ Odoo connection works (may need CORS configuration)
|
||||
5. ✅ PWA installs correctly
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/deploy-github` - Interactive GitHub Pages deployment
|
||||
- User: "Deploy to GitHub Pages"
|
||||
- User: "Set up GitHub Actions for my PWA"
|
||||
|
||||
## Troubleshooting:
|
||||
|
||||
### Build Fails in Actions
|
||||
- Check Actions logs for specific error
|
||||
- Verify all secrets are set correctly
|
||||
- Ensure Node version is compatible
|
||||
- Test build locally first
|
||||
|
||||
### 404 on GitHub Pages
|
||||
- Verify `gh-pages` branch exists
|
||||
- Check GitHub Pages settings
|
||||
- Ensure base path is configured
|
||||
- Wait a few minutes for DNS propagation
|
||||
|
||||
### Assets Not Loading
|
||||
- Check base path configuration
|
||||
- Verify all asset paths are relative
|
||||
- Look for CORS issues in console
|
||||
- Ensure service worker paths are correct
|
||||
|
||||
### API Routes Don't Work
|
||||
- GitHub Pages doesn't support server-side code
|
||||
- Deploy API routes to Vercel/Netlify separately
|
||||
- Or modify Odoo client for direct API calls with CORS
|
||||
|
||||
## After Deployment:
|
||||
Provide the user with:
|
||||
1. GitHub Pages URL
|
||||
2. Link to Actions tab for monitoring
|
||||
3. Instructions for custom domain setup
|
||||
4. Reminder about server-side limitations
|
||||
5. Alternative hosting recommendations if needed
|
||||
144
commands/deploy-vercel.md
Normal file
144
commands/deploy-vercel.md
Normal file
@@ -0,0 +1,144 @@
|
||||
Deploy your Odoo PWA to Vercel with proper environment variable configuration.
|
||||
|
||||
## What this command does:
|
||||
- Prepares the project for Vercel deployment
|
||||
- Guides through Vercel CLI setup or web deployment
|
||||
- Configures environment variables securely
|
||||
- Sets up continuous deployment from Git
|
||||
- Provides post-deployment verification steps
|
||||
|
||||
## Prerequisites:
|
||||
Before deploying, verify:
|
||||
1. ✅ Project builds successfully locally (`npm run build`)
|
||||
2. ✅ All tests pass
|
||||
3. ✅ `.env` file is configured and working
|
||||
4. ✅ Git repository is initialized and pushed to GitHub/GitLab/Bitbucket
|
||||
5. ✅ Vercel account exists (or guide user to create one)
|
||||
|
||||
## Deployment Options:
|
||||
|
||||
### Option 1: Vercel CLI (Recommended for first deployment)
|
||||
```bash
|
||||
npm install -g vercel
|
||||
vercel login
|
||||
vercel
|
||||
```
|
||||
|
||||
### Option 2: Vercel Dashboard (Recommended for Git integration)
|
||||
1. Go to https://vercel.com/new
|
||||
2. Import your Git repository
|
||||
3. Configure project settings
|
||||
4. Add environment variables
|
||||
5. Deploy
|
||||
|
||||
## Environment Variables to Set in Vercel:
|
||||
Required for production:
|
||||
```
|
||||
VITE_ODOO_URL=https://yourcompany.odoo.com
|
||||
VITE_ODOO_DB=yourcompany-main
|
||||
ODOO_API_KEY=your_production_api_key
|
||||
ODOO_USERNAME=your.email@company.com
|
||||
VITE_MODEL_NAME=x_expense
|
||||
VITE_MODEL_DISPLAY_NAME=Expense
|
||||
```
|
||||
|
||||
## Steps:
|
||||
1. Verify project builds successfully
|
||||
2. Check if Vercel is already configured (look for `vercel.json`)
|
||||
3. Ask user which deployment option they prefer
|
||||
4. Guide through the chosen deployment method
|
||||
5. Help set up environment variables in Vercel dashboard
|
||||
6. Initiate deployment
|
||||
7. Wait for build to complete
|
||||
8. Test the deployed application
|
||||
9. Set up custom domain (if requested)
|
||||
|
||||
## Framework-Specific Configuration:
|
||||
|
||||
### SvelteKit
|
||||
Verify `vercel.json` contains:
|
||||
```json
|
||||
{
|
||||
"buildCommand": "npm run build",
|
||||
"outputDirectory": "build",
|
||||
"framework": "sveltekit"
|
||||
}
|
||||
```
|
||||
|
||||
### React
|
||||
Verify build settings:
|
||||
```json
|
||||
{
|
||||
"buildCommand": "npm run build",
|
||||
"outputDirectory": "dist",
|
||||
"framework": "vite"
|
||||
}
|
||||
```
|
||||
|
||||
### Vue
|
||||
Verify build settings:
|
||||
```json
|
||||
{
|
||||
"buildCommand": "npm run build",
|
||||
"outputDirectory": "dist",
|
||||
"framework": "vite"
|
||||
}
|
||||
```
|
||||
|
||||
## Post-Deployment Checks:
|
||||
After deployment, verify:
|
||||
1. ✅ Application loads correctly
|
||||
2. ✅ Odoo connection works (check browser console)
|
||||
3. ✅ Data syncs from Odoo
|
||||
4. ✅ CRUD operations work
|
||||
5. ✅ Offline functionality works
|
||||
6. ✅ PWA can be installed
|
||||
7. ✅ Service worker is active
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/deploy-vercel` - Interactive deployment wizard
|
||||
- User: "Deploy my PWA to Vercel"
|
||||
- User: "Help me set up Vercel deployment"
|
||||
|
||||
## Continuous Deployment:
|
||||
Once Git integration is set up:
|
||||
- Every push to `main` branch triggers automatic deployment
|
||||
- Preview deployments for pull requests
|
||||
- Automatic rollback on build failures
|
||||
- Environment variables persist across deployments
|
||||
|
||||
## Custom Domain Setup:
|
||||
If user wants a custom domain:
|
||||
1. Go to Vercel Dashboard → Project → Settings → Domains
|
||||
2. Add custom domain
|
||||
3. Configure DNS records as shown
|
||||
4. Wait for SSL certificate provisioning (automatic)
|
||||
5. Test HTTPS access
|
||||
|
||||
## Troubleshooting:
|
||||
|
||||
### Build Fails
|
||||
- Check build logs in Vercel dashboard
|
||||
- Verify all dependencies are in package.json
|
||||
- Ensure Node version is compatible
|
||||
- Check for environment-specific code
|
||||
|
||||
### Environment Variables Not Working
|
||||
- Verify variables are set in Vercel dashboard
|
||||
- Check variable names match exactly (case-sensitive)
|
||||
- Ensure variables starting with `VITE_` for client-side access
|
||||
- Redeploy after adding new variables
|
||||
|
||||
### API Routes Not Working
|
||||
- Verify serverless functions are in correct directory
|
||||
- Check function size limits (< 50MB)
|
||||
- Review function logs in Vercel dashboard
|
||||
- Ensure API routes use correct paths
|
||||
|
||||
## After Deployment:
|
||||
Provide the user with:
|
||||
1. Deployed URL
|
||||
2. Vercel dashboard link
|
||||
3. Instructions for adding custom domain
|
||||
4. Tips for monitoring performance
|
||||
5. Reminder to update API keys for production
|
||||
467
commands/examples.md
Normal file
467
commands/examples.md
Normal file
@@ -0,0 +1,467 @@
|
||||
Real-world usage examples and scenarios for the Odoo PWA Generator plugin.
|
||||
|
||||
## What this command does:
|
||||
- Provides practical, real-world examples of using the plugin
|
||||
- Shows complete workflows from start to finish
|
||||
- Demonstrates different use cases and scenarios
|
||||
- Includes code samples and best practices
|
||||
- Helps users understand the plugin's capabilities
|
||||
|
||||
## Example 1: Expense Tracking App 💰
|
||||
|
||||
### Business Need:
|
||||
Create a mobile-friendly app for employees to track expenses on-the-go, even without internet connection. Sync with Odoo for approval and reimbursement.
|
||||
|
||||
### Odoo Model Setup:
|
||||
In Odoo Studio, create model `x_expense` with fields:
|
||||
- `x_studio_description` (Char) - Expense description
|
||||
- `x_studio_amount` (Float) - Amount spent
|
||||
- `x_studio_date` (Date) - When expense occurred
|
||||
- `x_studio_category` (Selection) - Meal, Travel, Hotel, Other
|
||||
- `x_studio_receipt` (Binary) - Photo of receipt
|
||||
- `x_studio_employee` (Many2one to res.partner) - Who spent it
|
||||
- `x_studio_status` (Selection) - Draft, Submitted, Approved, Paid
|
||||
|
||||
### Implementation Steps:
|
||||
```
|
||||
1. /new-svelte-pwa
|
||||
- Project name: expense-tracker
|
||||
- Model: expense
|
||||
- Display name: Expense
|
||||
- Deployment: vercel
|
||||
|
||||
2. cd expense-tracker
|
||||
|
||||
3. /init-project
|
||||
- Install dependencies
|
||||
- Configure Odoo credentials
|
||||
- Test connection
|
||||
|
||||
4. Customize the UI:
|
||||
- Add category filter
|
||||
- Display total amount
|
||||
- Add receipt upload
|
||||
- Status badge colors
|
||||
|
||||
5. /deploy-vercel
|
||||
- Deploy to production
|
||||
- Share with team
|
||||
```
|
||||
|
||||
### Key Features:
|
||||
- ✅ Record expenses offline
|
||||
- ✅ Take photos of receipts
|
||||
- ✅ Categorize expenses
|
||||
- ✅ Auto-sync when online
|
||||
- ✅ View approval status
|
||||
- ✅ Calculate monthly totals
|
||||
|
||||
### Code Customization:
|
||||
```javascript
|
||||
// Add total calculation to cache store
|
||||
export const totalExpenses = derived(expenseCache, $cache => {
|
||||
return $cache.reduce((sum, exp) => sum + exp.x_studio_amount, 0);
|
||||
});
|
||||
|
||||
// Add category filter
|
||||
export function filterByCategory(category) {
|
||||
return $expenseCache.filter(e => e.x_studio_category === category);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example 2: Inventory Management System 📦
|
||||
|
||||
### Business Need:
|
||||
Warehouse staff need to check stock levels, update quantities, and add new inventory items from mobile devices or tablets, even in areas with poor connectivity.
|
||||
|
||||
### Odoo Model Setup:
|
||||
Create model `x_inventory` with fields:
|
||||
- `x_studio_sku` (Char) - Product SKU
|
||||
- `x_studio_name` (Char) - Product name
|
||||
- `x_studio_quantity` (Integer) - Current stock
|
||||
- `x_studio_location` (Char) - Warehouse location
|
||||
- `x_studio_min_quantity` (Integer) - Reorder threshold
|
||||
- `x_studio_supplier` (Many2one to res.partner) - Supplier
|
||||
- `x_studio_last_restock` (Date) - Last restock date
|
||||
|
||||
### Implementation Steps:
|
||||
```
|
||||
1. /new-react-pwa
|
||||
- Project name: inventory-manager
|
||||
- Model: inventory
|
||||
- Display name: Inventory Item
|
||||
- Deployment: vercel
|
||||
|
||||
2. cd inventory-manager
|
||||
|
||||
3. /init-project
|
||||
|
||||
4. Add barcode scanning:
|
||||
- npm install @zxing/library
|
||||
- Add scanner component
|
||||
- Look up items by SKU
|
||||
|
||||
5. Add low stock alerts:
|
||||
- Filter items where quantity < min_quantity
|
||||
- Show notification badge
|
||||
- Sort by urgency
|
||||
|
||||
6. /deploy-vercel
|
||||
```
|
||||
|
||||
### Key Features:
|
||||
- ✅ Scan barcodes to find items
|
||||
- ✅ Update quantities offline
|
||||
- ✅ Low stock alerts
|
||||
- ✅ Search by name or SKU
|
||||
- ✅ Filter by location
|
||||
- ✅ Auto-sync updates
|
||||
|
||||
### Code Customization:
|
||||
```javascript
|
||||
// Add low stock filter
|
||||
const lowStockItems = useMemo(() => {
|
||||
return records.filter(item =>
|
||||
item.x_studio_quantity < item.x_studio_min_quantity
|
||||
);
|
||||
}, [records]);
|
||||
|
||||
// Add barcode lookup
|
||||
async function lookupBySKU(sku) {
|
||||
return records.find(item => item.x_studio_sku === sku);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example 3: Field Service CRM 🔧
|
||||
|
||||
### Business Need:
|
||||
Field technicians need to view customer information, log service calls, and update job status while on-site, often without reliable internet.
|
||||
|
||||
### Odoo Model Setup:
|
||||
Create model `x_service_call` with fields:
|
||||
- `x_studio_customer` (Many2one to res.partner) - Customer
|
||||
- `x_studio_issue` (Text) - Problem description
|
||||
- `x_studio_status` (Selection) - Scheduled, In Progress, Completed
|
||||
- `x_studio_scheduled_date` (Datetime) - When to visit
|
||||
- `x_studio_technician` (Many2one to res.partner) - Assigned tech
|
||||
- `x_studio_notes` (Text) - Service notes
|
||||
- `x_studio_parts_used` (Char) - Parts replaced
|
||||
- `x_studio_duration` (Float) - Hours spent
|
||||
|
||||
### Implementation Steps:
|
||||
```
|
||||
1. /new-vue-pwa
|
||||
- Project name: field-service-crm
|
||||
- Model: service_call
|
||||
- Display name: Service Call
|
||||
- Deployment: vercel
|
||||
|
||||
2. /init-project
|
||||
|
||||
3. Add customer details:
|
||||
- Create customer cache store
|
||||
- /add-model
|
||||
- Model: customer (use res.partner)
|
||||
- Generate UI: no (use existing)
|
||||
|
||||
4. Add map integration:
|
||||
- npm install @googlemaps/js-api-loader
|
||||
- Show customer locations
|
||||
- Route planning
|
||||
|
||||
5. Add time tracking:
|
||||
- Start/stop timer
|
||||
- Calculate duration
|
||||
- Generate timesheet
|
||||
|
||||
6. /deploy-vercel
|
||||
```
|
||||
|
||||
### Key Features:
|
||||
- ✅ View today's schedule
|
||||
- ✅ Customer contact info
|
||||
- ✅ Log service notes offline
|
||||
- ✅ Track time spent
|
||||
- ✅ Update job status
|
||||
- ✅ View service history
|
||||
|
||||
---
|
||||
|
||||
## Example 4: Sales Order Entry 🛒
|
||||
|
||||
### Business Need:
|
||||
Sales reps at trade shows need to take orders offline and sync them with Odoo when they get back online.
|
||||
|
||||
### Odoo Model Setup:
|
||||
Create model `x_sales_order` with fields:
|
||||
- `x_studio_customer` (Many2one to res.partner)
|
||||
- `x_studio_date` (Date)
|
||||
- `x_studio_items` (Text/JSON) - Line items
|
||||
- `x_studio_total` (Float) - Order total
|
||||
- `x_studio_status` (Selection) - Draft, Sent, Confirmed
|
||||
- `x_studio_notes` (Text) - Special instructions
|
||||
- `x_studio_salesperson` (Many2one to res.partner)
|
||||
|
||||
### Implementation Steps:
|
||||
```
|
||||
1. /new-svelte-pwa
|
||||
- Project name: sales-order-entry
|
||||
- Model: sales_order
|
||||
- Display name: Sales Order
|
||||
|
||||
2. /add-model
|
||||
- Model: customer (res.partner)
|
||||
- Add product catalog model
|
||||
|
||||
3. Build line item editor:
|
||||
- Add/remove products
|
||||
- Quantity and price
|
||||
- Calculate totals
|
||||
|
||||
4. Add customer search:
|
||||
- Autocomplete
|
||||
- Recently viewed
|
||||
- New customer form
|
||||
|
||||
5. /deploy-vercel
|
||||
```
|
||||
|
||||
### Key Features:
|
||||
- ✅ Search products
|
||||
- ✅ Build order offline
|
||||
- ✅ Calculate totals
|
||||
- ✅ Customer lookup
|
||||
- ✅ Sync when online
|
||||
- ✅ Email confirmation
|
||||
|
||||
---
|
||||
|
||||
## Example 5: Multi-Model Project Management 📋
|
||||
|
||||
### Business Need:
|
||||
Manage projects with tasks, time entries, and documents, all syncing with Odoo.
|
||||
|
||||
### Multiple Models:
|
||||
1. `x_project` - Projects
|
||||
2. `x_task` - Tasks
|
||||
3. `x_time_entry` - Time tracking
|
||||
4. `x_document` - File attachments
|
||||
|
||||
### Implementation Steps:
|
||||
```
|
||||
1. /new-svelte-pwa
|
||||
- Project name: project-manager
|
||||
- Model: project
|
||||
- Display name: Project
|
||||
|
||||
2. /add-model
|
||||
- Model: task
|
||||
- Generate UI: yes
|
||||
|
||||
3. /add-model
|
||||
- Model: time_entry
|
||||
- Generate UI: yes
|
||||
|
||||
4. /add-model
|
||||
- Model: document
|
||||
- Generate UI: yes
|
||||
|
||||
5. Add relationships:
|
||||
- Tasks belong to projects
|
||||
- Time entries belong to tasks
|
||||
- Documents belong to projects
|
||||
|
||||
6. Build dashboard:
|
||||
- Project overview
|
||||
- Task list by status
|
||||
- Total hours tracked
|
||||
- Recent documents
|
||||
|
||||
7. /deploy-vercel
|
||||
```
|
||||
|
||||
### Key Features:
|
||||
- ✅ Multiple model types
|
||||
- ✅ Relationships between models
|
||||
- ✅ Aggregate data (total hours)
|
||||
- ✅ Complex filtering
|
||||
- ✅ Dashboard views
|
||||
|
||||
---
|
||||
|
||||
## Example 6: Custom Cache Strategy 🎯
|
||||
|
||||
### Scenario:
|
||||
Need a custom caching strategy for frequently changing data.
|
||||
|
||||
### Implementation:
|
||||
```
|
||||
1. Open existing project
|
||||
|
||||
2. /create-cache-store
|
||||
- Model: notification
|
||||
- Shorter cache timeout (1 minute)
|
||||
- More frequent sync (30 seconds)
|
||||
|
||||
3. Customize the generated store:
|
||||
```
|
||||
|
||||
```javascript
|
||||
// Shorten cache validity
|
||||
const CACHE_VALIDITY = 60 * 1000; // 1 minute
|
||||
|
||||
// More frequent sync
|
||||
const SYNC_INTERVAL = 30 * 1000; // 30 seconds
|
||||
|
||||
// Add real-time refresh
|
||||
export function enableRealTimeSync() {
|
||||
return setInterval(() => {
|
||||
refresh();
|
||||
}, SYNC_INTERVAL);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example 7: Migrating Existing App 🔄
|
||||
|
||||
### Scenario:
|
||||
Have an existing web app, want to add Odoo integration and offline functionality.
|
||||
|
||||
### Implementation Steps:
|
||||
```
|
||||
1. Generate reference implementation:
|
||||
/new-svelte-pwa
|
||||
- Project name: reference-app
|
||||
- Model: your_model
|
||||
|
||||
2. Study generated code:
|
||||
- Review odoo.js client
|
||||
- Study cache.js pattern
|
||||
- Examine API routes
|
||||
|
||||
3. Copy patterns to existing app:
|
||||
- Copy src/lib/odoo.js
|
||||
- Copy src/routes/api/odoo/+server.js
|
||||
- Adapt cache store to your state management
|
||||
|
||||
4. Test integration:
|
||||
/test-connection
|
||||
|
||||
5. Gradually add features:
|
||||
- Start with read-only
|
||||
- Add create functionality
|
||||
- Add update/delete
|
||||
- Add offline support
|
||||
|
||||
6. /deploy-vercel
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Customizations:
|
||||
|
||||
### 1. Add Search Functionality
|
||||
```javascript
|
||||
export function searchRecords(query) {
|
||||
return $cache.filter(record =>
|
||||
record.x_studio_name.toLowerCase().includes(query.toLowerCase())
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Add Sorting
|
||||
```javascript
|
||||
export function sortBy(field, direction = 'asc') {
|
||||
return $cache.sort((a, b) => {
|
||||
const valA = a[field];
|
||||
const valB = b[field];
|
||||
return direction === 'asc' ? valA - valB : valB - valA;
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Add Pagination
|
||||
```javascript
|
||||
export function paginate(page, pageSize) {
|
||||
const start = (page - 1) * pageSize;
|
||||
return $cache.slice(start, start + pageSize);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Add Export to CSV
|
||||
```javascript
|
||||
export function exportToCSV() {
|
||||
const headers = ['ID', 'Name', 'Amount', 'Date'];
|
||||
const rows = $cache.map(r => [
|
||||
r.id,
|
||||
r.x_studio_name,
|
||||
r.x_studio_amount,
|
||||
r.x_studio_date
|
||||
]);
|
||||
// Convert to CSV and download
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Add Bulk Operations
|
||||
```javascript
|
||||
export async function bulkUpdate(ids, fields) {
|
||||
const promises = ids.map(id => update(id, fields));
|
||||
return Promise.all(promises);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tips for Success:
|
||||
|
||||
### Start Simple
|
||||
1. Generate basic PWA first
|
||||
2. Test with sample data
|
||||
3. Add features incrementally
|
||||
4. Deploy early and often
|
||||
|
||||
### Plan Your Models
|
||||
1. Design Odoo model schema carefully
|
||||
2. Include all necessary fields
|
||||
3. Think about relationships
|
||||
4. Consider mobile UX
|
||||
|
||||
### Test Thoroughly
|
||||
1. Test offline functionality
|
||||
2. Verify sync works correctly
|
||||
3. Check error handling
|
||||
4. Test on real devices
|
||||
|
||||
### Optimize Performance
|
||||
1. Limit initial data load
|
||||
2. Use pagination for large datasets
|
||||
3. Lazy load images
|
||||
4. Minimize bundle size
|
||||
|
||||
### Deploy Confidently
|
||||
1. Test build locally
|
||||
2. Use staging environment
|
||||
3. Monitor errors
|
||||
4. Have rollback plan
|
||||
|
||||
---
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/examples` - Show all examples
|
||||
- User: "Show me real-world examples"
|
||||
- User: "How do I build an expense tracker?"
|
||||
- User: "Give me ideas for using this plugin"
|
||||
|
||||
## Next Steps:
|
||||
After reviewing these examples:
|
||||
1. Choose a use case similar to your needs
|
||||
2. Follow the implementation steps
|
||||
3. Customize to match your requirements
|
||||
4. Deploy and iterate
|
||||
|
||||
Need help? Run `/help` for more information!
|
||||
596
commands/fix-sync.md
Normal file
596
commands/fix-sync.md
Normal file
@@ -0,0 +1,596 @@
|
||||
Diagnose and fix synchronization issues between your PWA and Odoo.
|
||||
|
||||
## What this command does:
|
||||
- Identifies sync problems
|
||||
- Tests each component of the sync system
|
||||
- Provides step-by-step fixes
|
||||
- Clears problematic cached data
|
||||
- Verifies sync works correctly
|
||||
|
||||
---
|
||||
|
||||
## Quick Diagnosis 🔍
|
||||
|
||||
Run through these quick checks first:
|
||||
|
||||
### 1. Visual Inspection
|
||||
```
|
||||
□ Check browser console for errors
|
||||
□ Look at "Last synced" timestamp
|
||||
□ Try manual refresh
|
||||
□ Check network tab for failed requests
|
||||
```
|
||||
|
||||
### 2. Quick Tests
|
||||
```javascript
|
||||
// In browser console:
|
||||
|
||||
// 1. Check if cache exists
|
||||
localStorage.getItem('expenseCache');
|
||||
|
||||
// 2. Test API endpoint
|
||||
fetch('/api/odoo', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'search',
|
||||
model: 'res.partner',
|
||||
domain: [],
|
||||
fields: ['name'],
|
||||
limit: 1
|
||||
})
|
||||
}).then(r => r.json()).then(console.log);
|
||||
|
||||
// 3. Force refresh
|
||||
expenseCache.refresh();
|
||||
```
|
||||
|
||||
### 3. Automatic Diagnosis
|
||||
```bash
|
||||
/test-connection
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Sync Issues
|
||||
|
||||
### Issue 1: Initial Load Works, But No Updates 🔄
|
||||
|
||||
**Symptoms:**
|
||||
- Data loads on first visit
|
||||
- But never updates with new Odoo data
|
||||
- "Last synced" timestamp is old
|
||||
- Background sync not happening
|
||||
|
||||
**Diagnosis:**
|
||||
```javascript
|
||||
// Check if sync timer is running
|
||||
// In cache store, look for:
|
||||
setInterval(() => syncInBackground(), 180000);
|
||||
|
||||
// Check if stale detection works
|
||||
const cacheData = JSON.parse(localStorage.getItem('expenseCache'));
|
||||
console.log('Last sync:', new Date(cacheData?.lastSyncTime));
|
||||
console.log('Is stale?', Date.now() - cacheData?.lastSyncTime > 5 * 60 * 1000);
|
||||
```
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### Solution A: Restart Background Sync
|
||||
```javascript
|
||||
// In browser console
|
||||
expenseCache.stopAutoSync();
|
||||
expenseCache.startAutoSync();
|
||||
```
|
||||
|
||||
#### Solution B: Check Cache Validity
|
||||
```javascript
|
||||
// In cache store file (e.g., expenseCache.js)
|
||||
const CACHE_VALIDITY = 5 * 60 * 1000; // 5 minutes
|
||||
|
||||
function isCacheStale() {
|
||||
const cacheData = JSON.parse(localStorage.getItem('expenseCache'));
|
||||
if (!cacheData) return true;
|
||||
|
||||
const now = Date.now();
|
||||
const age = now - cacheData.lastSyncTime;
|
||||
|
||||
console.log(`Cache age: ${Math.floor(age / 1000)}s`);
|
||||
|
||||
return age > CACHE_VALIDITY;
|
||||
}
|
||||
```
|
||||
|
||||
#### Solution C: Force Manual Sync
|
||||
```javascript
|
||||
// Add a refresh button to your UI
|
||||
<button onclick={() => expenseCache.refresh()}>
|
||||
Sync Now
|
||||
</button>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Issue 2: Incremental Sync Not Working 📈
|
||||
|
||||
**Symptoms:**
|
||||
- Always fetches all records
|
||||
- Slow sync times
|
||||
- High bandwidth usage
|
||||
- `lastRecordId` not updating
|
||||
|
||||
**Diagnosis:**
|
||||
```javascript
|
||||
// Check lastRecordId
|
||||
const cacheData = JSON.parse(localStorage.getItem('expenseCache'));
|
||||
console.log('Last record ID:', cacheData?.lastRecordId);
|
||||
|
||||
// Check if it's being updated after sync
|
||||
```
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### Solution A: Verify Domain Filter
|
||||
```javascript
|
||||
// In syncInBackground() function
|
||||
async function syncInBackground() {
|
||||
const { lastRecordId } = getCacheMetadata();
|
||||
|
||||
console.log('Fetching records with id >', lastRecordId);
|
||||
|
||||
const domain = lastRecordId > 0
|
||||
? [['id', '>', lastRecordId]]
|
||||
: [];
|
||||
|
||||
const newRecords = await odoo.searchRecords(
|
||||
MODEL_NAME,
|
||||
domain,
|
||||
fields
|
||||
);
|
||||
|
||||
console.log('Fetched:', newRecords.length, 'new records');
|
||||
|
||||
if (newRecords.length > 0) {
|
||||
// Update lastRecordId
|
||||
const maxId = Math.max(...newRecords.map(r => r.id));
|
||||
updateCacheMetadata({ lastRecordId: maxId });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Solution B: Reset lastRecordId
|
||||
```javascript
|
||||
// If stuck, reset to fetch all
|
||||
const cacheData = JSON.parse(localStorage.getItem('expenseCache'));
|
||||
cacheData.lastRecordId = 0;
|
||||
localStorage.setItem('expenseCache', JSON.stringify(cacheData));
|
||||
|
||||
// Then refresh
|
||||
expenseCache.refresh();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Issue 3: Optimistic Updates Not Syncing ⚡
|
||||
|
||||
**Symptoms:**
|
||||
- Create/update works in UI
|
||||
- But changes don't save to Odoo
|
||||
- Records disappear on refresh
|
||||
- Temp IDs persist
|
||||
|
||||
**Diagnosis:**
|
||||
```javascript
|
||||
// Check for temp IDs
|
||||
console.log($expenseCache.filter(e => e.id.toString().startsWith('temp-')));
|
||||
|
||||
// Check browser console for API errors
|
||||
```
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### Solution A: Check API Route
|
||||
```javascript
|
||||
// Test create
|
||||
fetch('/api/odoo', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'create',
|
||||
model: 'x_expense',
|
||||
fields: {
|
||||
x_studio_description: 'Test',
|
||||
x_studio_amount: 10.00
|
||||
}
|
||||
})
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(console.log)
|
||||
.catch(console.error);
|
||||
```
|
||||
|
||||
#### Solution B: Fix Error Handling
|
||||
```javascript
|
||||
// In cache store create() function
|
||||
export async function create(data) {
|
||||
const tempId = `temp-${Date.now()}`;
|
||||
const tempRecord = { id: tempId, ...data };
|
||||
|
||||
// Add to cache
|
||||
records.update(r => [...r, tempRecord]);
|
||||
|
||||
try {
|
||||
// Create in Odoo
|
||||
const realId = await odoo.createRecord(MODEL_NAME, data);
|
||||
|
||||
// Replace temp ID
|
||||
records.update(r =>
|
||||
r.map(rec => rec.id === tempId ? { ...rec, id: realId } : rec)
|
||||
);
|
||||
|
||||
// Update cache metadata
|
||||
await refresh(); // Sync to get the complete record
|
||||
|
||||
return realId;
|
||||
} catch (error) {
|
||||
console.error('Failed to create record:', error);
|
||||
|
||||
// Rollback
|
||||
records.update(r => r.filter(rec => rec.id !== tempId));
|
||||
|
||||
// Re-throw
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Solution C: Clean Up Temp Records
|
||||
```javascript
|
||||
// Remove stuck temp records
|
||||
expenseCache.records.update(records =>
|
||||
records.filter(r => !r.id.toString().startsWith('temp-'))
|
||||
);
|
||||
|
||||
// Then refresh
|
||||
expenseCache.refresh();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Issue 4: Partner Names Not Resolving 👥
|
||||
|
||||
**Symptoms:**
|
||||
- Partner fields show IDs instead of names
|
||||
- Many2one fields display as arrays
|
||||
- "undefined" or "[object Object]" displayed
|
||||
|
||||
**Diagnosis:**
|
||||
```javascript
|
||||
// Check partner field format
|
||||
const record = $expenseCache[0];
|
||||
console.log('Employee field:', record.x_studio_employee);
|
||||
// Should be: [12, "John Doe"] or 12
|
||||
```
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### Solution A: Add Partner Resolution
|
||||
```javascript
|
||||
// In syncInBackground()
|
||||
async function syncInBackground() {
|
||||
// ... fetch records ...
|
||||
|
||||
// Resolve partner names
|
||||
const partnerIds = new Set();
|
||||
|
||||
records.forEach(record => {
|
||||
if (record.x_studio_employee) {
|
||||
const id = Array.isArray(record.x_studio_employee)
|
||||
? record.x_studio_employee[0]
|
||||
: record.x_studio_employee;
|
||||
partnerIds.add(id);
|
||||
}
|
||||
});
|
||||
|
||||
if (partnerIds.size > 0) {
|
||||
const partners = await odoo.fetchPartners(Array.from(partnerIds));
|
||||
const partnerMap = new Map(partners.map(p => [p.id, p.name]));
|
||||
|
||||
// Cache partners
|
||||
localStorage.setItem('partnerCache', JSON.stringify(
|
||||
Array.from(partnerMap.entries())
|
||||
));
|
||||
|
||||
// Update records with names
|
||||
records = records.map(record => {
|
||||
if (record.x_studio_employee) {
|
||||
const id = Array.isArray(record.x_studio_employee)
|
||||
? record.x_studio_employee[0]
|
||||
: record.x_studio_employee;
|
||||
|
||||
return {
|
||||
...record,
|
||||
x_studio_employee: [id, partnerMap.get(id) || 'Unknown']
|
||||
};
|
||||
}
|
||||
return record;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Solution B: Display Helper Function
|
||||
```javascript
|
||||
// Helper to display partner name
|
||||
function getPartnerName(field) {
|
||||
if (!field) return 'None';
|
||||
if (Array.isArray(field)) return field[1] || `ID: ${field[0]}`;
|
||||
return `ID: ${field}`;
|
||||
}
|
||||
|
||||
// In component
|
||||
{getPartnerName(expense.x_studio_employee)}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Issue 5: Duplicate Records 📋📋
|
||||
|
||||
**Symptoms:**
|
||||
- Same record appears multiple times
|
||||
- ID conflicts
|
||||
- Sync creates duplicates
|
||||
|
||||
**Diagnosis:**
|
||||
```javascript
|
||||
// Check for duplicates
|
||||
const ids = $expenseCache.map(r => r.id);
|
||||
const duplicates = ids.filter((id, index) => ids.indexOf(id) !== index);
|
||||
console.log('Duplicate IDs:', duplicates);
|
||||
```
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### Solution A: Deduplicate Cache
|
||||
```javascript
|
||||
function deduplicateCache() {
|
||||
records.update(currentRecords => {
|
||||
const seen = new Set();
|
||||
return currentRecords.filter(record => {
|
||||
if (seen.has(record.id)) {
|
||||
return false;
|
||||
}
|
||||
seen.add(record.id);
|
||||
return true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Run deduplication
|
||||
deduplicateCache();
|
||||
```
|
||||
|
||||
#### Solution B: Fix Sync Logic
|
||||
```javascript
|
||||
// When appending new records, check for duplicates
|
||||
async function appendToCache(newRecords) {
|
||||
records.update(currentRecords => {
|
||||
const existingIds = new Set(currentRecords.map(r => r.id));
|
||||
|
||||
// Only add records that don't exist
|
||||
const toAdd = newRecords.filter(r => !existingIds.has(r.id));
|
||||
|
||||
return [...currentRecords, ...toAdd];
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Issue 6: Offline Queue Not Syncing 📴
|
||||
|
||||
**Symptoms:**
|
||||
- Changes made offline
|
||||
- Online now, but changes not syncing
|
||||
- Stuck in "pending" state
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### Solution A: Implement Offline Queue
|
||||
```javascript
|
||||
// Store failed operations
|
||||
const offlineQueue = writable([]);
|
||||
|
||||
async function queueOperation(operation) {
|
||||
offlineQueue.update(q => [...q, operation]);
|
||||
saveOfflineQueue();
|
||||
}
|
||||
|
||||
async function processOfflineQueue() {
|
||||
const queue = get(offlineQueue);
|
||||
|
||||
for (const operation of queue) {
|
||||
try {
|
||||
if (operation.type === 'create') {
|
||||
await odoo.createRecord(operation.model, operation.data);
|
||||
} else if (operation.type === 'update') {
|
||||
await odoo.updateRecord(operation.model, operation.id, operation.data);
|
||||
} else if (operation.type === 'delete') {
|
||||
await odoo.deleteRecord(operation.model, operation.id);
|
||||
}
|
||||
|
||||
// Remove from queue
|
||||
offlineQueue.update(q => q.filter(op => op !== operation));
|
||||
} catch (error) {
|
||||
console.error('Failed to process queued operation:', error);
|
||||
// Keep in queue, will retry
|
||||
}
|
||||
}
|
||||
|
||||
saveOfflineQueue();
|
||||
}
|
||||
|
||||
// Listen for online event
|
||||
window.addEventListener('online', () => {
|
||||
console.log('Back online, processing queue...');
|
||||
processOfflineQueue();
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step-by-Step Fix Procedure 🔧
|
||||
|
||||
### Step 1: Clear Everything
|
||||
```javascript
|
||||
// Clear all caches
|
||||
localStorage.clear();
|
||||
|
||||
// Clear IndexedDB
|
||||
// DevTools → Application → IndexedDB → Delete database
|
||||
```
|
||||
|
||||
### Step 2: Test API
|
||||
```bash
|
||||
/test-connection
|
||||
```
|
||||
|
||||
### Step 3: Fresh Sync
|
||||
```javascript
|
||||
// Refresh page
|
||||
location.reload();
|
||||
|
||||
// Should fetch all data fresh
|
||||
```
|
||||
|
||||
### Step 4: Monitor Sync
|
||||
```javascript
|
||||
// Watch console for sync messages
|
||||
// Should see:
|
||||
// "Syncing x_expense..."
|
||||
// "Fetched X records"
|
||||
// "Cache updated"
|
||||
```
|
||||
|
||||
### Step 5: Test CRUD
|
||||
```javascript
|
||||
// Test create
|
||||
await expenseCache.create({ /* data */ });
|
||||
|
||||
// Test update
|
||||
await expenseCache.update(id, { /* data */ });
|
||||
|
||||
// Test delete
|
||||
await expenseCache.remove(id);
|
||||
|
||||
// Verify in Odoo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sync Debugging Checklist ✅
|
||||
|
||||
```
|
||||
□ Browser console shows no errors
|
||||
□ /api/odoo endpoint responds
|
||||
□ ODOO_API_KEY is valid
|
||||
□ lastSyncTime is updating
|
||||
□ lastRecordId is updating
|
||||
□ Background sync interval is running
|
||||
□ Stale detection works correctly
|
||||
□ Incremental fetch has correct domain
|
||||
□ Optimistic updates resolve temp IDs
|
||||
□ Partner names resolve correctly
|
||||
□ No duplicate records
|
||||
□ Offline queue processes when online
|
||||
□ IndexedDB is storing data
|
||||
□ localStorage has metadata
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Advanced Debugging 🐛
|
||||
|
||||
### Enable Verbose Logging
|
||||
```javascript
|
||||
// Add to cache store
|
||||
const DEBUG = true;
|
||||
|
||||
function log(...args) {
|
||||
if (DEBUG) console.log('[ExpenseCache]', ...args);
|
||||
}
|
||||
|
||||
async function syncInBackground() {
|
||||
log('Starting background sync...');
|
||||
log('lastRecordId:', getLastRecordId());
|
||||
|
||||
const records = await fetch();
|
||||
log('Fetched records:', records.length);
|
||||
|
||||
await saveToCache(records);
|
||||
log('Cache updated');
|
||||
}
|
||||
```
|
||||
|
||||
### Monitor Network
|
||||
```javascript
|
||||
// Log all API calls
|
||||
const originalFetch = window.fetch;
|
||||
window.fetch = async (...args) => {
|
||||
console.log('Fetch:', args[0]);
|
||||
const response = await originalFetch(...args);
|
||||
console.log('Response:', response.status);
|
||||
return response;
|
||||
};
|
||||
```
|
||||
|
||||
### Profile Performance
|
||||
```javascript
|
||||
// Measure sync time
|
||||
console.time('sync');
|
||||
await expenseCache.refresh();
|
||||
console.timeEnd('sync');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/fix-sync` - Diagnose sync issues
|
||||
- User: "Data is not syncing"
|
||||
- User: "My changes aren't saving"
|
||||
- User: "Sync is broken"
|
||||
|
||||
## Related Commands:
|
||||
- `/test-connection` - Test Odoo connectivity
|
||||
- `/clear-cache` - Clear all cached data
|
||||
- `/troubleshoot` - General troubleshooting
|
||||
- `/help` - Full documentation
|
||||
|
||||
---
|
||||
|
||||
## Prevention Tips 🛡️
|
||||
|
||||
1. **Monitor sync health**
|
||||
- Display "Last synced" timestamp in UI
|
||||
- Show sync status indicator
|
||||
- Alert on sync failures
|
||||
|
||||
2. **Handle errors gracefully**
|
||||
- Catch and log all errors
|
||||
- Show user-friendly messages
|
||||
- Provide retry mechanisms
|
||||
|
||||
3. **Test offline scenarios**
|
||||
- Test creating records offline
|
||||
- Test going offline mid-sync
|
||||
- Test coming back online
|
||||
|
||||
4. **Keep sync simple**
|
||||
- Stick to generated patterns
|
||||
- Don't overcomplicate logic
|
||||
- Follow proven examples
|
||||
|
||||
5. **Regular maintenance**
|
||||
- Clear old data periodically
|
||||
- Update dependencies
|
||||
- Monitor performance
|
||||
322
commands/help.md
Normal file
322
commands/help.md
Normal file
@@ -0,0 +1,322 @@
|
||||
Display comprehensive help and documentation for the Odoo PWA Generator plugin.
|
||||
|
||||
## What this command does:
|
||||
- Provides overview of the plugin and its capabilities
|
||||
- Lists all available commands with descriptions
|
||||
- Explains the plugin's skills and when to use them
|
||||
- Shows common usage patterns and workflows
|
||||
- Links to detailed documentation
|
||||
|
||||
## Plugin Overview:
|
||||
The **odoo-pwa-generator** plugin helps you create offline-first Progressive Web Apps with Odoo Studio backend integration. It supports SvelteKit, React, and Vue frameworks.
|
||||
|
||||
### Key Features:
|
||||
✨ **Quick Project Generation** - Create complete PWAs in minutes
|
||||
📱 **Offline-First** - Smart caching with background sync
|
||||
🔄 **Odoo Integration** - Seamless Odoo Studio connectivity
|
||||
🚀 **Production Ready** - Pre-configured deployment setups
|
||||
⚡ **Framework Support** - SvelteKit, React, and Vue
|
||||
|
||||
### Core Capabilities:
|
||||
- Automatic CRUD operations for Odoo models
|
||||
- Smart caching with localStorage + IndexedDB
|
||||
- Incremental sync (only fetch new records)
|
||||
- Optimistic UI updates
|
||||
- Partner/relation resolution
|
||||
- PWA installability
|
||||
- Offline functionality
|
||||
|
||||
## Available Commands:
|
||||
|
||||
### 🎯 Skill Shortcuts (Project Generation)
|
||||
Create new PWA projects:
|
||||
- `/new-svelte-pwa` - Generate SvelteKit PWA
|
||||
- `/new-react-pwa` - Generate React PWA
|
||||
- `/new-vue-pwa` - Generate Vue PWA
|
||||
- `/add-model` - Add Odoo model to existing PWA
|
||||
- `/create-cache-store` - Create cache store for a model
|
||||
|
||||
### 🔧 Workflow Commands
|
||||
Development and deployment:
|
||||
- `/init-project` - Initialize new PWA project
|
||||
- `/setup-env` - Configure environment variables
|
||||
- `/test-connection` - Test Odoo API connection
|
||||
- `/deploy-vercel` - Deploy to Vercel
|
||||
- `/deploy-github` - Deploy to GitHub Pages
|
||||
|
||||
### 📚 Documentation Commands
|
||||
Help and reference:
|
||||
- `/help` - This help document (you are here!)
|
||||
- `/examples` - Real-world usage examples
|
||||
- `/architecture` - Explain PWA architecture
|
||||
- `/api-reference` - Odoo API client documentation
|
||||
- `/troubleshoot` - Common issues and solutions
|
||||
|
||||
### 🛠 Maintenance Commands
|
||||
Project management:
|
||||
- `/update-deps` - Update project dependencies
|
||||
- `/fix-sync` - Diagnose and fix sync issues
|
||||
- `/clear-cache` - Clear application caches
|
||||
- `/add-deployment` - Add new deployment target
|
||||
- `/optimize` - Run optimization checks
|
||||
|
||||
## Common Workflows:
|
||||
|
||||
### 1️⃣ Starting a New Project
|
||||
```
|
||||
1. /new-svelte-pwa (or /new-react-pwa or /new-vue-pwa)
|
||||
2. Provide project details (name, model, etc.)
|
||||
3. /init-project
|
||||
4. Start coding!
|
||||
```
|
||||
|
||||
### 2️⃣ Setting Up Environment
|
||||
```
|
||||
1. /setup-env
|
||||
2. Provide Odoo credentials
|
||||
3. /test-connection
|
||||
4. Verify everything works
|
||||
```
|
||||
|
||||
### 3️⃣ Adding More Models
|
||||
```
|
||||
1. /add-model
|
||||
2. Specify model name and details
|
||||
3. Test CRUD operations
|
||||
4. Customize UI as needed
|
||||
```
|
||||
|
||||
### 4️⃣ Deploying to Production
|
||||
```
|
||||
1. /deploy-vercel (recommended)
|
||||
OR /deploy-github
|
||||
2. Configure environment variables
|
||||
3. Test deployed application
|
||||
4. Set up custom domain (optional)
|
||||
```
|
||||
|
||||
### 5️⃣ Troubleshooting Issues
|
||||
```
|
||||
1. /test-connection - Check Odoo connectivity
|
||||
2. /troubleshoot - Find specific solutions
|
||||
3. /fix-sync - Diagnose sync problems
|
||||
4. /clear-cache - Reset if needed
|
||||
```
|
||||
|
||||
## Quick Start Guide:
|
||||
|
||||
### Step 1: Generate a New PWA
|
||||
Choose your framework and run the appropriate command:
|
||||
```
|
||||
/new-svelte-pwa
|
||||
```
|
||||
|
||||
### Step 2: Provide Project Details
|
||||
When prompted, provide:
|
||||
- **Project name**: e.g., "expense-tracker"
|
||||
- **Odoo model**: e.g., "expense" (without x_ prefix)
|
||||
- **Display name**: e.g., "Expense"
|
||||
- **Deployment target**: e.g., "vercel" (optional)
|
||||
|
||||
### Step 3: Initialize the Project
|
||||
```
|
||||
cd your-project-name
|
||||
/init-project
|
||||
```
|
||||
|
||||
### Step 4: Configure Odoo Connection
|
||||
```
|
||||
/setup-env
|
||||
```
|
||||
Provide your Odoo URL, database, API key, and username.
|
||||
|
||||
### Step 5: Test Everything
|
||||
```
|
||||
/test-connection
|
||||
```
|
||||
Verify your Odoo connection works correctly.
|
||||
|
||||
### Step 6: Start Developing
|
||||
The dev server should be running. Open your browser and start customizing!
|
||||
|
||||
### Step 7: Deploy (when ready)
|
||||
```
|
||||
/deploy-vercel
|
||||
```
|
||||
Follow the prompts to deploy to production.
|
||||
|
||||
## Plugin Skills:
|
||||
|
||||
### create-odoo-pwa
|
||||
Generates a complete PWA project from scratch.
|
||||
|
||||
**When to use**: Starting a new project
|
||||
|
||||
**What it generates**:
|
||||
- Base configuration (package.json, vite.config, etc.)
|
||||
- Odoo API client
|
||||
- Cache stores with smart syncing
|
||||
- Server-side API proxy
|
||||
- UI components (forms, lists)
|
||||
- PWA manifest and service worker
|
||||
- Deployment configurations
|
||||
- Complete documentation
|
||||
|
||||
### add-odoo-model
|
||||
Adds integration for additional Odoo models.
|
||||
|
||||
**When to use**: Adding new data models to existing project
|
||||
|
||||
**What it generates**:
|
||||
- Cache store for the new model
|
||||
- API methods in Odoo client
|
||||
- Form and list pages (optional)
|
||||
- Navigation updates
|
||||
|
||||
### create-cache-store
|
||||
Creates a standalone cache store.
|
||||
|
||||
**When to use**: Need custom caching logic
|
||||
|
||||
**What it generates**:
|
||||
- Framework-specific cache store
|
||||
- Smart caching logic
|
||||
- Background sync
|
||||
- Optimistic updates
|
||||
|
||||
## Best Practices:
|
||||
|
||||
### Security
|
||||
- ✅ Keep API keys in `.env` file (never commit)
|
||||
- ✅ Use different credentials for dev and production
|
||||
- ✅ Set environment variables in hosting platform
|
||||
- ✅ Rotate API keys periodically
|
||||
|
||||
### Development
|
||||
- ✅ Test Odoo connection before coding
|
||||
- ✅ Use version control (Git)
|
||||
- ✅ Test offline functionality regularly
|
||||
- ✅ Read generated CLAUDE.md for patterns
|
||||
|
||||
### Deployment
|
||||
- ✅ Build and test locally first
|
||||
- ✅ Use Vercel/Netlify for full functionality
|
||||
- ✅ Set up continuous deployment from Git
|
||||
- ✅ Monitor performance and errors
|
||||
|
||||
### Maintenance
|
||||
- ✅ Keep dependencies updated
|
||||
- ✅ Monitor Odoo API changes
|
||||
- ✅ Test after Odoo upgrades
|
||||
- ✅ Clear caches when schema changes
|
||||
|
||||
## Getting More Help:
|
||||
|
||||
### Example prompts to use this command:
|
||||
- `/help` - Show this help document
|
||||
- User: "How do I use the Odoo PWA plugin?"
|
||||
- User: "What commands are available?"
|
||||
|
||||
### In Generated Projects:
|
||||
- `README.md` - Getting started guide
|
||||
- `CLAUDE.md` - Architecture patterns
|
||||
- `API.md` - API client reference
|
||||
|
||||
### External Resources:
|
||||
- Odoo API Documentation: https://www.odoo.com/documentation/
|
||||
- SvelteKit: https://kit.svelte.dev/
|
||||
- React: https://react.dev/
|
||||
- Vue: https://vuejs.org/
|
||||
- PWA Guide: https://web.dev/progressive-web-apps/
|
||||
|
||||
### Troubleshooting:
|
||||
If you encounter issues:
|
||||
1. Run `/test-connection` to diagnose
|
||||
2. Check `/troubleshoot` for common solutions
|
||||
3. Review browser console for errors
|
||||
4. Verify Odoo configuration
|
||||
5. Check generated documentation
|
||||
|
||||
### Support:
|
||||
For bugs or feature requests:
|
||||
- Check existing issues
|
||||
- Review documentation thoroughly
|
||||
- Provide detailed error messages
|
||||
- Include environment details
|
||||
|
||||
## Framework-Specific Notes:
|
||||
|
||||
### SvelteKit (Recommended)
|
||||
- Uses Svelte 5 runes syntax
|
||||
- Server-side API routes work perfectly
|
||||
- Best offline functionality
|
||||
- Smallest bundle size
|
||||
- Easiest to deploy
|
||||
|
||||
### React
|
||||
- Modern React 18+ hooks
|
||||
- Context API for state management
|
||||
- Wide ecosystem support
|
||||
- Popular and familiar
|
||||
|
||||
### Vue
|
||||
- Vue 3 Composition API
|
||||
- Pinia for state management
|
||||
- Great developer experience
|
||||
- Progressive framework
|
||||
|
||||
## Architecture Highlights:
|
||||
|
||||
### Data Flow
|
||||
```
|
||||
Component → Cache Store → API Client → Server Route → Odoo
|
||||
```
|
||||
|
||||
### Caching Strategy
|
||||
1. **Load from cache** (instant, may be stale)
|
||||
2. **Check if stale** (> 5 minutes)
|
||||
3. **Background sync** (fetch new data)
|
||||
4. **Update cache** (localStorage + IndexedDB)
|
||||
5. **Reactive update** (UI updates automatically)
|
||||
|
||||
### Sync Strategy
|
||||
1. **Incremental fetch** - Only `id > lastRecordId`
|
||||
2. **Partner resolution** - Batch fetch related records
|
||||
3. **Optimistic updates** - UI updates before server
|
||||
4. **Error recovery** - Graceful offline handling
|
||||
|
||||
## Tips and Tricks:
|
||||
|
||||
💡 **Use the right command for the job**
|
||||
- Quick start? `/new-svelte-pwa`
|
||||
- Need help? `/help` or `/troubleshoot`
|
||||
- Deploy ready? `/deploy-vercel`
|
||||
|
||||
💡 **Test early and often**
|
||||
- Run `/test-connection` after setup
|
||||
- Test offline mode frequently
|
||||
- Verify sync works correctly
|
||||
|
||||
💡 **Read the generated docs**
|
||||
- CLAUDE.md has architecture details
|
||||
- API.md has client method docs
|
||||
- README.md has setup instructions
|
||||
|
||||
💡 **Customize to your needs**
|
||||
- Start with generated code
|
||||
- Modify UI components
|
||||
- Add business logic
|
||||
- Extend with new features
|
||||
|
||||
💡 **Deploy with confidence**
|
||||
- Test build locally first
|
||||
- Use environment variables properly
|
||||
- Monitor after deployment
|
||||
- Set up error tracking
|
||||
|
||||
## Summary:
|
||||
The odoo-pwa-generator plugin makes it easy to create production-ready PWAs with Odoo integration. Use the commands above to generate, develop, deploy, and maintain your applications.
|
||||
|
||||
For more details on any command, just run that command and follow the prompts!
|
||||
|
||||
Happy coding! 🚀
|
||||
202
commands/init-project.md
Normal file
202
commands/init-project.md
Normal file
@@ -0,0 +1,202 @@
|
||||
Initialize a newly generated Odoo PWA project with all necessary setup steps.
|
||||
|
||||
## What this command does:
|
||||
- Runs `npm install` to install all dependencies
|
||||
- Creates `.env` file from `.env.example`
|
||||
- Guides through environment configuration
|
||||
- Tests the Odoo connection
|
||||
- Starts the development server
|
||||
- Opens the application in browser
|
||||
- Provides next steps and documentation
|
||||
|
||||
## Prerequisites:
|
||||
- Newly generated Odoo PWA project
|
||||
- Node.js installed (v18 or higher)
|
||||
- npm or pnpm package manager
|
||||
- Internet connection for dependencies
|
||||
|
||||
## Steps:
|
||||
|
||||
### 1. Verify Project Structure
|
||||
Check that required files exist:
|
||||
- ✅ `package.json`
|
||||
- ✅ `.env.example`
|
||||
- ✅ `README.md`
|
||||
- ✅ `src/lib/odoo.js` (or equivalent)
|
||||
- ✅ Framework config file (svelte.config.js / vite.config.js)
|
||||
|
||||
### 2. Install Dependencies
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
Show progress and estimated time.
|
||||
|
||||
### 3. Environment Setup
|
||||
Copy `.env.example` to `.env`:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Ask the user to provide:
|
||||
1. Odoo URL
|
||||
2. Database name
|
||||
3. API key
|
||||
4. Username
|
||||
5. Model configuration
|
||||
|
||||
Update `.env` file with provided values.
|
||||
|
||||
### 4. Verify Setup
|
||||
Read `.env` and verify all required variables are set.
|
||||
|
||||
### 5. Test Odoo Connection
|
||||
Run a quick connection test:
|
||||
- Test authentication
|
||||
- Verify model access
|
||||
- Check permissions
|
||||
|
||||
If connection fails, offer to run full diagnostics (`/test-connection`).
|
||||
|
||||
### 6. Initialize Git (if not already)
|
||||
```bash
|
||||
git init
|
||||
git add .
|
||||
git commit -m "Initial commit: Odoo PWA generated"
|
||||
```
|
||||
|
||||
### 7. Start Development Server
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Framework-specific commands:
|
||||
- **SvelteKit**: `npm run dev` (default port 5173)
|
||||
- **React**: `npm run dev` (default port 5173)
|
||||
- **Vue**: `npm run dev` (default port 5173)
|
||||
|
||||
### 8. Open in Browser
|
||||
Automatically open browser to `http://localhost:5173`
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/init-project` - Complete initialization wizard
|
||||
- User: "Set up my new Odoo PWA"
|
||||
- User: "Initialize the project"
|
||||
- User: "Get my PWA running"
|
||||
|
||||
## Post-Initialization Checklist:
|
||||
After successful initialization:
|
||||
|
||||
✅ **Immediate Next Steps**:
|
||||
1. Test the application in the browser
|
||||
2. Verify data loads from Odoo
|
||||
3. Test creating a new record
|
||||
4. Test editing and deleting records
|
||||
5. Verify offline functionality (disable network)
|
||||
|
||||
✅ **Configuration**:
|
||||
1. Review and customize PWA manifest (colors, icons, name)
|
||||
2. Update application metadata
|
||||
3. Configure deployment targets
|
||||
4. Set up version control (Git)
|
||||
|
||||
✅ **Development**:
|
||||
1. Read the generated `CLAUDE.md` for architecture details
|
||||
2. Review `API.md` for Odoo client documentation
|
||||
3. Explore the codebase structure
|
||||
4. Customize UI components and styling
|
||||
|
||||
✅ **Testing**:
|
||||
1. Test all CRUD operations
|
||||
2. Verify sync functionality
|
||||
3. Test offline mode
|
||||
4. Check PWA installability
|
||||
5. Test on mobile devices
|
||||
|
||||
✅ **Deployment Preparation**:
|
||||
1. Review deployment documentation
|
||||
2. Set up hosting platform account (Vercel/Netlify/etc)
|
||||
3. Prepare production Odoo API keys
|
||||
4. Configure environment variables for production
|
||||
|
||||
## Helpful Resources:
|
||||
Provide links to:
|
||||
- Project `README.md`
|
||||
- `CLAUDE.md` (architecture guide)
|
||||
- `API.md` (API documentation)
|
||||
- Odoo documentation
|
||||
- Framework documentation (SvelteKit/React/Vue)
|
||||
- PWA best practices
|
||||
|
||||
## Development Commands:
|
||||
Remind the user of available commands:
|
||||
```bash
|
||||
npm run dev # Start development server
|
||||
npm run build # Build for production
|
||||
npm run preview # Preview production build
|
||||
npm run lint # Run linter
|
||||
npm run format # Format code
|
||||
```
|
||||
|
||||
## Troubleshooting:
|
||||
|
||||
### npm install fails
|
||||
- Check Node.js version (must be v18+)
|
||||
- Clear npm cache: `npm cache clean --force`
|
||||
- Delete `node_modules` and `package-lock.json`, try again
|
||||
- Check internet connection
|
||||
|
||||
### .env configuration issues
|
||||
- Verify all variables are set (no empty values)
|
||||
- Check for typos in variable names
|
||||
- Ensure no spaces around `=` signs
|
||||
- Verify Odoo credentials are correct
|
||||
|
||||
### Development server won't start
|
||||
- Check if port 5173 is already in use
|
||||
- Try different port: `npm run dev -- --port 3000`
|
||||
- Check for syntax errors in config files
|
||||
- Review console error messages
|
||||
|
||||
### Odoo connection fails
|
||||
- Run `/test-connection` for full diagnostics
|
||||
- Verify `.env` file is loaded correctly
|
||||
- Check Odoo server is accessible
|
||||
- Verify API key is valid
|
||||
|
||||
### Build fails
|
||||
- Check for TypeScript errors (if using TypeScript)
|
||||
- Verify all dependencies are installed
|
||||
- Check for missing environment variables
|
||||
- Review build logs for specific errors
|
||||
|
||||
## After Initialization:
|
||||
Display summary:
|
||||
```
|
||||
🎉 Odoo PWA Initialized Successfully!
|
||||
|
||||
📁 Project: [project-name]
|
||||
🚀 Framework: [SvelteKit/React/Vue]
|
||||
🔗 Dev Server: http://localhost:5173
|
||||
📝 Model: [model-name]
|
||||
|
||||
✅ Next Steps:
|
||||
1. Open http://localhost:5173 in your browser
|
||||
2. Test data sync from Odoo
|
||||
3. Read CLAUDE.md for architecture details
|
||||
4. Customize the UI to match your needs
|
||||
5. Run /deploy-vercel when ready to deploy
|
||||
|
||||
📚 Documentation:
|
||||
- README.md - Getting started guide
|
||||
- CLAUDE.md - Architecture and patterns
|
||||
- API.md - Odoo API client reference
|
||||
|
||||
💡 Helpful Commands:
|
||||
- /test-connection - Verify Odoo integration
|
||||
- /add-model - Add more Odoo models
|
||||
- /deploy-vercel - Deploy to production
|
||||
- /odoo-help - Get plugin help
|
||||
|
||||
Happy coding! 🚀
|
||||
```
|
||||
33
commands/new-react-pwa.md
Normal file
33
commands/new-react-pwa.md
Normal file
@@ -0,0 +1,33 @@
|
||||
Generate a new offline-first Progressive Web App using React framework with Odoo Studio backend integration.
|
||||
|
||||
## What this command does:
|
||||
- Invokes the `create-odoo-pwa` skill with React as the framework
|
||||
- Generates a complete PWA project with smart caching, offline support, and Odoo integration
|
||||
- Creates all necessary configuration files, components, hooks, and deployment setups
|
||||
|
||||
## Required Information:
|
||||
Before starting, gather:
|
||||
1. **Project name** (kebab-case, e.g., "expense-tracker", "inventory-manager")
|
||||
2. **Odoo model name** (without `x_` prefix, e.g., "expense", "inventory")
|
||||
3. **Model display name** (human-readable, e.g., "Expense", "Inventory Item")
|
||||
4. **Deployment target** (optional: vercel, github, cloudflare, netlify)
|
||||
|
||||
## Steps:
|
||||
1. Ask the user for the required information listed above
|
||||
2. Invoke the `create-odoo-pwa` skill with framework set to "react"
|
||||
3. Generate the complete React PWA project structure
|
||||
4. Create comprehensive documentation (README.md, CLAUDE.md, API.md)
|
||||
5. Provide next steps for setup and deployment
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/new-react-pwa` - Interactive mode, will ask for all parameters
|
||||
- User: "Create a React PWA for tracking expenses with Odoo"
|
||||
- User: "Generate an inventory management app using React and Odoo Studio"
|
||||
|
||||
## After generation:
|
||||
Remind the user to:
|
||||
1. Navigate to the project directory
|
||||
2. Copy `.env.example` to `.env` and configure Odoo credentials
|
||||
3. Run `npm install` to install dependencies
|
||||
4. Run `npm run dev` to start development server
|
||||
5. Test the Odoo connection and sync functionality
|
||||
33
commands/new-svelte-pwa.md
Normal file
33
commands/new-svelte-pwa.md
Normal file
@@ -0,0 +1,33 @@
|
||||
Generate a new offline-first Progressive Web App using SvelteKit framework with Odoo Studio backend integration.
|
||||
|
||||
## What this command does:
|
||||
- Invokes the `create-odoo-pwa` skill with SvelteKit as the framework
|
||||
- Generates a complete PWA project with smart caching, offline support, and Odoo integration
|
||||
- Creates all necessary configuration files, routes, components, and deployment setups
|
||||
|
||||
## Required Information:
|
||||
Before starting, gather:
|
||||
1. **Project name** (kebab-case, e.g., "expense-tracker", "inventory-manager")
|
||||
2. **Odoo model name** (without `x_` prefix, e.g., "expense", "inventory")
|
||||
3. **Model display name** (human-readable, e.g., "Expense", "Inventory Item")
|
||||
4. **Deployment target** (optional: vercel, github, cloudflare, netlify)
|
||||
|
||||
## Steps:
|
||||
1. Ask the user for the required information listed above
|
||||
2. Invoke the `create-odoo-pwa` skill with framework set to "sveltekit"
|
||||
3. Generate the complete SvelteKit PWA project structure
|
||||
4. Create comprehensive documentation (README.md, CLAUDE.md, API.md)
|
||||
5. Provide next steps for setup and deployment
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/new-svelte-pwa` - Interactive mode, will ask for all parameters
|
||||
- User: "Create a SvelteKit PWA for tracking expenses with Odoo"
|
||||
- User: "Generate an inventory management app using SvelteKit and Odoo Studio"
|
||||
|
||||
## After generation:
|
||||
Remind the user to:
|
||||
1. Navigate to the project directory
|
||||
2. Copy `.env.example` to `.env` and configure Odoo credentials
|
||||
3. Run `npm install` to install dependencies
|
||||
4. Run `npm run dev` to start development server
|
||||
5. Test the Odoo connection and sync functionality
|
||||
33
commands/new-vue-pwa.md
Normal file
33
commands/new-vue-pwa.md
Normal file
@@ -0,0 +1,33 @@
|
||||
Generate a new offline-first Progressive Web App using Vue framework with Odoo Studio backend integration.
|
||||
|
||||
## What this command does:
|
||||
- Invokes the `create-odoo-pwa` skill with Vue as the framework
|
||||
- Generates a complete PWA project with smart caching, offline support, and Odoo integration
|
||||
- Creates all necessary configuration files, components, composables, and deployment setups
|
||||
|
||||
## Required Information:
|
||||
Before starting, gather:
|
||||
1. **Project name** (kebab-case, e.g., "expense-tracker", "inventory-manager")
|
||||
2. **Odoo model name** (without `x_` prefix, e.g., "expense", "inventory")
|
||||
3. **Model display name** (human-readable, e.g., "Expense", "Inventory Item")
|
||||
4. **Deployment target** (optional: vercel, github, cloudflare, netlify)
|
||||
|
||||
## Steps:
|
||||
1. Ask the user for the required information listed above
|
||||
2. Invoke the `create-odoo-pwa` skill with framework set to "vue"
|
||||
3. Generate the complete Vue PWA project structure
|
||||
4. Create comprehensive documentation (README.md, CLAUDE.md, API.md)
|
||||
5. Provide next steps for setup and deployment
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/new-vue-pwa` - Interactive mode, will ask for all parameters
|
||||
- User: "Create a Vue PWA for tracking expenses with Odoo"
|
||||
- User: "Generate an inventory management app using Vue and Odoo Studio"
|
||||
|
||||
## After generation:
|
||||
Remind the user to:
|
||||
1. Navigate to the project directory
|
||||
2. Copy `.env.example` to `.env` and configure Odoo credentials
|
||||
3. Run `npm install` to install dependencies
|
||||
4. Run `npm run dev` to start development server
|
||||
5. Test the Odoo connection and sync functionality
|
||||
642
commands/optimize.md
Normal file
642
commands/optimize.md
Normal file
@@ -0,0 +1,642 @@
|
||||
Analyze and optimize your Odoo PWA for performance, bundle size, and user experience.
|
||||
|
||||
## What this command does:
|
||||
- Analyzes bundle size
|
||||
- Identifies performance bottlenecks
|
||||
- Suggests optimizations
|
||||
- Checks caching efficiency
|
||||
- Reviews PWA configuration
|
||||
- Provides actionable recommendations
|
||||
|
||||
---
|
||||
|
||||
## Quick Performance Check 🚀
|
||||
|
||||
### Run These Commands:
|
||||
```bash
|
||||
# Build for production
|
||||
npm run build
|
||||
|
||||
# Analyze bundle size
|
||||
npm run build -- --analyze
|
||||
|
||||
# Preview production build
|
||||
npm run preview
|
||||
|
||||
# Run Lighthouse audit
|
||||
# (Chrome DevTools → Lighthouse tab)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Bundle Size Analysis 📦
|
||||
|
||||
### Check Current Size
|
||||
```bash
|
||||
# Build and see output
|
||||
npm run build
|
||||
|
||||
# Typical output:
|
||||
# dist/index.html 1.2 kB
|
||||
# dist/assets/index-abc123.js 45.3 kB
|
||||
# dist/assets/vendor-def456.js 120.5 kB
|
||||
```
|
||||
|
||||
### Analyze Bundle Composition
|
||||
```bash
|
||||
# Install analyzer
|
||||
npm install -D rollup-plugin-visualizer
|
||||
|
||||
# Add to vite.config.js
|
||||
import { visualizer } from 'rollup-plugin-visualizer';
|
||||
|
||||
export default {
|
||||
plugins: [
|
||||
// ...other plugins
|
||||
visualizer({
|
||||
open: true,
|
||||
gzipSize: true,
|
||||
brotliSize: true
|
||||
})
|
||||
]
|
||||
};
|
||||
|
||||
# Build and open report
|
||||
npm run build
|
||||
# Opens stats.html in browser
|
||||
```
|
||||
|
||||
### Target Bundle Sizes:
|
||||
- ✅ **Excellent**: < 200 KB (gzipped)
|
||||
- ⚠️ **Good**: 200-500 KB
|
||||
- ❌ **Needs Work**: > 500 KB
|
||||
|
||||
---
|
||||
|
||||
## Optimization Strategies
|
||||
|
||||
### 1. Code Splitting 📂
|
||||
|
||||
#### Lazy Load Routes
|
||||
**SvelteKit** (automatic):
|
||||
```javascript
|
||||
// Routes are auto-split
|
||||
// src/routes/+page.svelte → separate chunk
|
||||
```
|
||||
|
||||
**React**:
|
||||
```javascript
|
||||
import { lazy, Suspense } from 'react';
|
||||
|
||||
const ExpenseList = lazy(() => import('./ExpenseList'));
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<Suspense fallback={<Loading />}>
|
||||
<ExpenseList />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Vue**:
|
||||
```javascript
|
||||
const ExpenseList = () => import('./ExpenseList.vue');
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/expenses',
|
||||
component: ExpenseList // Lazy loaded
|
||||
}
|
||||
];
|
||||
```
|
||||
|
||||
#### Manual Code Splitting
|
||||
```javascript
|
||||
// Split heavy utility into separate chunk
|
||||
const heavyUtil = await import('./heavyUtility.js');
|
||||
heavyUtil.doSomething();
|
||||
```
|
||||
|
||||
### 2. Tree Shaking 🌳
|
||||
|
||||
#### Remove Unused Code
|
||||
```javascript
|
||||
// Bad: Imports everything
|
||||
import * as utils from './utils';
|
||||
|
||||
// Good: Import only what you need
|
||||
import { formatDate, formatCurrency } from './utils';
|
||||
```
|
||||
|
||||
#### Check for Unused Dependencies
|
||||
```bash
|
||||
npm install -g depcheck
|
||||
depcheck
|
||||
|
||||
# Remove unused packages
|
||||
npm uninstall <unused-package>
|
||||
```
|
||||
|
||||
### 3. Optimize Dependencies 📚
|
||||
|
||||
#### Use Lighter Alternatives
|
||||
```javascript
|
||||
// Instead of moment.js (heavy)
|
||||
import moment from 'moment'; // 72 KB
|
||||
|
||||
// Use date-fns (tree-shakeable)
|
||||
import { format } from 'date-fns'; // ~2 KB
|
||||
|
||||
// Or native Date
|
||||
new Date().toLocaleDateString();
|
||||
```
|
||||
|
||||
#### Common Heavy Packages & Alternatives:
|
||||
- ❌ **moment** (72 KB) → ✅ **date-fns** (tree-shakeable)
|
||||
- ❌ **lodash** (whole) → ✅ **lodash-es** (individual imports)
|
||||
- ❌ **axios** → ✅ **fetch** (built-in)
|
||||
- ❌ **uuid** → ✅ **crypto.randomUUID()** (built-in)
|
||||
|
||||
### 4. Optimize Images 🖼️
|
||||
|
||||
#### Compress Images
|
||||
```bash
|
||||
# Install image optimizer
|
||||
npm install -D vite-plugin-imagemin
|
||||
|
||||
# Add to vite.config.js
|
||||
import viteImagemin from 'vite-plugin-imagemin';
|
||||
|
||||
export default {
|
||||
plugins: [
|
||||
viteImagemin({
|
||||
gifsicle: { optimizationLevel: 7 },
|
||||
optipng: { optimizationLevel: 7 },
|
||||
mozjpeg: { quality: 80 },
|
||||
svgo: { plugins: [{ removeViewBox: false }] }
|
||||
})
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
#### Lazy Load Images
|
||||
```javascript
|
||||
// Native lazy loading
|
||||
<img src="large-image.jpg" loading="lazy" />
|
||||
|
||||
// Or with IntersectionObserver
|
||||
```
|
||||
|
||||
#### Use Appropriate Formats
|
||||
- **WebP** for photos (smaller than JPEG)
|
||||
- **SVG** for icons/logos
|
||||
- **PNG** only when transparency needed
|
||||
|
||||
### 5. Minimize JavaScript ⚡
|
||||
|
||||
#### Enable Minification (default in Vite)
|
||||
```javascript
|
||||
// vite.config.js
|
||||
export default {
|
||||
build: {
|
||||
minify: 'terser', // or 'esbuild' (faster)
|
||||
terserOptions: {
|
||||
compress: {
|
||||
drop_console: true, // Remove console.logs
|
||||
drop_debugger: true
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### Remove Development Code
|
||||
```javascript
|
||||
// Use environment variables
|
||||
if (import.meta.env.DEV) {
|
||||
console.log('Debug info'); // Removed in production
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Caching Optimization 💾
|
||||
|
||||
### 1. Optimize Cache Strategy
|
||||
|
||||
#### Review Cache Settings
|
||||
```javascript
|
||||
// In cache store
|
||||
const CACHE_VALIDITY = 5 * 60 * 1000; // 5 minutes
|
||||
|
||||
// Consider your use case:
|
||||
// - Frequently changing data: 1-2 minutes
|
||||
// - Moderate updates: 5-10 minutes
|
||||
// - Rarely changes: 30-60 minutes
|
||||
```
|
||||
|
||||
#### Limit Initial Load
|
||||
```javascript
|
||||
// Don't fetch everything at once
|
||||
const records = await odoo.searchRecords(
|
||||
model,
|
||||
[],
|
||||
fields,
|
||||
100 // Limit to 100 records initially
|
||||
);
|
||||
|
||||
// Load more on demand (pagination)
|
||||
```
|
||||
|
||||
### 2. Optimize Sync Frequency
|
||||
```javascript
|
||||
// Adjust sync interval based on needs
|
||||
const SYNC_INTERVAL = 5 * 60 * 1000; // 5 minutes
|
||||
|
||||
// Balance:
|
||||
// - More frequent: Better UX, more bandwidth
|
||||
// - Less frequent: Less bandwidth, slightly stale data
|
||||
```
|
||||
|
||||
### 3. Selective Caching
|
||||
```javascript
|
||||
// Only cache fields you need
|
||||
const fields = [
|
||||
'x_studio_name',
|
||||
'x_studio_amount',
|
||||
'x_studio_date'
|
||||
// Don't fetch unnecessary fields
|
||||
];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PWA Optimization 📱
|
||||
|
||||
### 1. Service Worker Configuration
|
||||
|
||||
#### Optimize Caching Strategy
|
||||
```javascript
|
||||
// In service worker or vite-plugin-pwa config
|
||||
VitePWA({
|
||||
workbox: {
|
||||
runtimeCaching: [
|
||||
{
|
||||
urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/,
|
||||
handler: 'CacheFirst',
|
||||
options: {
|
||||
cacheName: 'google-fonts',
|
||||
expiration: {
|
||||
maxEntries: 10,
|
||||
maxAgeSeconds: 60 * 60 * 24 * 365 // 1 year
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
urlPattern: /^https:\/\/.*\.odoo\.com\/.*/,
|
||||
handler: 'NetworkFirst',
|
||||
options: {
|
||||
cacheName: 'odoo-api',
|
||||
networkTimeoutSeconds: 3
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 2. Optimize Manifest
|
||||
```json
|
||||
{
|
||||
"name": "Expense Tracker",
|
||||
"short_name": "Expenses",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#ffffff",
|
||||
"theme_color": "#0066cc",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
},
|
||||
{
|
||||
"src": "/icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Optimize Icons
|
||||
```bash
|
||||
# Use optimized PNG or WebP
|
||||
# Compress images
|
||||
# Provide multiple sizes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Network Optimization 🌐
|
||||
|
||||
### 1. Reduce API Calls
|
||||
|
||||
#### Batch Requests
|
||||
```javascript
|
||||
// Bad: Multiple calls
|
||||
const expenses = await fetchExpenses();
|
||||
const tasks = await fetchTasks();
|
||||
const partners = await fetchPartners();
|
||||
|
||||
// Good: Single call (if Odoo supports)
|
||||
const data = await fetchAll(['expenses', 'tasks', 'partners']);
|
||||
```
|
||||
|
||||
#### Cache Partner Names
|
||||
```javascript
|
||||
// Fetch once, reuse
|
||||
const partners = await odoo.fetchPartners();
|
||||
localStorage.setItem('partnerCache', JSON.stringify(partners));
|
||||
|
||||
// Later, use cached data
|
||||
const cached = JSON.parse(localStorage.getItem('partnerCache'));
|
||||
```
|
||||
|
||||
### 2. Incremental Loading
|
||||
```javascript
|
||||
// Load initial data
|
||||
const initial = await fetchExpenses({ limit: 20 });
|
||||
|
||||
// Load more on scroll
|
||||
function onScroll() {
|
||||
if (nearBottom) {
|
||||
loadMore();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Optimize Requests
|
||||
```javascript
|
||||
// Only fetch fields you display
|
||||
const fields = ['id', 'x_studio_name', 'x_studio_amount'];
|
||||
|
||||
// Use appropriate domain filters
|
||||
const domain = [
|
||||
['x_studio_date', '>=', lastMonth],
|
||||
['x_studio_status', '!=', 'deleted']
|
||||
];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## UI Performance 🎨
|
||||
|
||||
### 1. Virtual Scrolling
|
||||
For long lists:
|
||||
```javascript
|
||||
// SvelteKit
|
||||
import { VirtualList } from 'svelte-virtual-list';
|
||||
|
||||
<VirtualList items={expenses} let:item>
|
||||
<ExpenseCard expense={item} />
|
||||
</VirtualList>
|
||||
|
||||
// React
|
||||
import { FixedSizeList } from 'react-window';
|
||||
|
||||
// Vue
|
||||
import { RecycleScroller } from 'vue-virtual-scroller';
|
||||
```
|
||||
|
||||
### 2. Debounce Search
|
||||
```javascript
|
||||
import { debounce } from './utils';
|
||||
|
||||
const handleSearch = debounce((query) => {
|
||||
searchExpenses(query);
|
||||
}, 300); // Wait 300ms after typing stops
|
||||
```
|
||||
|
||||
### 3. Optimize Rendering
|
||||
```javascript
|
||||
// SvelteKit: Use keyed each blocks
|
||||
{#each expenses as expense (expense.id)}
|
||||
<ExpenseCard {expense} />
|
||||
{/each}
|
||||
|
||||
// React: Use keys and memo
|
||||
const ExpenseCard = memo(({ expense }) => {
|
||||
// ...
|
||||
});
|
||||
|
||||
expenses.map(expense => (
|
||||
<ExpenseCard key={expense.id} expense={expense} />
|
||||
));
|
||||
|
||||
// Vue: Use v-memo
|
||||
<ExpenseCard
|
||||
v-for="expense in expenses"
|
||||
:key="expense.id"
|
||||
:expense="expense"
|
||||
v-memo="[expense.id]"
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Build Optimization 🔨
|
||||
|
||||
### Vite Config Optimizations
|
||||
```javascript
|
||||
// vite.config.js
|
||||
export default {
|
||||
build: {
|
||||
// Target modern browsers
|
||||
target: 'es2020',
|
||||
|
||||
// Optimize chunks
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
vendor: ['svelte', '@sveltejs/kit'],
|
||||
odoo: ['./src/lib/odoo.js', './src/lib/stores']
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Compression
|
||||
minify: 'esbuild', // Faster than terser
|
||||
|
||||
// Source maps (only for debugging)
|
||||
sourcemap: false
|
||||
},
|
||||
|
||||
// Optimize dependencies
|
||||
optimizeDeps: {
|
||||
include: ['date-fns', 'lodash-es']
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Lighthouse Audit 💡
|
||||
|
||||
### Run Lighthouse
|
||||
1. Open Chrome DevTools
|
||||
2. Go to Lighthouse tab
|
||||
3. Select categories:
|
||||
- ✅ Performance
|
||||
- ✅ Progressive Web App
|
||||
- ✅ Best Practices
|
||||
- ✅ Accessibility
|
||||
- ✅ SEO
|
||||
4. Click "Analyze page load"
|
||||
|
||||
### Target Scores:
|
||||
- **Performance**: > 90
|
||||
- **PWA**: 100
|
||||
- **Best Practices**: > 95
|
||||
- **Accessibility**: > 90
|
||||
- **SEO**: > 90
|
||||
|
||||
### Common Issues & Fixes:
|
||||
|
||||
#### Low Performance Score
|
||||
- Reduce bundle size
|
||||
- Optimize images
|
||||
- Enable caching
|
||||
- Lazy load resources
|
||||
|
||||
#### PWA Issues
|
||||
- Fix manifest.json
|
||||
- Register service worker
|
||||
- Add offline support
|
||||
- Provide app icons
|
||||
|
||||
#### Accessibility Issues
|
||||
- Add alt text to images
|
||||
- Use semantic HTML
|
||||
- Ensure color contrast
|
||||
- Add ARIA labels
|
||||
|
||||
---
|
||||
|
||||
## Performance Monitoring 📊
|
||||
|
||||
### Add Performance Tracking
|
||||
```javascript
|
||||
// Measure initial load
|
||||
window.addEventListener('load', () => {
|
||||
const perfData = performance.getEntriesByType('navigation')[0];
|
||||
|
||||
console.log('Load time:', perfData.loadEventEnd - perfData.fetchStart);
|
||||
console.log('DOM ready:', perfData.domContentLoadedEventEnd - perfData.fetchStart);
|
||||
});
|
||||
|
||||
// Measure sync time
|
||||
console.time('sync');
|
||||
await expenseCache.refresh();
|
||||
console.timeEnd('sync');
|
||||
```
|
||||
|
||||
### Use Web Vitals
|
||||
```bash
|
||||
npm install web-vitals
|
||||
|
||||
# In app
|
||||
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
|
||||
|
||||
getCLS(console.log);
|
||||
getFID(console.log);
|
||||
getFCP(console.log);
|
||||
getLCP(console.log);
|
||||
getTTFB(console.log);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Optimization Checklist ✅
|
||||
|
||||
### Bundle Size:
|
||||
```
|
||||
□ Analyzed bundle composition
|
||||
□ Removed unused dependencies
|
||||
□ Lazy loaded routes/components
|
||||
□ Optimized images
|
||||
□ Tree-shaking enabled
|
||||
□ Minification enabled
|
||||
□ Total size < 500 KB (gzipped)
|
||||
```
|
||||
|
||||
### Caching:
|
||||
```
|
||||
□ Optimal cache validity period
|
||||
□ Incremental sync working
|
||||
□ Selective field fetching
|
||||
□ Partner name caching
|
||||
□ Appropriate sync frequency
|
||||
□ IndexedDB optimized
|
||||
```
|
||||
|
||||
### PWA:
|
||||
```
|
||||
□ Service worker registered
|
||||
□ Offline mode works
|
||||
□ App installable
|
||||
□ Icons optimized
|
||||
□ Manifest configured
|
||||
□ Fast load time
|
||||
```
|
||||
|
||||
### Performance:
|
||||
```
|
||||
□ Lighthouse score > 90
|
||||
□ Initial load < 3s
|
||||
□ Sync time < 2s
|
||||
□ No console errors
|
||||
□ Smooth scrolling
|
||||
□ Fast navigation
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/optimize` - Run optimization checks
|
||||
- User: "Make my app faster"
|
||||
- User: "Reduce bundle size"
|
||||
- User: "Optimize performance"
|
||||
|
||||
## Related Commands:
|
||||
- `/test-connection` - Test after optimization
|
||||
- `/update-deps` - Update to faster versions
|
||||
- `/troubleshoot` - Fix performance issues
|
||||
- `/help` - More information
|
||||
|
||||
---
|
||||
|
||||
## Quick Wins 🎯
|
||||
|
||||
### Immediate Optimizations:
|
||||
1. **Enable compression** (already in Vite)
|
||||
2. **Remove console.logs** in production
|
||||
3. **Lazy load routes** (easy with frameworks)
|
||||
4. **Optimize images** (use WebP)
|
||||
5. **Limit initial data fetch** (pagination)
|
||||
|
||||
### Medium Effort:
|
||||
1. **Analyze and split bundles**
|
||||
2. **Replace heavy dependencies**
|
||||
3. **Implement virtual scrolling**
|
||||
4. **Optimize service worker**
|
||||
5. **Add performance monitoring**
|
||||
|
||||
### Long Term:
|
||||
1. **Regular Lighthouse audits**
|
||||
2. **Monitor real user metrics**
|
||||
3. **Continuous optimization**
|
||||
4. **Keep dependencies updated**
|
||||
5. **Review and refactor regularly**
|
||||
87
commands/setup-env.md
Normal file
87
commands/setup-env.md
Normal file
@@ -0,0 +1,87 @@
|
||||
Interactive setup wizard for configuring Odoo PWA environment variables.
|
||||
|
||||
## What this command does:
|
||||
- Guides the user through setting up their `.env` file
|
||||
- Validates Odoo connection credentials
|
||||
- Tests API connectivity
|
||||
- Configures model-specific settings
|
||||
- Provides troubleshooting help if connection fails
|
||||
|
||||
## Required Information:
|
||||
Gather from the user:
|
||||
1. **Odoo Instance URL** (e.g., "https://yourcompany.odoo.com")
|
||||
2. **Database Name** (e.g., "yourcompany-main")
|
||||
3. **API Key** (from Odoo user preferences)
|
||||
4. **Username/Email** (Odoo user email)
|
||||
5. **Primary Model Name** (e.g., "x_expense", "x_inventory")
|
||||
|
||||
## Steps:
|
||||
1. Check if `.env.example` exists in the current directory
|
||||
2. If not, ask if this is an Odoo PWA project
|
||||
3. Ask the user for each environment variable interactively
|
||||
4. Validate URL format (must start with http:// or https://)
|
||||
5. Create or update `.env` file with the provided values
|
||||
6. Test the connection by making a simple API call to Odoo
|
||||
7. If connection fails, provide troubleshooting steps
|
||||
8. Display success message with next steps
|
||||
|
||||
## Environment Variables to Set:
|
||||
```bash
|
||||
# Odoo Instance Configuration
|
||||
VITE_ODOO_URL=https://yourcompany.odoo.com
|
||||
VITE_ODOO_DB=yourcompany-main
|
||||
|
||||
# Authentication (keep these secret!)
|
||||
ODOO_API_KEY=your_api_key_here
|
||||
ODOO_USERNAME=your.email@company.com
|
||||
|
||||
# Model Configuration
|
||||
VITE_MODEL_NAME=x_expense
|
||||
VITE_MODEL_DISPLAY_NAME=Expense
|
||||
```
|
||||
|
||||
## Validation Tests:
|
||||
After creating `.env`, run these checks:
|
||||
1. Test Odoo URL is reachable
|
||||
2. Verify API key is valid
|
||||
3. Check if the model exists in Odoo
|
||||
4. Test read permissions on the model
|
||||
5. Verify required fields are accessible
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/setup-env` - Interactive setup wizard
|
||||
- User: "Help me configure my Odoo credentials"
|
||||
- User: "Set up environment variables for Odoo PWA"
|
||||
|
||||
## Security Reminders:
|
||||
After setup, remind the user:
|
||||
1. ✅ `.env` should be in `.gitignore` (verify this)
|
||||
2. ✅ Never commit API keys to version control
|
||||
3. ✅ Use different credentials for development and production
|
||||
4. ✅ For deployment, set environment variables in the hosting platform
|
||||
5. ✅ Rotate API keys periodically
|
||||
|
||||
## Troubleshooting Common Issues:
|
||||
|
||||
### Connection Failed
|
||||
- Verify Odoo URL is correct and accessible
|
||||
- Check if API key is valid (generate new one in Odoo)
|
||||
- Ensure username matches the API key owner
|
||||
- Check firewall/network restrictions
|
||||
|
||||
### Model Not Found
|
||||
- Verify the model exists in Odoo Studio
|
||||
- Check model name has `x_` prefix
|
||||
- Ensure user has access permissions to the model
|
||||
|
||||
### Authentication Error
|
||||
- Regenerate API key in Odoo (Settings → Users → API Keys)
|
||||
- Verify database name is correct
|
||||
- Check if account is active and not locked
|
||||
|
||||
## After Setup:
|
||||
Remind the user to:
|
||||
1. Restart the development server to load new environment variables
|
||||
2. Test the application and verify data loads correctly
|
||||
3. Keep the `.env.example` file updated for team members
|
||||
4. Document any custom configuration in project README
|
||||
230
commands/test-connection.md
Normal file
230
commands/test-connection.md
Normal file
@@ -0,0 +1,230 @@
|
||||
Test Odoo API connection and sync functionality to diagnose issues.
|
||||
|
||||
## What this command does:
|
||||
- Validates Odoo connection credentials
|
||||
- Tests API authentication
|
||||
- Verifies model access and permissions
|
||||
- Checks sync functionality
|
||||
- Runs diagnostic tests on cache stores
|
||||
- Provides detailed error reporting and solutions
|
||||
|
||||
## Prerequisites:
|
||||
Before testing, ensure:
|
||||
1. ✅ `.env` file exists and is configured
|
||||
2. ✅ Current directory is an Odoo PWA project
|
||||
3. ✅ Development server can be started
|
||||
4. ✅ Internet connection is available
|
||||
|
||||
## Diagnostic Tests to Run:
|
||||
|
||||
### 1. Environment Configuration Check
|
||||
Verify all required environment variables are set:
|
||||
- `VITE_ODOO_URL` - Odoo instance URL
|
||||
- `VITE_ODOO_DB` - Database name
|
||||
- `ODOO_API_KEY` - API authentication key
|
||||
- `ODOO_USERNAME` - User email/username
|
||||
- `VITE_MODEL_NAME` - Primary model name
|
||||
|
||||
### 2. Network Connectivity Test
|
||||
```bash
|
||||
# Test if Odoo URL is reachable
|
||||
curl -I [ODOO_URL]
|
||||
```
|
||||
|
||||
Expected: HTTP 200 or 301/302 redirect
|
||||
|
||||
### 3. API Authentication Test
|
||||
Make a test API call to verify credentials:
|
||||
```javascript
|
||||
POST /api/odoo
|
||||
{
|
||||
"action": "search",
|
||||
"model": "res.partner",
|
||||
"domain": [],
|
||||
"fields": ["id", "name"],
|
||||
"limit": 1
|
||||
}
|
||||
```
|
||||
|
||||
Expected: Returns at least one partner record
|
||||
|
||||
### 4. Model Access Test
|
||||
Verify the configured model exists and is accessible:
|
||||
```javascript
|
||||
POST /api/odoo
|
||||
{
|
||||
"action": "search_model",
|
||||
"model": "[VITE_MODEL_NAME]",
|
||||
"domain": [],
|
||||
"fields": ["id"],
|
||||
"limit": 1
|
||||
}
|
||||
```
|
||||
|
||||
Expected: Returns records or empty array (not an error)
|
||||
|
||||
### 5. CRUD Operations Test
|
||||
Test each operation:
|
||||
- **Create**: Create a test record
|
||||
- **Read**: Fetch the created record
|
||||
- **Update**: Modify the record
|
||||
- **Delete**: Remove the test record
|
||||
|
||||
### 6. Cache Functionality Test
|
||||
Verify cache stores work correctly:
|
||||
- localStorage read/write
|
||||
- IndexedDB read/write
|
||||
- Cache expiration logic
|
||||
- Sync mechanism
|
||||
|
||||
### 7. Sync Performance Test
|
||||
Measure sync performance:
|
||||
- Initial load time
|
||||
- Incremental sync time
|
||||
- Number of records synced
|
||||
- Network request count
|
||||
|
||||
## Steps:
|
||||
1. Read and validate `.env` file
|
||||
2. Parse environment variables
|
||||
3. Run each diagnostic test in sequence
|
||||
4. Log results with timestamps
|
||||
5. Identify failing tests
|
||||
6. Provide specific solutions for failures
|
||||
7. Generate diagnostic report
|
||||
|
||||
## Output Format:
|
||||
```
|
||||
🧪 Odoo PWA Connection Diagnostics
|
||||
================================
|
||||
|
||||
✅ Environment Configuration: PASSED
|
||||
- ODOO_URL: https://yourcompany.odoo.com
|
||||
- DATABASE: yourcompany-main
|
||||
- MODEL: x_expense
|
||||
|
||||
✅ Network Connectivity: PASSED
|
||||
- Odoo server reachable
|
||||
- Response time: 234ms
|
||||
|
||||
✅ API Authentication: PASSED
|
||||
- API key valid
|
||||
- User authenticated: your.email@company.com
|
||||
|
||||
✅ Model Access: PASSED
|
||||
- Model exists: x_expense
|
||||
- Read permission: Yes
|
||||
- Write permission: Yes
|
||||
|
||||
✅ CRUD Operations: PASSED
|
||||
- Create: ✅ Record created (ID: 123)
|
||||
- Read: ✅ Record fetched
|
||||
- Update: ✅ Record updated
|
||||
- Delete: ✅ Record deleted
|
||||
|
||||
✅ Cache Functionality: PASSED
|
||||
- localStorage: Working
|
||||
- IndexedDB: Working
|
||||
- Sync interval: 3 minutes
|
||||
|
||||
✅ Sync Performance: PASSED
|
||||
- Initial load: 1.2s (45 records)
|
||||
- Incremental sync: 0.3s (2 new records)
|
||||
- Network requests: 3
|
||||
|
||||
================================
|
||||
🎉 All tests passed! Your Odoo PWA is working correctly.
|
||||
```
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/test-connection` - Run full diagnostic suite
|
||||
- User: "Test my Odoo connection"
|
||||
- User: "Why isn't data syncing from Odoo?"
|
||||
- User: "Diagnose Odoo API issues"
|
||||
|
||||
## Common Issues and Solutions:
|
||||
|
||||
### ❌ Connection Failed
|
||||
**Error**: Cannot reach Odoo URL
|
||||
**Solutions**:
|
||||
- Verify URL is correct (include https://)
|
||||
- Check internet connection
|
||||
- Test URL in browser
|
||||
- Check firewall/VPN settings
|
||||
|
||||
### ❌ Authentication Failed
|
||||
**Error**: Invalid API key or credentials
|
||||
**Solutions**:
|
||||
- Regenerate API key in Odoo (Settings → Users → API Keys)
|
||||
- Verify username matches API key owner
|
||||
- Check for typos in `.env` file
|
||||
- Ensure API key has not expired
|
||||
|
||||
### ❌ Model Not Found
|
||||
**Error**: Model doesn't exist or no access
|
||||
**Solutions**:
|
||||
- Verify model exists in Odoo Studio
|
||||
- Check model name includes `x_` prefix
|
||||
- Verify user has read/write permissions
|
||||
- Check model is published (not in draft mode)
|
||||
|
||||
### ❌ CORS Error
|
||||
**Error**: Blocked by CORS policy
|
||||
**Solutions**:
|
||||
- Use server-side API proxy (recommended)
|
||||
- Configure CORS in Odoo (not recommended)
|
||||
- Check API route is working correctly
|
||||
|
||||
### ❌ Sync Not Working
|
||||
**Error**: Records not updating
|
||||
**Solutions**:
|
||||
- Check browser console for errors
|
||||
- Verify sync interval is running
|
||||
- Clear cache and try again
|
||||
- Check Odoo server is not down
|
||||
|
||||
### ❌ Permission Denied
|
||||
**Error**: Cannot create/update records
|
||||
**Solutions**:
|
||||
- Verify user has write permission on model
|
||||
- Check required fields are included
|
||||
- Verify field types match expectations
|
||||
- Check for validation rules in Odoo
|
||||
|
||||
## Development Tools:
|
||||
Provide user with helpful commands:
|
||||
```bash
|
||||
# Watch network requests
|
||||
# Open browser DevTools → Network tab
|
||||
|
||||
# View cache contents
|
||||
localStorage.getItem('[model]Cache')
|
||||
|
||||
# Force cache clear
|
||||
localStorage.clear()
|
||||
|
||||
# Monitor sync in console
|
||||
# Look for "Syncing..." messages
|
||||
```
|
||||
|
||||
## After Testing:
|
||||
If all tests pass:
|
||||
- Confirm the application is working correctly
|
||||
- Suggest running tests periodically
|
||||
- Recommend monitoring in production
|
||||
|
||||
If tests fail:
|
||||
- Provide specific error messages
|
||||
- Offer step-by-step troubleshooting
|
||||
- Suggest checking Odoo server logs
|
||||
- Offer to help fix configuration
|
||||
|
||||
## Advanced Diagnostics:
|
||||
For complex issues:
|
||||
1. Export full diagnostic report
|
||||
2. Check Odoo server logs
|
||||
3. Review browser console errors
|
||||
4. Analyze network traffic
|
||||
5. Test with different API keys
|
||||
6. Try with different models
|
||||
7. Compare with working examples
|
||||
694
commands/troubleshoot.md
Normal file
694
commands/troubleshoot.md
Normal file
@@ -0,0 +1,694 @@
|
||||
Common issues and solutions for Odoo PWA projects.
|
||||
|
||||
## What this command does:
|
||||
- Lists common problems and their solutions
|
||||
- Provides step-by-step debugging guides
|
||||
- Offers troubleshooting workflows
|
||||
- Helps diagnose connection, sync, and build issues
|
||||
- Links to relevant documentation and tools
|
||||
|
||||
---
|
||||
|
||||
## Quick Diagnostic Checklist ✅
|
||||
|
||||
Before diving into specific issues, run through this checklist:
|
||||
|
||||
```
|
||||
□ .env file exists and has all required variables
|
||||
□ Odoo URL is correct and reachable
|
||||
□ API key is valid and not expired
|
||||
□ Database name is correct
|
||||
□ Model name includes x_ prefix
|
||||
□ Development server is running
|
||||
□ No errors in browser console
|
||||
□ Internet connection is working
|
||||
□ Node.js version is 18 or higher
|
||||
```
|
||||
|
||||
**Quick Test:** Run `/test-connection` to diagnose most issues automatically.
|
||||
|
||||
---
|
||||
|
||||
## Connection Issues 🔌
|
||||
|
||||
### Problem: Cannot connect to Odoo
|
||||
**Symptoms:**
|
||||
- "Connection refused" error
|
||||
- "Network error" in console
|
||||
- Timeout errors
|
||||
- No data loading
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### 1. Verify Odoo URL
|
||||
```bash
|
||||
# Test if URL is reachable
|
||||
curl -I https://yourcompany.odoo.com
|
||||
|
||||
# Expected: HTTP 200 or 301/302
|
||||
```
|
||||
|
||||
**Common mistakes:**
|
||||
- Missing `https://`
|
||||
- Extra trailing slash
|
||||
- Wrong subdomain
|
||||
- Typo in URL
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
# Wrong
|
||||
VITE_ODOO_URL=yourcompany.odoo.com
|
||||
VITE_ODOO_URL=https://yourcompany.odoo.com/
|
||||
|
||||
# Right
|
||||
VITE_ODOO_URL=https://yourcompany.odoo.com
|
||||
```
|
||||
|
||||
#### 2. Check firewall / VPN
|
||||
- Try accessing Odoo URL in browser
|
||||
- Disable VPN temporarily
|
||||
- Check corporate firewall rules
|
||||
- Try from different network
|
||||
|
||||
#### 3. Verify environment variables loaded
|
||||
```javascript
|
||||
// Add to your code temporarily
|
||||
console.log('Odoo URL:', import.meta.env.VITE_ODOO_URL);
|
||||
console.log('Database:', import.meta.env.VITE_ODOO_DB);
|
||||
```
|
||||
|
||||
**If undefined:**
|
||||
- Restart development server
|
||||
- Check variable names (case-sensitive)
|
||||
- Ensure variables start with `VITE_`
|
||||
|
||||
---
|
||||
|
||||
## Authentication Issues 🔐
|
||||
|
||||
### Problem: Invalid API key / Authentication failed
|
||||
**Symptoms:**
|
||||
- "Invalid credentials" error
|
||||
- "Access denied" message
|
||||
- 401 Unauthorized errors
|
||||
- UID is null
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### 1. Regenerate API Key
|
||||
1. Log into Odoo
|
||||
2. Go to Settings → Users & Companies → Users
|
||||
3. Open your user record
|
||||
4. Go to "API Keys" tab
|
||||
5. Click "New API Key"
|
||||
6. Copy the key immediately (shown only once!)
|
||||
7. Update `.env` file:
|
||||
```bash
|
||||
ODOO_API_KEY=your_new_api_key_here
|
||||
```
|
||||
8. Restart development server
|
||||
|
||||
#### 2. Verify username matches
|
||||
```bash
|
||||
# Username must match the API key owner
|
||||
ODOO_USERNAME=john.doe@company.com # ✅ Correct
|
||||
ODOO_USERNAME=John Doe # ❌ Wrong
|
||||
```
|
||||
|
||||
#### 3. Check user permissions
|
||||
- Ensure user has access to the model
|
||||
- Verify read/write permissions
|
||||
- Check if user account is active
|
||||
- Verify not locked out
|
||||
|
||||
#### 4. Test authentication manually
|
||||
```javascript
|
||||
// In browser console
|
||||
fetch('/api/odoo', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'search',
|
||||
model: 'res.partner',
|
||||
domain: [],
|
||||
fields: ['name'],
|
||||
limit: 1
|
||||
})
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(console.log);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Model Access Issues 📋
|
||||
|
||||
### Problem: Model not found / No records returned
|
||||
**Symptoms:**
|
||||
- "Model does not exist" error
|
||||
- Empty array returned
|
||||
- "Access rights" error
|
||||
- Records don't appear
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### 1. Verify model name
|
||||
```bash
|
||||
# Check model name includes x_ prefix
|
||||
VITE_MODEL_NAME=x_expense # ✅ Correct
|
||||
VITE_MODEL_NAME=expense # ❌ Wrong
|
||||
```
|
||||
|
||||
#### 2. Check model exists in Odoo
|
||||
1. Log into Odoo
|
||||
2. Go to Settings → Technical → Database Structure → Models
|
||||
3. Search for your model name
|
||||
4. Verify it exists and is active
|
||||
|
||||
#### 3. Check field names
|
||||
```javascript
|
||||
// Fields must use full name with x_studio_ prefix
|
||||
const fields = [
|
||||
'x_studio_name', // ✅ Correct
|
||||
'x_studio_amount', // ✅ Correct
|
||||
'name', // ❌ Wrong (unless it's a standard field)
|
||||
'amount' // ❌ Wrong
|
||||
];
|
||||
```
|
||||
|
||||
#### 4. Verify permissions
|
||||
- User must have read access to model
|
||||
- Check access rights in Odoo Studio
|
||||
- Verify record rules don't filter all records
|
||||
- Test with admin user
|
||||
|
||||
#### 5. Check if model is published
|
||||
- In Odoo Studio, verify model is not in draft mode
|
||||
- Ensure model is accessible via API
|
||||
- Check if model requires special access
|
||||
|
||||
---
|
||||
|
||||
## Sync Issues 🔄
|
||||
|
||||
### Problem: Data not syncing
|
||||
**Symptoms:**
|
||||
- Old data displayed
|
||||
- Changes don't appear
|
||||
- "Last synced" time not updating
|
||||
- Background sync not working
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### 1. Check browser console
|
||||
Look for:
|
||||
- Network errors
|
||||
- JavaScript errors
|
||||
- CORS errors
|
||||
- Authentication errors
|
||||
|
||||
#### 2. Verify sync mechanism
|
||||
```javascript
|
||||
// Check if sync is running
|
||||
// Look for these console logs:
|
||||
"Syncing x_expense..."
|
||||
"Fetched X new records"
|
||||
"Cache updated"
|
||||
```
|
||||
|
||||
#### 3. Force refresh
|
||||
```javascript
|
||||
// In browser console
|
||||
expenseCache.refresh();
|
||||
```
|
||||
|
||||
#### 4. Clear cache and reload
|
||||
```javascript
|
||||
// In browser console
|
||||
localStorage.clear();
|
||||
// Then refresh page
|
||||
```
|
||||
|
||||
#### 5. Check sync interval
|
||||
```javascript
|
||||
// Verify sync timer is running
|
||||
// Default: 3 minutes (180,000ms)
|
||||
// Look in cache store for:
|
||||
setInterval(() => sync(), 180000);
|
||||
```
|
||||
|
||||
#### 6. Test incremental sync
|
||||
```javascript
|
||||
// Check lastRecordId is updating
|
||||
const cacheData = localStorage.getItem('expenseCache');
|
||||
console.log(JSON.parse(cacheData));
|
||||
// Should show: { lastRecordId: X, lastSyncTime: Y }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Offline Mode Issues 📵
|
||||
|
||||
### Problem: Offline mode not working
|
||||
**Symptoms:**
|
||||
- App doesn't work without internet
|
||||
- "No connection" errors when offline
|
||||
- Service worker not registered
|
||||
- Data not available offline
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### 1. Verify service worker registered
|
||||
```javascript
|
||||
// In browser console
|
||||
navigator.serviceWorker.getRegistration()
|
||||
.then(reg => console.log('Service Worker:', reg));
|
||||
```
|
||||
|
||||
#### 2. Check cache stores
|
||||
```javascript
|
||||
// Verify data is cached
|
||||
localStorage.getItem('expenseCache');
|
||||
// Should return JSON string
|
||||
|
||||
// Check IndexedDB
|
||||
// Open DevTools → Application → IndexedDB
|
||||
// Look for your database and tables
|
||||
```
|
||||
|
||||
#### 3. Test offline mode
|
||||
1. Load app while online
|
||||
2. Open DevTools → Network tab
|
||||
3. Enable "Offline" checkbox
|
||||
4. Refresh page
|
||||
5. App should still work
|
||||
|
||||
#### 4. Build and test production
|
||||
```bash
|
||||
# Offline mode works better in production build
|
||||
npm run build
|
||||
npm run preview
|
||||
```
|
||||
|
||||
#### 5. Check manifest.json
|
||||
Verify PWA manifest is correct:
|
||||
- Located in `/static/manifest.json`
|
||||
- Has correct `start_url`
|
||||
- Has valid icons
|
||||
|
||||
---
|
||||
|
||||
## Build / Deployment Issues 🚀
|
||||
|
||||
### Problem: Build fails
|
||||
**Symptoms:**
|
||||
- `npm run build` returns errors
|
||||
- TypeScript errors
|
||||
- Module not found errors
|
||||
- Build process hangs
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### 1. Check Node version
|
||||
```bash
|
||||
node --version
|
||||
# Must be v18 or higher
|
||||
|
||||
# If too old:
|
||||
nvm install 18
|
||||
nvm use 18
|
||||
```
|
||||
|
||||
#### 2. Clean install
|
||||
```bash
|
||||
rm -rf node_modules package-lock.json
|
||||
npm install
|
||||
```
|
||||
|
||||
#### 3. Check for errors
|
||||
```bash
|
||||
# Run build with verbose output
|
||||
npm run build -- --verbose
|
||||
```
|
||||
|
||||
#### 4. Verify environment variables
|
||||
```bash
|
||||
# For production build, set env vars:
|
||||
VITE_ODOO_URL=https://yourcompany.odoo.com \
|
||||
VITE_ODOO_DB=yourcompany-main \
|
||||
npm run build
|
||||
```
|
||||
|
||||
#### 5. Check imports
|
||||
- Verify all imports are correct
|
||||
- Check for circular dependencies
|
||||
- Ensure all files exist
|
||||
|
||||
---
|
||||
|
||||
### Problem: Deployment fails
|
||||
**Symptoms:**
|
||||
- Vercel/Netlify build fails
|
||||
- Environment variables not working
|
||||
- 404 errors in production
|
||||
- Blank page after deployment
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### 1. Set environment variables
|
||||
In hosting dashboard:
|
||||
- Add all `VITE_*` variables
|
||||
- Add `ODOO_API_KEY`
|
||||
- Add `ODOO_USERNAME`
|
||||
- Redeploy after adding
|
||||
|
||||
#### 2. Check build logs
|
||||
- Review deployment logs
|
||||
- Look for specific errors
|
||||
- Check Node version in platform
|
||||
|
||||
#### 3. Test build locally
|
||||
```bash
|
||||
npm run build
|
||||
npm run preview
|
||||
# Test at http://localhost:4173
|
||||
```
|
||||
|
||||
#### 4. Verify base path
|
||||
```javascript
|
||||
// For GitHub Pages or subpath deployment
|
||||
// vite.config.js
|
||||
export default {
|
||||
base: '/your-repo-name/'
|
||||
};
|
||||
```
|
||||
|
||||
#### 5. Check API routes
|
||||
- Ensure serverless functions deploy correctly
|
||||
- Verify function size < 50MB
|
||||
- Check function logs in platform dashboard
|
||||
|
||||
---
|
||||
|
||||
## Performance Issues ⚡
|
||||
|
||||
### Problem: App is slow
|
||||
**Symptoms:**
|
||||
- Slow initial load
|
||||
- Laggy UI
|
||||
- Long sync times
|
||||
- High memory usage
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### 1. Optimize initial load
|
||||
```javascript
|
||||
// Limit initial fetch
|
||||
const records = await odoo.searchRecords(
|
||||
model,
|
||||
[],
|
||||
fields,
|
||||
100 // Only fetch first 100
|
||||
);
|
||||
```
|
||||
|
||||
#### 2. Add pagination
|
||||
```javascript
|
||||
// Load more on scroll
|
||||
let page = 1;
|
||||
const pageSize = 20;
|
||||
|
||||
async function loadMore() {
|
||||
const offset = (page - 1) * pageSize;
|
||||
const more = await odoo.searchRecords(
|
||||
model, [], fields, pageSize, offset
|
||||
);
|
||||
page++;
|
||||
return more;
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Optimize bundle size
|
||||
```bash
|
||||
# Analyze bundle
|
||||
npm run build -- --analyze
|
||||
|
||||
# Lazy load routes
|
||||
// SvelteKit (automatic)
|
||||
// React
|
||||
const ExpenseList = lazy(() => import('./ExpenseList'));
|
||||
|
||||
// Vue
|
||||
const ExpenseList = () => import('./ExpenseList.vue');
|
||||
```
|
||||
|
||||
#### 4. Reduce sync frequency
|
||||
```javascript
|
||||
// Increase sync interval
|
||||
const SYNC_INTERVAL = 5 * 60 * 1000; // 5 minutes instead of 3
|
||||
```
|
||||
|
||||
#### 5. Optimize images
|
||||
- Compress images before upload
|
||||
- Use appropriate image formats
|
||||
- Lazy load images
|
||||
|
||||
---
|
||||
|
||||
## Data Issues 📊
|
||||
|
||||
### Problem: Wrong data displayed
|
||||
**Symptoms:**
|
||||
- Incorrect values shown
|
||||
- Missing fields
|
||||
- Corrupted data
|
||||
- Date format issues
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### 1. Clear cache
|
||||
```javascript
|
||||
expenseCache.clearCache();
|
||||
expenseCache.refresh();
|
||||
```
|
||||
|
||||
#### 2. Verify field mapping
|
||||
```javascript
|
||||
// Check if fields are correctly named
|
||||
console.log(records[0]);
|
||||
// Should show x_studio_* fields
|
||||
```
|
||||
|
||||
#### 3. Check data types
|
||||
```javascript
|
||||
// Ensure correct types
|
||||
const expense = {
|
||||
x_studio_amount: 45.50, // number ✅
|
||||
x_studio_date: '2025-01-15', // string (ISO) ✅
|
||||
x_studio_employee: [12, false] // Many2one ✅
|
||||
};
|
||||
```
|
||||
|
||||
#### 4. Format dates correctly
|
||||
```javascript
|
||||
// Store as ISO string
|
||||
const dateString = '2025-01-15';
|
||||
|
||||
// Display formatted
|
||||
new Date(dateString).toLocaleDateString();
|
||||
```
|
||||
|
||||
#### 5. Handle Many2one fields
|
||||
```javascript
|
||||
// Many2one can be [id, name] or just id
|
||||
function getPartnerId(field) {
|
||||
return Array.isArray(field) ? field[0] : field;
|
||||
}
|
||||
|
||||
function getPartnerName(field) {
|
||||
return Array.isArray(field) ? field[1] : null;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CORS Issues 🚫
|
||||
|
||||
### Problem: CORS error
|
||||
**Symptoms:**
|
||||
- "Blocked by CORS policy" in console
|
||||
- Requests fail in browser but work in Postman
|
||||
- Preflight errors (OPTIONS)
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### 1. Use server-side proxy (recommended)
|
||||
All generated PWAs include server-side API routes. Ensure you're using them:
|
||||
```javascript
|
||||
// ✅ Good: Goes through server proxy
|
||||
fetch('/api/odoo', { ... });
|
||||
|
||||
// ❌ Bad: Direct call to Odoo (CORS error)
|
||||
fetch('https://yourcompany.odoo.com/jsonrpc', { ... });
|
||||
```
|
||||
|
||||
#### 2. Verify API route works
|
||||
```javascript
|
||||
// Test in browser console
|
||||
fetch('/api/odoo', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
action: 'search',
|
||||
model: 'res.partner',
|
||||
domain: [],
|
||||
fields: ['name'],
|
||||
limit: 1
|
||||
})
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(console.log);
|
||||
```
|
||||
|
||||
#### 3. Check if deployed correctly
|
||||
- Verify serverless functions deployed
|
||||
- Check function logs
|
||||
- Ensure environment variables set
|
||||
|
||||
---
|
||||
|
||||
## Browser-Specific Issues 🌐
|
||||
|
||||
### Problem: Works in Chrome but not Safari/Firefox
|
||||
**Symptoms:**
|
||||
- Different behavior across browsers
|
||||
- Safari-specific errors
|
||||
- Mobile browser issues
|
||||
|
||||
**Solutions:**
|
||||
|
||||
#### 1. Check browser compatibility
|
||||
- Test in multiple browsers
|
||||
- Check for console errors in each
|
||||
- Verify IndexedDB support
|
||||
|
||||
#### 2. Safari-specific
|
||||
- Safari has stricter storage limits
|
||||
- Check if localStorage/IndexedDB working
|
||||
- Test in private mode
|
||||
|
||||
#### 3. Mobile browsers
|
||||
- Test on actual devices
|
||||
- Check responsive design
|
||||
- Verify touch interactions work
|
||||
|
||||
---
|
||||
|
||||
## Debugging Tools & Commands 🔧
|
||||
|
||||
### Essential Commands
|
||||
```bash
|
||||
# Test connection
|
||||
/test-connection
|
||||
|
||||
# View full help
|
||||
/help
|
||||
|
||||
# See architecture details
|
||||
/architecture
|
||||
|
||||
# Clear cache and start fresh
|
||||
/clear-cache
|
||||
|
||||
# Fix sync issues
|
||||
/fix-sync
|
||||
```
|
||||
|
||||
### Browser DevTools
|
||||
```javascript
|
||||
// Network tab
|
||||
// - See all API calls
|
||||
// - Check request/response
|
||||
// - View timing
|
||||
|
||||
// Console tab
|
||||
// - See error messages
|
||||
// - Run test commands
|
||||
// - Inspect data
|
||||
|
||||
// Application tab
|
||||
// - View localStorage
|
||||
// - Inspect IndexedDB
|
||||
// - Check Service Workers
|
||||
// - View Cache Storage
|
||||
|
||||
// Performance tab
|
||||
// - Profile slow operations
|
||||
// - Find bottlenecks
|
||||
```
|
||||
|
||||
### Useful Console Commands
|
||||
```javascript
|
||||
// View cache
|
||||
localStorage.getItem('expenseCache');
|
||||
|
||||
// Clear cache
|
||||
localStorage.clear();
|
||||
|
||||
// Force refresh
|
||||
expenseCache.refresh();
|
||||
|
||||
// View current records
|
||||
console.log($expenseCache); // SvelteKit
|
||||
|
||||
// Test API
|
||||
fetch('/api/odoo', { /* ... */ })
|
||||
.then(r => r.json())
|
||||
.then(console.log);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Getting Help 💬
|
||||
|
||||
### Before asking for help:
|
||||
1. Run `/test-connection`
|
||||
2. Check browser console for errors
|
||||
3. Review this troubleshooting guide
|
||||
4. Try solutions listed above
|
||||
5. Test with minimal example
|
||||
|
||||
### When reporting issues:
|
||||
Include:
|
||||
- Exact error message
|
||||
- Browser and version
|
||||
- Node.js version
|
||||
- Steps to reproduce
|
||||
- What you've already tried
|
||||
- Relevant code snippets
|
||||
|
||||
### Helpful resources:
|
||||
- `/help` - Plugin documentation
|
||||
- `/examples` - Usage examples
|
||||
- `/architecture` - Design patterns
|
||||
- `/api-reference` - API documentation
|
||||
- Odoo docs: https://www.odoo.com/documentation/
|
||||
- Framework docs (SvelteKit/React/Vue)
|
||||
|
||||
---
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/troubleshoot` - Show troubleshooting guide
|
||||
- User: "Why isn't my data syncing?"
|
||||
- User: "I'm getting a connection error"
|
||||
- User: "Help! Nothing works!"
|
||||
|
||||
## Still Stuck?
|
||||
If these solutions don't help:
|
||||
1. Run `/test-connection` for detailed diagnostics
|
||||
2. Check generated project's CLAUDE.md
|
||||
3. Review Odoo server logs
|
||||
4. Test with different Odoo model
|
||||
5. Try generating fresh project to compare
|
||||
|
||||
Most issues are related to configuration or permissions. Double-check your `.env` file and Odoo settings!
|
||||
505
commands/update-deps.md
Normal file
505
commands/update-deps.md
Normal file
@@ -0,0 +1,505 @@
|
||||
Update dependencies in your Odoo PWA project to latest compatible versions.
|
||||
|
||||
## What this command does:
|
||||
- Checks for outdated dependencies
|
||||
- Updates packages to latest versions
|
||||
- Tests the application after updates
|
||||
- Fixes breaking changes if needed
|
||||
- Updates lock files
|
||||
- Verifies everything still works
|
||||
|
||||
## Prerequisites:
|
||||
- Current directory is an Odoo PWA project
|
||||
- Git repository (recommended for easy rollback)
|
||||
- Latest npm installed
|
||||
|
||||
---
|
||||
|
||||
## Update Strategy
|
||||
|
||||
### Safe Update (Recommended)
|
||||
Updates to latest compatible versions within semver ranges.
|
||||
|
||||
```bash
|
||||
npm update
|
||||
```
|
||||
|
||||
### Major Update (Requires testing)
|
||||
Updates to latest versions including major releases.
|
||||
|
||||
```bash
|
||||
npm outdated # See what's outdated
|
||||
npm update # Update minor/patch
|
||||
npx npm-check-updates -u # Update majors
|
||||
npm install
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Steps:
|
||||
|
||||
### 1. Check Current Status
|
||||
```bash
|
||||
# See current versions
|
||||
npm list --depth=0
|
||||
|
||||
# See outdated packages
|
||||
npm outdated
|
||||
```
|
||||
|
||||
### 2. Create Backup
|
||||
```bash
|
||||
# Commit current state
|
||||
git add .
|
||||
git commit -m "Pre-dependency update checkpoint"
|
||||
|
||||
# Or backup package files
|
||||
cp package.json package.json.backup
|
||||
cp package-lock.json package-lock.json.backup
|
||||
```
|
||||
|
||||
### 3. Update Dependencies
|
||||
|
||||
#### Minor/Patch Updates (Safe)
|
||||
```bash
|
||||
npm update
|
||||
npm install
|
||||
```
|
||||
|
||||
#### Major Updates (Test carefully)
|
||||
```bash
|
||||
# Install npm-check-updates if needed
|
||||
npm install -g npm-check-updates
|
||||
|
||||
# Preview updates
|
||||
ncu
|
||||
|
||||
# Update package.json
|
||||
ncu -u
|
||||
|
||||
# Install new versions
|
||||
npm install
|
||||
```
|
||||
|
||||
### 4. Framework-Specific Updates
|
||||
|
||||
#### SvelteKit
|
||||
```bash
|
||||
# Update Svelte + SvelteKit
|
||||
npm update @sveltejs/kit @sveltejs/adapter-static
|
||||
npm update svelte
|
||||
|
||||
# Check for breaking changes
|
||||
# https://github.com/sveltejs/kit/blob/master/CHANGELOG.md
|
||||
```
|
||||
|
||||
#### React
|
||||
```bash
|
||||
# Update React
|
||||
npm update react react-dom
|
||||
|
||||
# Update related packages
|
||||
npm update @types/react @types/react-dom
|
||||
```
|
||||
|
||||
#### Vue
|
||||
```bash
|
||||
# Update Vue
|
||||
npm update vue
|
||||
|
||||
# Update related packages
|
||||
npm update @vitejs/plugin-vue
|
||||
```
|
||||
|
||||
### 5. Update Build Tools
|
||||
```bash
|
||||
# Update Vite
|
||||
npm update vite
|
||||
|
||||
# Update PWA plugin
|
||||
npm update vite-plugin-pwa @vite-pwa/sveltekit
|
||||
```
|
||||
|
||||
### 6. Test Everything
|
||||
|
||||
#### Run Development Server
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Check:
|
||||
- ✅ Server starts without errors
|
||||
- ✅ App loads correctly
|
||||
- ✅ No console errors
|
||||
- ✅ All routes work
|
||||
|
||||
#### Test Core Functionality
|
||||
- ✅ Odoo connection works
|
||||
- ✅ Data loads from cache
|
||||
- ✅ Sync works
|
||||
- ✅ CRUD operations work
|
||||
- ✅ Offline mode works
|
||||
|
||||
#### Build for Production
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
Check:
|
||||
- ✅ Build completes without errors
|
||||
- ✅ No warnings about deprecations
|
||||
- ✅ Bundle size is reasonable
|
||||
|
||||
#### Preview Production Build
|
||||
```bash
|
||||
npm run preview
|
||||
```
|
||||
|
||||
Test the same functionality in production mode.
|
||||
|
||||
### 7. Run Connection Test
|
||||
```bash
|
||||
# If /test-connection command is available
|
||||
/test-connection
|
||||
```
|
||||
|
||||
### 8. Commit Changes
|
||||
```bash
|
||||
git add package.json package-lock.json
|
||||
git commit -m "Update dependencies to latest versions"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Issues & Solutions
|
||||
|
||||
### Issue: Build fails after update
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Revert updates
|
||||
git checkout package.json package-lock.json
|
||||
npm install
|
||||
|
||||
# Try updating one package at a time
|
||||
npm update vite
|
||||
npm run build # Test
|
||||
|
||||
npm update @sveltejs/kit
|
||||
npm run build # Test
|
||||
|
||||
# Continue one by one
|
||||
```
|
||||
|
||||
### Issue: TypeScript errors
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Update TypeScript
|
||||
npm update typescript
|
||||
|
||||
# Update type definitions
|
||||
npm update @types/node
|
||||
|
||||
# Regenerate tsconfig
|
||||
npx tsc --init
|
||||
```
|
||||
|
||||
### Issue: Import errors
|
||||
|
||||
**Solution:**
|
||||
```javascript
|
||||
// Old import might be:
|
||||
import { foo } from 'package';
|
||||
|
||||
// New import might be:
|
||||
import { foo } from 'package/foo';
|
||||
|
||||
// Check package's CHANGELOG for migration guide
|
||||
```
|
||||
|
||||
### Issue: Service Worker errors
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Update PWA plugin
|
||||
npm update vite-plugin-pwa
|
||||
|
||||
# Check configuration
|
||||
# vite.config.js
|
||||
VitePWA({
|
||||
// Update config as needed
|
||||
})
|
||||
```
|
||||
|
||||
### Issue: Peer dependency warnings
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Install peer dependencies
|
||||
npm install <missing-peer-dep>
|
||||
|
||||
# Or use --force (not recommended)
|
||||
npm install --force
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Breaking Changes to Watch For
|
||||
|
||||
### Vite 5+
|
||||
- May require Node 18+
|
||||
- ESM-only packages
|
||||
- Updated config format
|
||||
|
||||
### SvelteKit 2+
|
||||
- Svelte 5 syntax (runes)
|
||||
- Updated adapter config
|
||||
- New routing conventions
|
||||
|
||||
### React 19+
|
||||
- New JSX transform
|
||||
- Updated hooks behavior
|
||||
- Server components
|
||||
|
||||
### Vue 3.4+
|
||||
- New compiler optimizations
|
||||
- Updated Composition API
|
||||
- Better TypeScript support
|
||||
|
||||
---
|
||||
|
||||
## Update Checklist
|
||||
|
||||
After updating, verify:
|
||||
|
||||
```
|
||||
□ npm run dev works
|
||||
□ npm run build succeeds
|
||||
□ npm run preview works
|
||||
□ No console errors
|
||||
□ Odoo connection works
|
||||
□ Data syncs correctly
|
||||
□ CRUD operations work
|
||||
□ Offline mode works
|
||||
□ Service worker registered
|
||||
□ Tests pass (if any)
|
||||
□ No TypeScript errors
|
||||
□ No ESLint warnings
|
||||
□ Documentation updated
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Selective Updates
|
||||
|
||||
### Update Only Production Dependencies
|
||||
```bash
|
||||
npm update --prod
|
||||
```
|
||||
|
||||
### Update Specific Package
|
||||
```bash
|
||||
npm update vite
|
||||
npm update @sveltejs/kit
|
||||
```
|
||||
|
||||
### Update to Specific Version
|
||||
```bash
|
||||
npm install vite@5.0.0
|
||||
npm install svelte@5.0.0
|
||||
```
|
||||
|
||||
### Keep Package at Current Version
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"some-package": "1.2.3" // No ^ or ~ = exact version
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Update Regularly
|
||||
- Check weekly for security updates
|
||||
- Update monthly for feature updates
|
||||
- Test before deploying
|
||||
|
||||
### 2. Read Changelogs
|
||||
- Check CHANGELOG.md for breaking changes
|
||||
- Review migration guides
|
||||
- Test thoroughly
|
||||
|
||||
### 3. Update One Category at a Time
|
||||
```bash
|
||||
# 1. Framework
|
||||
npm update svelte @sveltejs/kit
|
||||
|
||||
# 2. Build tools
|
||||
npm update vite
|
||||
|
||||
# 3. Dependencies
|
||||
npm update # All others
|
||||
```
|
||||
|
||||
### 4. Keep Lock Files
|
||||
- Commit `package-lock.json`
|
||||
- Ensure consistent installs
|
||||
- Track exact versions
|
||||
|
||||
### 5. Test in Staging
|
||||
- Deploy to staging first
|
||||
- Test all functionality
|
||||
- Then deploy to production
|
||||
|
||||
---
|
||||
|
||||
## Security Updates
|
||||
|
||||
### Check for Vulnerabilities
|
||||
```bash
|
||||
npm audit
|
||||
```
|
||||
|
||||
### Fix Automatically
|
||||
```bash
|
||||
npm audit fix
|
||||
```
|
||||
|
||||
### Fix with Breaking Changes
|
||||
```bash
|
||||
npm audit fix --force
|
||||
```
|
||||
|
||||
### Review Details
|
||||
```bash
|
||||
npm audit --json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Automated Updates (Optional)
|
||||
|
||||
### Using Dependabot (GitHub)
|
||||
Create `.github/dependabot.yml`:
|
||||
```yaml
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 10
|
||||
```
|
||||
|
||||
### Using Renovate
|
||||
Create `renovate.json`:
|
||||
```json
|
||||
{
|
||||
"extends": ["config:base"],
|
||||
"schedule": ["before 10am on monday"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
### If Something Breaks
|
||||
|
||||
#### Quick Rollback
|
||||
```bash
|
||||
git checkout package.json package-lock.json
|
||||
npm install
|
||||
```
|
||||
|
||||
#### Restore from Backup
|
||||
```bash
|
||||
cp package.json.backup package.json
|
||||
cp package-lock.json.backup package-lock.json
|
||||
npm install
|
||||
```
|
||||
|
||||
#### Git Reset
|
||||
```bash
|
||||
git reset --hard HEAD~1
|
||||
npm install
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## After Update
|
||||
|
||||
### Update Documentation
|
||||
- Note any breaking changes
|
||||
- Update README if needed
|
||||
- Document new features used
|
||||
|
||||
### Notify Team
|
||||
- Share what was updated
|
||||
- Note any changes in behavior
|
||||
- Update staging/production
|
||||
|
||||
### Monitor Production
|
||||
- Watch error logs
|
||||
- Check performance metrics
|
||||
- Monitor user reports
|
||||
|
||||
---
|
||||
|
||||
## Example prompts to use this command:
|
||||
- `/update-deps` - Update all dependencies
|
||||
- User: "Update my dependencies"
|
||||
- User: "Check for package updates"
|
||||
- User: "My packages are outdated"
|
||||
|
||||
## Related Commands:
|
||||
- `/fix-sync` - If sync breaks after update
|
||||
- `/test-connection` - Verify Odoo still works
|
||||
- `/troubleshoot` - Fix issues after update
|
||||
- `/optimize` - Check for optimizations after update
|
||||
|
||||
---
|
||||
|
||||
## Quick Update Script
|
||||
|
||||
Save as `update.sh`:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
echo "Backing up..."
|
||||
cp package.json package.json.backup
|
||||
cp package-lock.json package-lock.json.backup
|
||||
|
||||
echo "Checking for updates..."
|
||||
npm outdated
|
||||
|
||||
echo "Updating..."
|
||||
npm update
|
||||
|
||||
echo "Installing..."
|
||||
npm install
|
||||
|
||||
echo "Testing..."
|
||||
npm run build
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ Build successful!"
|
||||
echo "Run: npm run dev to test"
|
||||
else
|
||||
echo "❌ Build failed! Rolling back..."
|
||||
cp package.json.backup package.json
|
||||
cp package-lock.json.backup package-lock.json
|
||||
npm install
|
||||
fi
|
||||
```
|
||||
|
||||
Usage:
|
||||
```bash
|
||||
chmod +x update.sh
|
||||
./update.sh
|
||||
```
|
||||
Reference in New Issue
Block a user