remove obsolete prompt files and add .gitkeep to codex-prompt directory
This commit is contained in:
parent
591323a2f8
commit
89c0a89d00
|
|
@ -1,79 +0,0 @@
|
||||||
TASK: Aggiungere Dark Mode globale con toggle nel footer (Tailwind).
|
|
||||||
|
|
||||||
Vincoli:
|
|
||||||
- Usare Tailwind dark mode con strategia "class" (non media)
|
|
||||||
- Toggle nel footer visibile su tutte le pagine (layout globale)
|
|
||||||
- Stato persistente con localStorage
|
|
||||||
- Default: se non c’è preferenza salvata, usare prefers-color-scheme
|
|
||||||
- Nessun framework JS aggiuntivo
|
|
||||||
- Non rompere HTMX
|
|
||||||
- Accessibile (aria-label, stato, focus)
|
|
||||||
|
|
||||||
1) Tailwind config
|
|
||||||
- Aggiornare tailwind.config.js:
|
|
||||||
- impostare `darkMode: 'class'`
|
|
||||||
- assicurarsi che content includa templates e script statici come già configurato
|
|
||||||
|
|
||||||
2) JS globale
|
|
||||||
- Creare file /web/static/vendor/theme.js (o /web/static/js/theme.js se preferisci) con:
|
|
||||||
- all’avvio (prima del render visibile):
|
|
||||||
- leggere localStorage key `theme` ('dark'|'light')
|
|
||||||
- se non presente, leggere `window.matchMedia('(prefers-color-scheme: dark)')`
|
|
||||||
- applicare/rimuovere classe `dark` su <html> (document.documentElement)
|
|
||||||
- esporre funzione toggleTheme() che:
|
|
||||||
- toggla classe `dark`
|
|
||||||
- salva preferenza in localStorage
|
|
||||||
- aggiorna label testo del bottone e aria-pressed
|
|
||||||
- gestire aggiornamento se l’utente non ha preferenza salvata e cambia prefers-color-scheme (listener matchMedia), opzionale ma gradito
|
|
||||||
|
|
||||||
3) Includere theme.js nel layout
|
|
||||||
- In /web/templates/layout.html:
|
|
||||||
- includere theme.js nel <head> prima del CSS per evitare FOUC:
|
|
||||||
<script src="/static/vendor/theme.js"></script>
|
|
||||||
- poi link CSS e script frontend come già presenti
|
|
||||||
- aggiungere classi base al body per dark:
|
|
||||||
- bg-white dark:bg-gray-900
|
|
||||||
- text-gray-900 dark:text-gray-100
|
|
||||||
- min-h-screen flex flex-col
|
|
||||||
- contenuto in main con flex-1
|
|
||||||
|
|
||||||
4) Footer + toggle button (Tailwind style)
|
|
||||||
- Nel footer del layout aggiungere un bottone:
|
|
||||||
- posizionato a destra (o center se preferisci) con icona (testo va bene senza icone)
|
|
||||||
- classi Tailwind:
|
|
||||||
- px-3 py-2 text-sm font-medium rounded-lg
|
|
||||||
- bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700
|
|
||||||
- attributi accessibilità:
|
|
||||||
- id="themeToggle"
|
|
||||||
- type="button"
|
|
||||||
- aria-label="Toggle dark mode"
|
|
||||||
- aria-pressed="false" (aggiornato via JS)
|
|
||||||
- testo dinamico: "Dark mode" / "Light mode" o "Tema: Scuro/Chiaro"
|
|
||||||
|
|
||||||
- Aggiungere onclick:
|
|
||||||
- onclick="window.toggleTheme && window.toggleTheme()"
|
|
||||||
|
|
||||||
5) Aggiornare componenti base per dark
|
|
||||||
- Aggiornare /web/templates/components/navbar.html (se esiste) e altri partial principali con classi dark:
|
|
||||||
- Navbar: bg-white dark:bg-gray-900, border-gray-200 dark:border-gray-700
|
|
||||||
- Dropdown: bg-white dark:bg-gray-800, text colors
|
|
||||||
- Cards: bg-white dark:bg-gray-800
|
|
||||||
- Tables: dark divide colors
|
|
||||||
Non serve perfezione totale, ma assicurare leggibilità.
|
|
||||||
|
|
||||||
6) README
|
|
||||||
- Aggiornare README con nota:
|
|
||||||
- dark mode persistente in localStorage key "theme"
|
|
||||||
|
|
||||||
7) Criteri di accettazione
|
|
||||||
- Il toggle è visibile nel footer su tutte le pagine
|
|
||||||
- Il tema persiste al reload
|
|
||||||
- Default segue prefers-color-scheme se non impostato manualmente
|
|
||||||
- Nessun flash di tema sbagliato (FOUC minimizzato)
|
|
||||||
- Non rompe modals, dropdown e HTMX
|
|
||||||
- Accessibile: bottone focusable e aria-pressed aggiornato
|
|
||||||
|
|
||||||
Esegui:
|
|
||||||
- make tw-build (o make tw-watch per verificare)
|
|
||||||
- Avvia server e verifica cambio tema su /login e /users.
|
|
||||||
Correggi eventuali classi mancanti.
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
Sei Codex in VS Code. Lavora direttamente nel workspace.
|
|
||||||
|
|
||||||
Obiettivo: creare un boilerplate riusabile “GoFiber MVC + HTMX + Svelte Custom Elements UI kit + GORM + SQLite/Postgres + Auth + Email sink + CORS + template directory public/private/admin + role admin”.
|
|
||||||
|
|
||||||
1) Scansiona il workspace e dimmi cosa esiste già.
|
|
||||||
2) Crea/aggiorna la struttura cartelle secondo questa convenzione:
|
|
||||||
/cmd/server
|
|
||||||
/internal/{app,config,http,middleware,db,models,repo,services,controllers,auth,mailer}
|
|
||||||
/web/{templates/{public,private,admin},emails/templates,static/{vendor,ui,css}}
|
|
||||||
/ui-kit
|
|
||||||
/data (solo dev)
|
|
||||||
3) Crea una TODO checklist in README.md con i passi rimanenti.
|
|
||||||
Non implementare ancora logica: solo struttura + README e .gitignore.
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
Implementa internal/config e internal/app.
|
|
||||||
|
|
||||||
- Aggiungi internal/config/config.go:
|
|
||||||
- carica .env se presente (godotenv)
|
|
||||||
- espone Config con: AppName, Env (develop|prod), Port, BaseURL, BuildHash
|
|
||||||
DBDriver (sqlite|postgres), SQLitePath, PostgresDSN
|
|
||||||
CORS settings (origins/headers/methods/credentials)
|
|
||||||
SessionKey
|
|
||||||
SMTP settings + EmailSinkDir
|
|
||||||
Flags: AutoMigrate, SeedEnabled
|
|
||||||
- valida i campi essenziali (es. DB DSN se postgres)
|
|
||||||
|
|
||||||
- Aggiungi internal/app/app.go:
|
|
||||||
- crea fiber.App
|
|
||||||
- registra CORS middleware
|
|
||||||
- registra session store
|
|
||||||
- init DB (internal/db) + migrate/seed (in base ai flag)
|
|
||||||
- registra router (internal/http/router.go)
|
|
||||||
- espone NewApp(cfg) (*fiber.App, error)
|
|
||||||
|
|
||||||
- Aggiorna cmd/server/main.go per usare internal/app.
|
|
||||||
|
|
||||||
Crea/aggiorna .env.example e .gitignore (escludi .env, /data, db sqlite, email sink).
|
|
||||||
Scrivi codice compilabile.
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
Aggiungi DX boilerplate.
|
|
||||||
|
|
||||||
- Makefile:
|
|
||||||
- make dev (go run ./cmd/server)
|
|
||||||
- make ui-build (cd ui-kit && npm i && npm run build)
|
|
||||||
- make ui-dev (watch)
|
|
||||||
- make test (go test ./...)
|
|
||||||
- make db-reset (solo sqlite: rimuovi ./data/app.db)
|
|
||||||
- make fmt (gofmt)
|
|
||||||
|
|
||||||
- docker-compose.yml:
|
|
||||||
- postgres service (porta 5432)
|
|
||||||
- env compatibile con DB_PG_DSN
|
|
||||||
|
|
||||||
- README.md:
|
|
||||||
- Quickstart sqlite
|
|
||||||
- Quickstart postgres (docker compose)
|
|
||||||
- dove stanno templates public/private/admin
|
|
||||||
- email in develop: ./data/emails
|
|
||||||
- build UI kit
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
Implementa internal/db (db.go, migrate.go, seed.go) con GORM.
|
|
||||||
|
|
||||||
- db.go: Open(cfg) (*gorm.DB, error) con switch sqlite/postgres.
|
|
||||||
- sqlite usa cfg.SQLitePath, crea directory se serve.
|
|
||||||
- postgres usa cfg.PostgresDSN.
|
|
||||||
- logger più verboso in develop.
|
|
||||||
|
|
||||||
- migrate.go: Migrate(db) che fa AutoMigrate su tutti i modelli (User, EmailVerificationToken, PasswordResetToken).
|
|
||||||
- esegui solo se cfg.AutoMigrate=true (gestisci in app.go o in migrate.go).
|
|
||||||
|
|
||||||
- seed.go: Seed(db) idempotente se cfg.SeedEnabled=true:
|
|
||||||
- in develop crea:
|
|
||||||
- admin@example.com (role=admin, verified=true, password="password")
|
|
||||||
- user@example.com (role=user, verified=true, password="password")
|
|
||||||
- crea anche utenti demo aggiuntivi per tabella.
|
|
||||||
- usa upsert by email (GORM clauses OnConflict dove possibile).
|
|
||||||
- NON loggare password in chiaro.
|
|
||||||
|
|
||||||
Aggiorna/crea internal/models con i modelli necessari.
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
Implementa internal/models e internal/auth.
|
|
||||||
|
|
||||||
- internal/models/user.go:
|
|
||||||
- User: ID, Email unique, PasswordHash, EmailVerified, Role (default user), timestamps.
|
|
||||||
|
|
||||||
- internal/models/auth_tokens.go:
|
|
||||||
- EmailVerificationToken: UserID, TokenHash unique, ExpiresAt, timestamps
|
|
||||||
- PasswordResetToken: UserID, TokenHash unique, ExpiresAt, timestamps
|
|
||||||
|
|
||||||
- internal/auth/passwords.go:
|
|
||||||
- HashPassword(plain) -> hash (bcrypt)
|
|
||||||
- ComparePassword(hash, plain) -> bool/error
|
|
||||||
|
|
||||||
- internal/auth/tokens.go:
|
|
||||||
- NewToken() -> plainToken (base64url random 32+ bytes)
|
|
||||||
- HashToken(plainToken) -> hex/bytes SHA-256 string
|
|
||||||
- ExpiresAt helpers (verify 24h, reset 1h)
|
|
||||||
|
|
||||||
Assicurati che nel DB venga salvato SOLO l’hash del token.
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
Implementa internal/mailer.
|
|
||||||
|
|
||||||
Requisiti:
|
|
||||||
- directory template email: /web/emails/templates
|
|
||||||
- verify_email.html + .txt
|
|
||||||
- reset_password.html + .txt
|
|
||||||
|
|
||||||
- internal/mailer/templates.go:
|
|
||||||
- carica e renderizza template (html+txt) con dati: AppName, BaseURL, VerifyURL/ResetURL, UserEmail.
|
|
||||||
|
|
||||||
- internal/mailer/mailer.go:
|
|
||||||
- interfaccia Mailer { Send(ctx, to, subject, htmlBody, textBody) error }
|
|
||||||
- factory NewMailer(cfg) che ritorna:
|
|
||||||
- sink mailer se cfg.Env==develop
|
|
||||||
- smtp mailer altrimenti
|
|
||||||
|
|
||||||
- internal/mailer/sink.go:
|
|
||||||
- salva in cfg.EmailSinkDir file con timestamp__type__to.eml (o .txt/.html)
|
|
||||||
- includi subject, to, bodies e link.
|
|
||||||
|
|
||||||
- internal/mailer/smtp.go:
|
|
||||||
- invio via SMTP usando cfg.SMTPHost/Port/User/Password/From/FromName.
|
|
||||||
|
|
||||||
Aggiorna README con “in develop le email sono salvate in ./data/emails”.
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
Aggiungi session e middleware.
|
|
||||||
|
|
||||||
- Usa Fiber session middleware (cookie session). Configura key da cfg.SessionKey, cookie secure in prod, SameSite Lax, HttpOnly.
|
|
||||||
|
|
||||||
- Implementa internal/http/middleware:
|
|
||||||
- RequireAuth: se non loggato redirect /login
|
|
||||||
- RequireAdmin: se role != admin -> 403 (pagina admin/forbidden o testo)
|
|
||||||
- CurrentUser helper (legge user_id da sessione, carica user da DB con repo)
|
|
||||||
|
|
||||||
- Implementa flash messages (success/error) in sessione:
|
|
||||||
- SetFlashSuccess/SetFlashError
|
|
||||||
- ConsumeFlash middleware che aggiunge al template data
|
|
||||||
|
|
||||||
Aggiorna layout.html per mostrare flash e navbar diversa per public/private/admin.
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
Implementa AUTH completo (server-rendered) e templates in /web/templates/public.
|
|
||||||
|
|
||||||
Routes:
|
|
||||||
- GET/POST /signup
|
|
||||||
- GET/POST /login
|
|
||||||
- POST /logout
|
|
||||||
- GET /verify-email?token=...
|
|
||||||
- GET/POST /forgot-password
|
|
||||||
- GET/POST /reset-password?token=...
|
|
||||||
|
|
||||||
Comportamento:
|
|
||||||
- Signup crea user (role=user, verified=false), genera verify token (hash in DB), invia email (mailer).
|
|
||||||
- Login: blocca se email non verificata.
|
|
||||||
- Verify-email: valida token, set EmailVerified=true, elimina token.
|
|
||||||
- Forgot-password: risposta sempre generica; se user esiste+verified, genera reset token e invia email.
|
|
||||||
- Reset-password: valida token, aggiorna password, elimina token.
|
|
||||||
|
|
||||||
Crea templates:
|
|
||||||
- public/login.html
|
|
||||||
- public/signup.html
|
|
||||||
- public/forgot_password.html
|
|
||||||
- public/reset_password.html
|
|
||||||
- public/verify_notice.html
|
|
||||||
- public/home.html (opzionale)
|
|
||||||
Aggiungi partial per flash (public/_flash.html) e includilo nel layout.
|
|
||||||
|
|
||||||
Usa repo/service per accesso DB e logica (non tutto nel controller).
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
Implementa modulo “users” sotto /web/templates/private/users.
|
|
||||||
|
|
||||||
Routes protette (RequireAuth):
|
|
||||||
- GET /users -> pagina con search + container tabella
|
|
||||||
- GET /users/table -> partial HTML tabella (ajax)
|
|
||||||
- GET /users/:id/modal -> partial HTML contenuto modal
|
|
||||||
|
|
||||||
Requisiti tabella:
|
|
||||||
- query params: q, sort (id|name|email whitelist), dir (asc|desc), page, pageSize
|
|
||||||
- server-driven paging/sort/search usando GORM (Count + Limit/Offset + Order)
|
|
||||||
- _table.html deve includere:
|
|
||||||
- header th cliccabili con fetch GET (toggle dir)
|
|
||||||
- pager prev/next con fetch GET
|
|
||||||
- bottone “Apri” che aggiorna `#userModal` via fetch + `innerHTML`
|
|
||||||
- apri modal via JS minimal: setAttribute('open','') dopo swap (o onclick)
|
|
||||||
|
|
||||||
Crea template:
|
|
||||||
- private/users/index.html
|
|
||||||
- private/users/_table.html
|
|
||||||
- private/users/_modal.html
|
|
||||||
|
|
||||||
Integra <ui-modal id="userModal"> nella index privata.
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
Implementa area admin.
|
|
||||||
|
|
||||||
Routes protette (RequireAuth + RequireAdmin):
|
|
||||||
- GET /admin -> admin/dashboard.html
|
|
||||||
- GET /admin/users -> pagina elenco utenti (server-rendered semplice)
|
|
||||||
|
|
||||||
Templates:
|
|
||||||
- admin/dashboard.html
|
|
||||||
- admin/users.html
|
|
||||||
|
|
||||||
Navbar nel layout deve mostrare link Admin solo se role=admin.
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
Crea /ui-kit come progetto Vite + Svelte per custom elements.
|
|
||||||
|
|
||||||
Requisiti:
|
|
||||||
- build deve scrivere direttamente in ../web/static/ui:
|
|
||||||
- ui.esm.js
|
|
||||||
- ui.css (tokens+base)
|
|
||||||
- src/index.ts registra:
|
|
||||||
- ui-modal
|
|
||||||
- ui-drop-down
|
|
||||||
- ui-data-table-shell (driver JS per aggiornare un target)
|
|
||||||
|
|
||||||
Componenti:
|
|
||||||
1) UiModal.svelte:
|
|
||||||
- <svelte:options customElement="ui-modal" />
|
|
||||||
- attributi: title, open (boolean presence)
|
|
||||||
- close on ESC, backdrop click
|
|
||||||
- focus trap minimale
|
|
||||||
- emette evento "ui:close" (bubbles+composed)
|
|
||||||
- slot contenuto (HTMX swappa dentro al tag)
|
|
||||||
|
|
||||||
2) UiDropDown.svelte:
|
|
||||||
- usa <option> del light DOM
|
|
||||||
- espone value/name/placeholder/disabled
|
|
||||||
- integra con form MVC (hidden input name=...)
|
|
||||||
- emette change + ui:change
|
|
||||||
|
|
||||||
3) UiDataTableShell.svelte:
|
|
||||||
- attributi: endpoint, target, page-size
|
|
||||||
- input search -> usa fetch('GET', url) e aggiorna il target
|
|
||||||
- non renderizza tabella, solo toolbar
|
|
||||||
|
|
||||||
Aggiorna layout per includere /static/ui/ui.css e /static/ui/ui.esm.js con ?v={{.BuildHash}}.
|
|
||||||
Aggiorna README con comandi npm.
|
|
||||||
Loading…
Reference in New Issue