Application web d'inventaire réseau manuel avec FastAPI, Vue 3 et Docker. Inclut l'authentification JWT, la découverte ICMP, et la topologie en cards CSS. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.4 KiB
Extending the Application
Add a Field to Device
Every new Device field requires changes in four places. Missing any one of them will cause data loss or silent failures.
1. backend/models.py
Add the column to the Device class:
my_field = Column(String, nullable=True)
2. backend/main.py
Add an idempotent migration function and call it before Base.metadata.create_all:
def _migrate_device_my_field():
with engine.connect() as conn:
if not conn.execute(text(
"SELECT name FROM sqlite_master WHERE type='table' AND name='devices'"
)).fetchone():
return
cols = [row[1] for row in conn.execute(text("PRAGMA table_info(devices)")).fetchall()]
if 'my_field' not in cols:
conn.execute(text("ALTER TABLE devices ADD COLUMN my_field VARCHAR"))
conn.commit()
# Add the call at the bottom of the startup sequence:
_migrate_device_my_field()
3. backend/routers/devices.py
Add to both Pydantic models:
class DeviceCreate(BaseModel):
my_field: Optional[str] = None
class DeviceOut(BaseModel):
my_field: Optional[str] = None
Then assign explicitly in both create_device and update_device:
db_device = models.Device(
...
my_field=device.my_field,
)
Do not use **device.model_dump() to populate the ORM object — it silently ignores any field not present in the constructor keyword args.
4. Frontend
Add the field to the device form in DeviceManager.vue and display it where needed (chip in TopologyGraph.vue, card in DeviceManager.vue). Add any new i18n keys to all three locales in i18n.js.
Add a New API Route Group
- Create
backend/routers/myrouter.pyfollowing the pattern ofvlans.pyordevices.py. - Import and register in
backend/main.py:from routers import myrouter app.include_router(myrouter.router, prefix="/api/myroutes", tags=["myroutes"], dependencies=[Depends(get_current_user)]) - Add the corresponding API object in
frontend/src/api.js:export const myApi = { list: () => http.get('/myroutes/'), create: (data) => http.post('/myroutes/', data), remove: (id) => http.delete(`/myroutes/${id}`), }
Add a New i18n Key
- Open
frontend/src/i18n.js. - Add the key to all three locale objects (
fr,en,es). - Use
t('myKey')in the template.
For interpolation:
// i18n.js
fr: { myMsg: "Il y a {0} équipements dans {1}" }
// template
{{ tFmt('myMsg', devices.length, vlan.name) }}
Add a Language
- In
frontend/src/i18n.js, add a new locale object with all existing keys translated. - Add the language code to the valid values type/comment.
- In
App.vue, add a pill button to the language switcher:<button :class="{ active: locale === 'de' }" @click="setLocale('de')">de</button>
Add a Brand Icon
Supported brands are detected by keyword-matching device name and description.
- Find the Simple Icons export name:
cd frontend node -e "const si = require('./node_modules/simple-icons'); console.log(Object.keys(si).filter(k => k.toLowerCase().includes('yourterm')))" - In
frontend/src/brandIcons.js, import the icon:import { siYourbrand } from 'simple-icons' - Add an entry to the
BRANDSarray:{ id: 'yourbrand', name: 'YourBrand', keywords: ['yourbrand', 'alternate-name'], hex: siYourbrand.hex, path: siYourbrand.path, }
keywords are matched case-insensitively against the device name and description fields.
Add a Vue Component
- Create
frontend/src/components/MyComponent.vueusing<script setup>syntax. - Use CSS custom properties for all colors (see
docs/frontend.mdfor the variable list). - Use
t('key')for all visible strings — never hardcode text. - For dark-mode scoped overrides, put the full selector inside
:global()::global(html.dark .my-component) { background: #1E293B; } - Import and use in
App.vueor the relevant parent component.
Change the Default Admin Password
The admin account is seeded by _migrate_users() only when the users table is empty. To reset credentials on a running instance, use the account settings modal in the UI (sidebar footer → account icon).
To reset programmatically (e.g., locked out):
docker compose exec backend python3 -c "
from database import engine
from sqlalchemy import text
from passlib.context import CryptContext
pwd = CryptContext(schemes=['bcrypt'], deprecated='auto')
with engine.connect() as conn:
conn.execute(text(\"UPDATE users SET hashed_password=:h WHERE username='admin'\"), {'h': pwd.hash('newpassword')})
conn.commit()
"
Upgrade Dependencies
Backend Python packages
Check for passlib/bcrypt compatibility before upgrading:
passlib 1.7.4requiresbcrypt < 4.0— seerequirements.txtfor the pin.- If upgrading passlib, verify the new version supports the installed bcrypt before removing the pin.
Frontend npm packages
simple-icons has breaking changes between major versions (icon names and SVG paths change). Pin the major version in package.json and test brand detection after upgrading.
lucide-vue-next is generally backwards-compatible but icons are occasionally renamed or removed.