made dashboard style consistent to landingpage and login, also added translation for english and german

This commit is contained in:
2026-04-05 02:18:31 +02:00
parent 19a6bbd392
commit aa569e6cff
5 changed files with 1490 additions and 537 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+169 -102
View File
@@ -10,18 +10,39 @@
</head> </head>
<body> <body>
<nav class="dashboard-nav">
<a class="brand" href="{{ url_for('main.home') }}">
<span class="brand-mark">♛</span>
<span>8-Damen- und 8-Türme Solver</span>
</a>
<div class="nav-actions">
<a class="nav-link" href="{{ url_for('main.dashboard') }}" id="navDashboardLink">Dashboard</a>
<button class="nav-link-button lang-switch" id="langSwitch" type="button"
aria-label="Sprache wechseln">DE</button>
<a class="account-shortcut" href="{{ url_for('login.login_settings') }}"
aria-label="Konto und Login-Einstellungen öffnen">
<span class="account-avatar" aria-hidden="true">{{ current_user.username[:1]|upper }}</span>
<span class="account-copy">
<span class="account-label" id="accountLabel">Account</span>
<span class="account-name">{{ current_user.username }}</span>
</span>
</a>
<nav class="navbar">
<div class="nav-left">♛ 8-Queens App</div>
<div class="nav-right">
<a href="{{ url_for('main.dashboard') }}">Dashboard</a>
<a href="{{ url_for('login.login_settings') }}">Login settings</a>
<form action="{{ url_for('login.logout') }}" method="post" class="nav-logout-form"> <form action="{{ url_for('login.logout') }}" method="post" class="nav-logout-form">
<button class="nav-link-button" type="submit">Logout</button> <button class="nav-link-button" type="submit">Logout</button>
</form> </form>
</div> </div>
</nav> </nav>
<button class="settings-trigger" id="settingsTrigger" onclick="toggleSidebar()" type="button"
aria-controls="settingsSidebar" aria-expanded="false">
<span class="settings-trigger-arrow" id="settingsTriggerArrow">→</span>
<span class="settings-trigger-label" id="settingsTriggerLabel">Brett-Einstellungen</span>
</button>
<div class="container"> <div class="container">
{% with messages = get_flashed_messages(with_categories=true) %} {% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %} {% if messages %}
@@ -33,116 +54,157 @@
{% endif %} {% endif %}
{% endwith %} {% endwith %}
<div class="card"> <section class="dashboard-intro card">
<h2>👋 Willkommen, {{ current_user.username }}</h2> <p class="section-kicker" id="introKicker">Puzzle-Modus</p>
<h1 id="introTitle">Wähl deinen Modus und löse das Brett auf deine Art.</h1>
<p class="dashboard-intro-text" id="introText">
Wechsle zwischen Damen und Türmen, nutze Animation oder Sofort-Lösung und öffne die
Brett-Einstellungen jederzeit über den linken Seiten-Tab.
</p>
<div class="user-info"> <div class="mode-switch" aria-label="Spielmodus">
<p><strong>ID:</strong> {{ current_user.id }}</p> <button class="btn active" onclick="setMode('queens')" id="btnQueens" type="button">♛ Damen</button>
<p><strong>Username:</strong> {{ current_user.username }}</p> <button class="btn secondary" onclick="setMode('rooks')" id="btnRooks" type="button">♜ Tuerme</button>
<p><strong>2FA:</strong> {% if current_user.two_factor_enabled %}Authenticator app enabled{% else %}Disabled{% endif %}</p>
<p><strong>Erstellt:</strong> {{ current_user.created_at }}</p>
</div>
<div class="inline-actions">
<a class="btn secondary" href="{{ url_for('login.login_settings') }}">Open login settings</a>
<form action="{{ url_for('login.logout') }}" method="post">
<button class="btn danger" type="submit">Logout</button>
</form>
</div>
</div>
<div class="mode-switch">
<button class="btn active" onclick="setMode('queens')" id="btnQueens">♛ Damen</button>
<button class="btn secondary" onclick="setMode('rooks')" id="btnRooks">♜ Türme</button>
<button class="btn secondary" onclick="toggleSidebar()" id="btnSidebar">Board Settings</button>
</div> </div>
</section>
<div class="card game-card"> <div class="card game-card">
<div class="game-card-header"> <div class="game-card-header">
<h2>♟️ Damen- und Tuerme-Spiel</h2> <div class="game-card-copy">
<button class="info-button" id="infoButton" onclick="toggleInfoModal(true)" type="button" <p class="section-kicker" id="gameModeEyebrow">Damen-Modus</p>
aria-label="Spielanleitung und Erklaerung anzeigen">i</button> <h2 id="gameTitle">Damen-Spielbrett</h2>
<p class="board-mode-text" id="boardModeText">
Platziere Damen so, dass keine zwei dieselbe Spalte oder Diagonale teilen.
</p>
</div> </div>
<p class="board-size-info">Aktuelle Brettgroesse: <span id="boardSizeValue">8</span> x <span
id="boardSizeValueMirror">8</span></p> <button class="info-button" id="infoButton" onclick="toggleInfoModal(true)" type="button"
aria-label="Spielregeln und Hilfe anzeigen">Regeln & Hilfe</button>
</div>
<p class="board-size-info" id="boardSizeInfo"><span id="boardSizeInfoPrefix">Aktuelle Brettgrösse im
Damen-Modus:</span>
<span id="boardSizeValue">8</span> x <span id="boardSizeValueMirror">8</span>
</p>
<div class="game-stats" aria-label="Spielstatus"> <div class="game-stats" aria-label="Spielstatus">
<article class="game-stat-card"> <article class="game-stat-card">
<p class="game-stat-label">Schritte</p> <p class="game-stat-label" id="stepsLabel">Schritte</p>
<p class="game-stat-value" id="stepCounterValue">0</p> <p class="game-stat-value" id="stepCounterValue">0</p>
</article> </article>
<article class="game-stat-card"> <article class="game-stat-card">
<p class="game-stat-label">Zeit</p> <p class="game-stat-label" id="timeLabel">Zeit</p>
<p class="game-stat-value" id="timerValue">00:00:00</p> <p class="game-stat-value" id="timerValue">00:00:00</p>
</article> </article>
<article class="game-stat-card"> <article class="game-stat-card">
<p class="game-stat-label">Status</p> <p class="game-stat-label" id="statusLabel">Status</p>
<p class="game-stat-value game-stat-status" id="gameProgressState">Laeuft</p> <p class="game-stat-value game-stat-status" id="gameProgressState">Läuft</p>
</article> </article>
</div> </div>
<p id="statusMessage"></p> <p id="statusMessage"></p>
<div class="solved-celebration" id="solvedCelebration" aria-live="polite" hidden>
<p class="solved-celebration-title" id="solvedCelebrationTitle">Richtig gelöst!</p>
<p class="solved-celebration-text" id="solvedCelebrationText">Stark gemacht. Das Brett ist konfliktfrei.
</p>
</div>
<div class="board" id="board"></div> <div class="board" id="board"></div>
<div class="controls">
<button class="btn secondary" onclick="resetBoard()" id="btnReset" type="button">Brett
zuruecksetzen</button>
<div class="controls-save-row">
<button class="btn" onclick="openSavePanel()" id="btnSave" type="button">Speichern</button>
<button class="btn secondary" onclick="openSavePointsPanel()" id="btnLoad"
type="button">Save-Points</button>
</div>
</div>
<div class="solver-panel"> <div class="solver-panel">
<div class="solver-panel-header"> <div class="solver-panel-header">
<div> <div>
<h3>Solver-Ablauf</h3> <p class="section-kicker" id="solverKicker">Solver</p>
<p class="solver-message" id="solverMessage">Bereite einen Ablauf vor und spiele ihn Schritt fuer Schritt ab.</p> <h3 id="solverTitle">Lösungswerkzeuge</h3>
<p class="solver-message" id="solverMessage">Bereite einen Ablauf vor und spiele ihn Schritt
für Schritt ab.</p>
</div> </div>
<p class="solver-step-info" id="solverStepInfo">Schritt 0 / 0</p> <p class="solver-step-info" id="solverStepInfo">Schritt 0 / 0</p>
</div> </div>
<div class="solver-groups">
<section class="solver-group">
<h4 id="animationSolverTitle">Animations-Solver</h4>
<p class="solver-group-text" id="animationSolverText">
Bereite den Lösungsweg vor, gehe ihn manüll Schritt für Schritt durch oder spiele die
Animation automatisch ab.
</p>
<div class="solver-controls"> <div class="solver-controls">
<button class="btn" onclick="prepareSolutionTrace()" id="btnPrepareSolve" type="button">Solve Step-by-Step</button> <button class="btn" onclick="prepareSolutionTrace()" id="btnPrepareSolve"
<button class="btn secondary" onclick="instantSolve()" id="btnInstantSolve" type="button">Instant Solve</button> type="button">Animation vorbereiten</button>
<button class="btn secondary" onclick="nextSolverStep()" id="btnNextStep" type="button">Next Step</button> <button class="btn secondary" onclick="nextSolverStep()" id="btnNextStep"
<button class="btn secondary" onclick="toggleSolverPlayback()" id="btnPlayPause" type="button">Play Animation</button> type="button">Nächster Schritt</button>
<button class="btn secondary" onclick="toggleSolverPlayback()" id="btnPlayPause"
type="button">Animation abspielen</button>
</div> </div>
<div class="solver-speed"> <div class="solver-speed">
<label class="solver-speed-label" for="solverSpeedInput">Speed</label> <label class="solver-speed-label" id="solverSpeedLabel"
for="solverSpeedInput">Animationsgeschwindigkeit</label>
<input id="solverSpeedInput" type="range" min="80" max="900" step="20" value="320" <input id="solverSpeedInput" type="range" min="80" max="900" step="20" value="320"
oninput="updateSolverSpeed(this.value)"> oninput="updateSolverSpeed(this.value)">
<span class="solver-speed-value" id="solverSpeedValue">320 ms</span> <span class="solver-speed-value" id="solverSpeedValue">320 ms</span>
</div> </div>
</section>
<section class="solver-group instant-solver-group">
<h4 id="instantSolverTitle">Sofort-Lösung</h4>
<p class="solver-group-text" id="instantSolverText">
Lade direkt eine gültige Lösung, ohne Zwischenschritte oder Animation.
</p>
<div class="instant-solver-actions">
<button class="btn accent" onclick="instantSolve()" id="btnInstantSolve"
type="button">Sofort lösen</button>
</div>
</section>
</div> </div>
<div class="controls">
<button class="btn" onclick="checkSolution()">Check</button>
<button class="btn secondary" onclick="resetBoard()">Reset</button>
<button class="btn" onclick="openSavePanel()">💾 Save</button>
<button class="btn" onclick="openSavePointsPanel()">📂 Load</button>
</div> </div>
</div> </div>
<div class="card"> <div class="card piece-card">
<h3>📋 Figuren Positionen</h3> <div class="section-header">
<h3 id="pieceListTitle">Positionen der Damen</h3>
<span class="section-badge" id="pieceCountBadge">0 gesetzt</span>
</div>
<ul id="queenList"></ul> <ul id="queenList"></ul>
</div> </div>
<div class="card"> <div class="card">
<div class="history-header"> <div class="history-header">
<div> <div>
<h3>⏱️ Bisherige Zeiten</h3> <p class="section-kicker" id="historyKicker">Save-Points</p>
<p class="history-subtitle">Die Tabelle zeigt gespeicherte Save-Points mit Zeit und Schritten.</p> <h3 id="historyTitle">Gespeicherte Zeiten und Fortschritte</h3>
<p class="history-subtitle" id="historySubtitle">Die Tabelle zeigt gespeicherte Save-Points mit
Zeit, Schritten und
Status.</p>
</div> </div>
<button class="btn secondary" onclick="refreshTimeHistory()" type="button">Aktualisieren</button> <button class="btn secondary" onclick="refreshTimeHistory()" id="btnRefreshHistory"
type="button">Aktualisieren</button>
</div> </div>
<div class="history-table-wrapper"> <div class="history-table-wrapper">
<table class="history-table"> <table class="history-table">
<thead> <thead>
<tr> <tr>
<th>Save-Point</th> <th id="historyHeadSave">Save-Point</th>
<th>Modus</th> <th id="historyHeadMode">Modus</th>
<th>Brett</th> <th id="historyHeadBoard">Brett</th>
<th>Schritte</th> <th id="historyHeadSteps">Schritte</th>
<th>Zeit</th> <th id="historyHeadTime">Zeit</th>
<th>Status</th> <th id="historyHeadStatus">Status</th>
<th>Gespeichert</th> <th id="historyHeadSaved">Gespeichert</th>
</tr> </tr>
</thead> </thead>
<tbody id="timeHistoryTableBody"> <tbody id="timeHistoryTableBody">
@@ -155,64 +217,69 @@
</div> </div>
</div> </div>
<aside class="sidebar" id="settingsSidebar" aria-hidden="true"> <aside class="sidebar settings-sidebar" id="settingsSidebar" aria-hidden="true">
<div class="sidebar-header"> <div class="sidebar-header">
<h3>Brettgroesse</h3> <h3 id="settingsSidebarTitle">Brett-Einstellungen</h3>
<button class="btn secondary sidebar-close" onclick="toggleSidebar(false)" type="button">Schliessen</button> <button class="btn secondary sidebar-close" onclick="toggleSidebar(false)" id="settingsSidebarClose"
type="button">Schliessen</button>
</div> </div>
<p>Wähle eine Grösse zwischen 4 und 13.</p> <p id="settingsSidebarText">Passe die Brettgrösse zwischen 4 und 13 an.</p>
<label class="sidebar-label" for="boardSizeInput">Groesse</label> <label class="sidebar-label" id="boardSizeInputLabel" for="boardSizeInput">Grösse</label>
<input id="boardSizeInput" type="range" min="4" max="13" value="8" oninput="previewBoardSize(this.value)"> <input id="boardSizeInput" type="range" min="4" max="13" value="8" oninput="previewBoardSize(this.value)">
<div class="sidebar-size-row"> <div class="sidebar-size-row">
<strong><span id="sidebarBoardSizeValue">8</span> x <span id="sidebarBoardSizeValueMirror">8</span></strong> <strong><span id="sidebarBoardSizeValue">8</span> x <span id="sidebarBoardSizeValueMirror">8</span></strong>
</div> </div>
<button class="btn" onclick="applyBoardSize()" type="button">Apply Size</button> <button class="btn" onclick="applyBoardSize()" id="applyBoardSizeButton" type="button">Grösse anwenden</button>
<p class="sidebar-hint">Das Brett wird beim Ändern zur Sicherheit zurückgesetzt.</p> <p class="sidebar-hint" id="settingsSidebarHint">Beim Ändern wird das Brett zur Sicherheit zurückgesetzt. Auf
dem Handy ist 8x8 eingeplant, grössere Bretter können abgeschnitten wirken.</p>
</aside> </aside>
<aside class="sidebar save-sidebar" id="saveSidebar" aria-hidden="true"> <aside class="sidebar save-sidebar" id="saveSidebar" aria-hidden="true">
<div class="sidebar-header"> <div class="sidebar-header">
<h3>Speicherpunkt</h3> <h3 id="saveSidebarTitle">Speicherpunkt</h3>
<button class="btn secondary sidebar-close" onclick="toggleSavePanel(false)" type="button">Schliessen</button> <button class="btn secondary sidebar-close" onclick="toggleSavePanel(false)" id="saveSidebarClose"
type="button">Schliessen</button>
</div> </div>
<p>Gib dem Spielstand einen klaren Namen und optional eine kurze Notiz.</p> <p id="saveSidebarText">Gib dem Spielstand einen klaren Namen und optional eine kurze Notiz.</p>
<label class="sidebar-label" for="saveNameInput">Name</label> <label class="sidebar-label" id="saveNameLabel" for="saveNameInput">Name</label>
<input class="sidebar-input" id="saveNameInput" type="text" maxlength="80" placeholder="z. B. Fast geloeste Dame 8x8"> <input class="sidebar-input" id="saveNameInput" type="text" maxlength="80"
placeholder="z. B. Fast gelöste Dame 8x8">
<label class="sidebar-label" for="saveNoteInput">Notiz</label> <label class="sidebar-label" id="saveNoteLabel" for="saveNoteInput">Notiz</label>
<textarea class="sidebar-input sidebar-textarea" id="saveNoteInput" rows="4" maxlength="240" <textarea class="sidebar-input sidebar-textarea" id="saveNoteInput" rows="4" maxlength="240"
placeholder="z. B. Gute Startposition fuer Tuermetest"></textarea> placeholder="z. B. Gute Startposition für Türmetest"></textarea>
<label class="sidebar-checkbox"> <label class="sidebar-checkbox">
<input id="saveFavoriteInput" type="checkbox"> <input id="saveFavoriteInput" type="checkbox">
Als Favorit markieren <span id="saveFavoriteLabel">Als Favorit markieren</span>
</label> </label>
<button class="btn" onclick="saveGame()" type="button">Jetzt speichern</button> <button class="btn" onclick="saveGame()" id="saveNowButton" type="button">Jetzt speichern</button>
</aside> </aside>
<aside class="sidebar save-points-sidebar" id="savePointsSidebar" aria-hidden="true"> <aside class="sidebar save-points-sidebar" id="savePointsSidebar" aria-hidden="true">
<div class="sidebar-header"> <div class="sidebar-header">
<h3>Save Points</h3> <h3 id="savePointsSidebarTitle">Save-Points</h3>
<button class="btn secondary sidebar-close" onclick="toggleSavePointsPanel(false)" type="button">Schliessen</button> <button class="btn secondary sidebar-close" onclick="toggleSavePointsPanel(false)"
id="savePointsSidebarClose" type="button">Schliessen</button>
</div> </div>
<p>Waehle einen Speicherstand aus der Liste.</p> <p id="savePointsSidebarText">Wähle einen Speicherstand aus der Liste.</p>
<div class="save-point-filters"> <div class="save-point-filters">
<label class="sidebar-label" for="savePointModeFilter">Modus</label> <label class="sidebar-label" id="savePointModeFilterLabel" for="savePointModeFilter">Modus</label>
<select class="sidebar-input" id="savePointModeFilter" onchange="refreshSavePoints()"> <select class="sidebar-input" id="savePointModeFilter" onchange="refreshSavePoints()">
<option value="all">Alle</option> <option value="all">Alle</option>
<option value="queens">Damen</option> <option value="queens">Damen</option>
<option value="rooks">Tuerme</option> <option value="rooks">Türme</option>
</select> </select>
<label class="sidebar-label" for="savePointSizeFilter">Brettgroesse</label> <label class="sidebar-label" id="savePointSizeFilterLabel" for="savePointSizeFilter">Brettgrösse</label>
<select class="sidebar-input" id="savePointSizeFilter" onchange="refreshSavePoints()"> <select class="sidebar-input" id="savePointSizeFilter" onchange="refreshSavePoints()">
<option value="all">Alle</option> <option value="all">Alle</option>
{% for board_size in range(4, 14) %} {% for board_size in range(4, 14) %}
@@ -220,22 +287,22 @@
{% endfor %} {% endfor %}
</select> </select>
<label class="sidebar-label" for="savePointSortFilter">Sortierung</label> <label class="sidebar-label" id="savePointSortFilterLabel" for="savePointSortFilter">Sortierung</label>
<select class="sidebar-input" id="savePointSortFilter" onchange="refreshSavePoints()"> <select class="sidebar-input" id="savePointSortFilter" onchange="refreshSavePoints()">
<option value="newest">Neueste zuerst</option> <option value="newest">Neueste zuerst</option>
<option value="oldest">Aelteste zuerst</option> <option value="oldest">älteste zuerst</option>
<option value="updated">Zuletzt bearbeitet</option> <option value="updated">Zuletzt bearbeitet</option>
<option value="favorites">Favoriten zuerst</option> <option value="favorites">Favoriten zuerst</option>
</select> </select>
<label class="sidebar-checkbox"> <label class="sidebar-checkbox">
<input id="savePointFavoritesOnly" type="checkbox" onchange="refreshSavePoints()"> <input id="savePointFavoritesOnly" type="checkbox" onchange="refreshSavePoints()">
Nur Favoriten anzeigen <span id="savePointFavoritesOnlyLabel">Nur Favoriten anzeigen</span>
</label> </label>
</div> </div>
<div class="save-points-list" id="savePointsList"> <div class="save-points-list" id="savePointsList">
<p class="sidebar-hint">Noch keine Speicherstaende gefunden.</p> <p class="sidebar-hint" id="savePointsEmptyState">Noch keine Speicherstände gefunden.</p>
</div> </div>
</aside> </aside>
@@ -246,31 +313,31 @@
<div class="modal-backdrop" id="infoModalBackdrop" onclick="toggleInfoModal(false)"></div> <div class="modal-backdrop" id="infoModalBackdrop" onclick="toggleInfoModal(false)"></div>
<section class="modal" id="infoModal" aria-hidden="true" aria-labelledby="infoModalTitle"> <section class="modal" id="infoModal" aria-hidden="true" aria-labelledby="infoModalTitle">
<div class="modal-header"> <div class="modal-header">
<h3 id="infoModalTitle">Spielanleitung und Acht-Damen-Problem</h3> <h3 id="infoModalTitle">Spielregeln und Acht-Damen-Problem</h3>
<button class="btn secondary sidebar-close" onclick="toggleInfoModal(false)" type="button">Schliessen</button> <button class="btn secondary sidebar-close" onclick="toggleInfoModal(false)"
type="button">Schliessen</button>
</div> </div>
<div class="modal-content"> <div class="modal-content">
<p>Setze pro Reihe genau eine Figur auf das Brett. Eine gueltige Loesung hat keine Konflikte.</p> <p>Setze pro Reihe genau eine Figur auf das Brett. Eine gültige Lösung hat keine Konflikte.</p>
<h4>So funktioniert das Spiel</h4> <h4>So funktioniert der aktuelle Modus</h4>
<p>Im Damen-Modus duerfen sich Damen weder in derselben Spalte noch diagonal angreifen. Im Tuerme-Modus <p id="infoModeRuleText">Im Damen-Modus dürfen sich Damen weder in derselben Spalte noch diagonal
zaehlen nur Spalten-Konflikte. Mit einem Klick setzt oder entfernst du eine Figur.</p> angreifen. Mit einem Klick setzt oder entfernst du eine Figur.</p>
<h4>Was ist das Acht-Damen-Problem?</h4> <h4 id="infoModalProblemHeading">Was ist das Acht-Damen-Problem?</h4>
<p>Das klassische Acht-Damen-Problem fragt nach einer Anordnung von acht Damen auf einem 8x8-Brett, bei <p id="infoModalProblemText">Das klassische Acht-Damen-Problem fragt nach einer Anordnung von acht Damen
der sich keine zwei Damen schlagen. Es ist ein bekanntes Beispiel fuer kombinatorische Suche und auf einem 8x8-Brett, bei der sich keine zwei Damen schlagen. Es ist ein bekanntes Beispiel für
Backtracking.</p> kombinatorische Suche und Backtracking.</p>
<h4>Was zeigen Zeit und Schritte?</h4> <h4>Was zeigen Zeit und Schritte?</h4>
<p>Der Schrittzaehler erfasst deine Zuege auf dem Brett. Die Zeit laeuft fuer das aktuelle Spiel weiter, <p>Der Schrittzähler erfasst deine Züge auf dem Brett. Die Zeit läuft für das aktuelle Spiel weiter,
auch wenn du die Seite neu laedst. Beim Speichern werden Zeit und Schritte zusammen mit dem Save-Point auch wenn du die Seite neu lädst. Beim Speichern werden Zeit und Schritte zusammen mit dem
abgelegt.</p> Save-Point abgelegt.</p>
</div> </div>
</section> </section>
<script src="{{ url_for('static', filename='js/dashboard.js') }}"></script> <script src="{{ url_for('static', filename='js/dashboard.js') }}"></script>
</body> </body>
</html> </html>
+3
View File
@@ -27,6 +27,9 @@ CREATE TABLE game_state (
save_name VARCHAR(80) NOT NULL DEFAULT 'Unnamed Save', save_name VARCHAR(80) NOT NULL DEFAULT 'Unnamed Save',
save_note TEXT NOT NULL DEFAULT '', save_note TEXT NOT NULL DEFAULT '',
is_favorite BOOLEAN NOT NULL DEFAULT 0, is_favorite BOOLEAN NOT NULL DEFAULT 0,
step_count INTEGER NOT NULL DEFAULT 0,
elapsed_seconds INTEGER NOT NULL DEFAULT 0,
is_solved BOOLEAN NOT NULL DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP, created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
); );