9-course Dutch e-learning platform fused onto atlasacademy.nl via Caddy reverse proxy. Odoo 19 Community as course engine (website_slides), static HTML for marketing front. Single Odoo account system. - static/: 8 marketing pages (index, pricing, coaching, leerpad, over, shop, bisl, esf) - backend/odoo_relay.py: lead relay Flask service (POST /academy-lead → Odoo CRM) - caddy/academy.caddyfile: full Caddy config with Odoo proxy + auth rewrites - docs/: ARCHITECTURE, USERFLOW, COURSES, DEPLOYMENT, SECURITY, ODOO Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
160 lines
4.7 KiB
Markdown
160 lines
4.7 KiB
Markdown
# Odoo eLearning Setup — Atlas Academy
|
|
|
|
## Installatie
|
|
|
|
`website_slides` is geïnstalleerd als onderdeel van Odoo 19 Community op atlas-01.
|
|
|
|
```bash
|
|
# Verificatie
|
|
ssh atlas-01 "docker exec atlas-odoo odoo --list-db 2>/dev/null"
|
|
# DB: atlas
|
|
|
|
# Module status
|
|
ssh atlas-01 "docker exec -i atlas-odoo odoo shell -d atlas --no-http" <<'EOF'
|
|
m = env['ir.module.module'].sudo().search([('name','=','website_slides')])
|
|
print(m.name, m.state) # verwacht: website_slides installed
|
|
EOF
|
|
```
|
|
|
|
---
|
|
|
|
## Multi-website configuratie
|
|
|
|
Atlas Academy draait op **website 3** (apart van de Atlas Corporation-website op website 1).
|
|
|
|
| | Website 1 | Website 3 |
|
|
|--|-----------|-----------|
|
|
| Naam | Atlas Corporation | Atlas Academy |
|
|
| Domein | *(default)* | `https://atlasacademy.nl` |
|
|
| Signup | `b2b` (gesloten) | `b2c` (open) |
|
|
| Taal | NL | NL |
|
|
| Logo | Atlas Corp | Atlas Academy icon |
|
|
|
|
### Kritische gotcha's
|
|
|
|
**1. Caching van website-routing**
|
|
`_get_current_website_id` is ORM-gecached. Na aanmaken/wijzigen van een website:
|
|
```bash
|
|
ssh atlas-01 "docker restart atlas-odoo"
|
|
```
|
|
|
|
**2. X-Forwarded-Host verplicht**
|
|
Caddy moet `X-Forwarded-Host {host}` doorgeven, anders serveert Odoo altijd website 1:
|
|
```caddyfile
|
|
reverse_proxy 100.93.16.81:8069 {
|
|
header_up Host {host}
|
|
header_up X-Forwarded-Host {host}
|
|
header_up X-Forwarded-Proto https
|
|
}
|
|
```
|
|
|
|
**3. `proxy_mode = True`**
|
|
Controleer `/opt/atlas-odoo/config/odoo.conf`:
|
|
```ini
|
|
proxy_mode = True
|
|
```
|
|
|
|
**4. Signup is per-website, niet globaal**
|
|
De globale `auth_signup.allow_uninvited` parameter wordt **genegeerd** als `website` module actief is. Gebruik altijd:
|
|
```python
|
|
env['website'].sudo().browse(3).write({'auth_signup_uninvited': 'b2c'})
|
|
env.cr.commit()
|
|
```
|
|
|
|
---
|
|
|
|
## Website 3 aanmaken (referentie)
|
|
|
|
```python
|
|
env = env # Odoo shell
|
|
|
|
w3 = env['website'].sudo().create({
|
|
'name': 'Atlas Academy',
|
|
'domain': 'https://atlasacademy.nl',
|
|
'company_id': env.company.id,
|
|
'language_ids': [(4, env.ref('base.lang_nl').id)],
|
|
'default_lang_id': env.ref('base.lang_nl').id,
|
|
'auth_signup_uninvited': 'b2c',
|
|
})
|
|
# Stel logo in
|
|
import base64, requests
|
|
logo_data = requests.get('https://atlasacademy.nl/atlas-icon.png').content
|
|
w3.write({'logo': base64.b64encode(logo_data).decode()})
|
|
env.cr.commit()
|
|
print(f"Website aangemaakt: ID={w3.id}")
|
|
# Vervolgens: docker restart atlas-odoo
|
|
```
|
|
|
|
---
|
|
|
|
## Cursus website-toewijzing
|
|
|
|
Alle cursussen (`slide.channel`) moeten `website_id=3` hebben:
|
|
|
|
```python
|
|
channels = env['slide.channel'].sudo().search([])
|
|
for c in channels:
|
|
if not c.website_id or c.website_id.id != 3:
|
|
c.sudo().write({'website_id': 3})
|
|
env.cr.commit()
|
|
print(f"{len(channels)} cursussen toegewezen aan website 3")
|
|
```
|
|
|
|
---
|
|
|
|
## Email base-URL
|
|
|
|
Odoo gebruikt `website.get_base_url()` voor links in e-mails (wachtwoord reset etc.).
|
|
Dankzij multi-website:
|
|
- Website 3 → `get_base_url()` = `https://atlasacademy.nl` ✅
|
|
- Website 1 → `get_base_url()` = corp-domein ✅
|
|
|
|
De globale `web.base.url` parameter wordt **niet** gewijzigd (zou corp-emails breken).
|
|
|
|
---
|
|
|
|
## Odoo backend bereikbaarheid
|
|
|
|
| Route | Bereikbaar? | Via |
|
|
|-------|-------------|-----|
|
|
| `atlasacademy.nl/slides` | ✅ Publiek | Caddy proxy |
|
|
| `atlasacademy.nl/web/login` | ✅ Publiek | Caddy proxy |
|
|
| `atlasacademy.nl/web` (backend) | ❌ Niet geproxied | — |
|
|
| `http://100.93.16.81:8069` | ✅ Tailnet only | Direct |
|
|
| `odoo.atlascorporation.nl` | ✅ SSO only | Authentik + Caddy |
|
|
|
|
---
|
|
|
|
## Veelgebruikte ORM-commando's
|
|
|
|
```bash
|
|
# Shell openen
|
|
ssh atlas-01 "docker exec -i atlas-odoo odoo shell -d atlas --no-http"
|
|
|
|
# Alle cursussen tonen
|
|
for c in env['slide.channel'].sudo().search([]): print(c.id, c.name, c.website_slug)
|
|
|
|
# Cursuspagina URL genereren
|
|
c = env['slide.channel'].sudo().browse(2)
|
|
print(f"https://atlasacademy.nl/slides/{c.website_slug}")
|
|
|
|
# Lessen van een cursus tonen
|
|
slides = env['slide.slide'].sudo().search([('channel_id','=',2),('is_category','=',False)])
|
|
for s in slides: print(s.sequence, s.name, len(s.question_ids), 'vragen')
|
|
|
|
# Website-instellingen inspecteren
|
|
w = env['website'].sudo().browse(3)
|
|
print(w.name, w.domain, w.auth_signup_uninvited, w.get_base_url())
|
|
```
|
|
|
|
---
|
|
|
|
## Bekende issues & oplossingen
|
|
|
|
| Issue | Oorzaak | Oplossing |
|
|
|-------|---------|-----------|
|
|
| `/web/signup` → 404 | `auth_signup_uninvited` niet op `b2c` | ORM shell: `w.write({'auth_signup_uninvited':'b2c'})` |
|
|
| Courses tonen op corp-website | `website_id=None` op channels | Script: set alle channels op `website_id=3` |
|
|
| Wachtwoord-reset e-mail heeft wrong URL | `web.base.url` verkeerd OF website 3 geen domein | Controleer `w3.domain` en `w3.get_base_url()` |
|
|
| Odoo toont corp-logo op academy-domein | Website-cache niet geleegd | `docker restart atlas-odoo` |
|
|
| `/slides` geeft 502 | Odoo container down | `docker start atlas-odoo && docker logs atlas-odoo` |
|