175 lines
4.1 KiB
Markdown
175 lines
4.1 KiB
Markdown
|
|
# Solution Module
|
||
|
|
|
||
|
|
Dette er template strukturen for nye BMC Hub moduler.
|
||
|
|
|
||
|
|
## Struktur
|
||
|
|
|
||
|
|
```
|
||
|
|
solution/
|
||
|
|
├── module.json # Metadata og konfiguration
|
||
|
|
├── README.md # Dokumentation
|
||
|
|
├── backend/
|
||
|
|
│ ├── __init__.py
|
||
|
|
│ └── router.py # FastAPI routes (API endpoints)
|
||
|
|
├── frontend/
|
||
|
|
│ ├── __init__.py
|
||
|
|
│ └── views.py # HTML view routes
|
||
|
|
├── templates/
|
||
|
|
│ └── index.html # Jinja2 templates
|
||
|
|
└── migrations/
|
||
|
|
└── 001_init.sql # Database migrations
|
||
|
|
```
|
||
|
|
|
||
|
|
## Opret nyt modul
|
||
|
|
|
||
|
|
```bash
|
||
|
|
python scripts/create_module.py solution "My Module Description"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Database Tables
|
||
|
|
|
||
|
|
Alle tabeller SKAL bruge `table_prefix` fra module.json:
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- Hvis table_prefix = "solution_"
|
||
|
|
CREATE TABLE solution_items (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
name VARCHAR(255)
|
||
|
|
);
|
||
|
|
```
|
||
|
|
|
||
|
|
Dette sikrer at moduler ikke kolliderer med core eller andre moduler.
|
||
|
|
|
||
|
|
### Customer Linking (Hvis nødvendigt)
|
||
|
|
|
||
|
|
Hvis dit modul skal have sin egen kunde-tabel (f.eks. ved sync fra eksternt system):
|
||
|
|
|
||
|
|
**SKAL altid linke til core customers:**
|
||
|
|
|
||
|
|
```sql
|
||
|
|
CREATE TABLE solution_customers (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
name VARCHAR(255) NOT NULL,
|
||
|
|
external_id VARCHAR(100), -- ID fra eksternt system
|
||
|
|
hub_customer_id INTEGER REFERENCES customers(id), -- VIGTIG!
|
||
|
|
active BOOLEAN DEFAULT TRUE,
|
||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
|
||
|
|
-- Auto-link trigger (se migrations/001_init.sql for komplet eksempel)
|
||
|
|
CREATE TRIGGER trigger_auto_link_solution_customer
|
||
|
|
BEFORE INSERT OR UPDATE OF name
|
||
|
|
ON solution_customers
|
||
|
|
FOR EACH ROW
|
||
|
|
EXECUTE FUNCTION auto_link_solution_customer();
|
||
|
|
```
|
||
|
|
|
||
|
|
**Hvorfor?** Dette sikrer at:
|
||
|
|
- ✅ E-conomic export virker automatisk
|
||
|
|
- ✅ Billing integration fungerer
|
||
|
|
- ✅ Ingen manuel linking nødvendig
|
||
|
|
|
||
|
|
**Alternativ:** Hvis modulet kun har simple kunde-relationer, brug direkte FK:
|
||
|
|
```sql
|
||
|
|
CREATE TABLE solution_orders (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
customer_id INTEGER REFERENCES customers(id) -- Direkte link
|
||
|
|
);
|
||
|
|
```
|
||
|
|
|
||
|
|
## Konfiguration
|
||
|
|
|
||
|
|
Modul-specifikke miljøvariable følger mønsteret:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
MODULES__MY_MODULE__API_KEY=secret123
|
||
|
|
MODULES__MY_MODULE__READ_ONLY=true
|
||
|
|
```
|
||
|
|
|
||
|
|
Tilgå i kode:
|
||
|
|
|
||
|
|
```python
|
||
|
|
from app.core.config import get_module_config
|
||
|
|
|
||
|
|
api_key = get_module_config("solution", "API_KEY")
|
||
|
|
read_only = get_module_config("solution", "READ_ONLY", default="true") == "true"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Database Queries
|
||
|
|
|
||
|
|
Brug ALTID helper functions fra `app.core.database`:
|
||
|
|
|
||
|
|
```python
|
||
|
|
from app.core.database import execute_query, execute_insert
|
||
|
|
|
||
|
|
# Fetch
|
||
|
|
customers = execute_query(
|
||
|
|
"SELECT * FROM solution_customers WHERE active = %s",
|
||
|
|
(True,)
|
||
|
|
)
|
||
|
|
|
||
|
|
# Insert
|
||
|
|
customer_id = execute_insert(
|
||
|
|
"INSERT INTO solution_customers (name) VALUES (%s)",
|
||
|
|
("Test Customer",)
|
||
|
|
)
|
||
|
|
```
|
||
|
|
|
||
|
|
## Migrations
|
||
|
|
|
||
|
|
Migrations ligger i `migrations/` og køres manuelt eller via migration tool:
|
||
|
|
|
||
|
|
```python
|
||
|
|
from app.core.database import execute_module_migration
|
||
|
|
|
||
|
|
with open("migrations/001_init.sql") as f:
|
||
|
|
migration_sql = f.read()
|
||
|
|
|
||
|
|
success = execute_module_migration("solution", migration_sql)
|
||
|
|
```
|
||
|
|
|
||
|
|
## Enable/Disable
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Enable via API
|
||
|
|
curl -X POST http://localhost:8000/api/v1/modules/solution/enable
|
||
|
|
|
||
|
|
# Eller rediger module.json
|
||
|
|
{
|
||
|
|
"enabled": true
|
||
|
|
}
|
||
|
|
|
||
|
|
# Restart app
|
||
|
|
docker-compose restart api
|
||
|
|
```
|
||
|
|
|
||
|
|
## Fejlhåndtering
|
||
|
|
|
||
|
|
Moduler er isolerede - hvis dit modul crasher ved opstart:
|
||
|
|
- Core systemet kører videre
|
||
|
|
- Modulet bliver ikke loaded
|
||
|
|
- Fejl logges til console og logs/app.log
|
||
|
|
|
||
|
|
Runtime fejl i endpoints påvirker ikke andre moduler.
|
||
|
|
|
||
|
|
## Testing
|
||
|
|
|
||
|
|
```python
|
||
|
|
import pytest
|
||
|
|
from app.core.database import execute_query
|
||
|
|
|
||
|
|
def test_solution():
|
||
|
|
# Test bruger samme database helpers
|
||
|
|
result = execute_query("SELECT 1 as test")
|
||
|
|
assert result[0]["test"] == 1
|
||
|
|
```
|
||
|
|
|
||
|
|
## Best Practices
|
||
|
|
|
||
|
|
1. **Database isolering**: Brug ALTID `table_prefix` fra module.json
|
||
|
|
2. **Safety switches**: Tilføj `READ_ONLY` og `DRY_RUN` flags
|
||
|
|
3. **Error handling**: Log fejl, raise HTTPException med status codes
|
||
|
|
4. **Dependencies**: Deklarer i `module.json` hvis du bruger andre moduler
|
||
|
|
5. **Migrations**: Nummer sekventielt (001, 002, 003...)
|
||
|
|
6. **Documentation**: Opdater README.md med API endpoints og use cases
|