Settings and Audit (SuperAdmin)
The tenant dashboard exposes an operator settings area at
/dashboard/amministrazione/settings/*, gated by IsSuperAdminGuard. Each page is
backed by a cookie-authenticated controller; sensitive endpoints re-check the
SuperAdmin role server-side. The raw JSON config editor lives at
/dashboard/amministrazione/configurazione-tecnica and is deliberately excluded
from the navigation surfaces.
Feature flags
| Page | /dashboard/amministrazione/settings/feature-flags |
| API | GET/POST /api/v1/admin/feature-flags |
| Access | Read is anonymous (login bootstrap); save requires Admin |
The page loads the whole flag list and batch-saves it — every toggle on the page
is posted in one request. Protected flags (_system_* keys and
enable_subscriptions once the subscriptions cutover marker is committed) are
skipped silently when their value is unchanged and rejected with
errors.general.permissionDenied when a real change is attempted, so an unrelated
batch never bricks the page.
Feature flags are audited entities (FeatureFlag : BaseAuditEntity), so every
value change is captured by the audit trail with actor and timestamps. See
Feature Flags for the flag list and semantics.
API tokens
| Page | /dashboard/amministrazione/settings/token-api |
| API | /api/v1/api-tokens |
| Access | SuperAdmin only |
- Create a token with a name, one or more permissions (scopes), allowed
origins (comma-separated;
*disables origin pinning) and an optionalexpiresAt. - The plaintext token is shown once, at creation. The database stores only a
SHA-256 hash plus an 8-character prefix (
TokenPrefix) used for identification. - Origin enforcement is strict: a token without
AllowedOriginsis rejected, and a request whoseOriginis not in the list is refused even if the token is valid. - Edit updates name/permissions/origins/expiry/active state; revoke deletes the
token record.
lastUsedAtandexpiresAtare visible in the table.
Tenant-side public-API tokens (native blog reader, sitemap, integrations) are
managed from the CLI with flo instance api-token ls|create|grant|revoke <id>.
Webhooks
| Page | /dashboard/amministrazione/settings/webhook |
| API | /api/v1/webhook-configs |
| Access | SuperAdmin only |
Webhooks dispatch external workflows (GitHub Actions / GitLab pipelines) when dynamic entities change:
- Provider: GitHub, GitLab, or Generic; target
Repository,WorkflowFile, andBranch. - Events: comma-separated
create,update,delete,publish; an empty list fires on every event. Additional workflowInputsJsoncan be attached. - Auth token: encrypted at rest with ASP.NET Data Protection
(
Flo.Webhook.AuthToken.v1); never returned in clear text. - Delivery log: each config tracks
LastTriggeredAt,LastTriggerStatus,LastTriggerError, andTriggerCount.POST /{id}/triggerandPOST /{id}/testrun a manual delivery from the UI (SuperAdmin only).
CORS origins
| Page | /dashboard/amministrazione/settings/origini-cors |
| API | /api/v1/cors-origins |
| Access | SuperAdmin only |
Origins are stored in the database and enforced by the backend's dynamic CORS
policy instead of static configuration. Operators can create, update, and delete
origins; each entry has an active flag and a description. GET /active returns the
effective list and POST /initialize seeds the default local development origins
(localhost:4200, 4201, 8080, 10001, 10002). Frontend origins for Cloudflare
Pages tenants are normally inserted automatically at provisioning time.
Audit trail
| Page | /dashboard/amministrazione/settings/audit-trail |
| API | /api/v1/audit-logs |
| Access | Read: Admin+ (IP addresses: SuperAdmin only) |
- Append-only:
ApplicationDbContextrejects updates and deletes ofAuditLogrows; only theAuditLogServicemaintenance paths may modify them. - Automatic capture: entity changes are staged in the same transaction as the
change itself, with actor, action (
Created/Modified/Deleted), entity name/ID, old/new values, and timestamp.AuditLogitself is never audited and machine-only writes are excluded. - Retention: default 730 days, configurable 30–3650 via
GET/PUT /retention.DELETE /purge?retentionDays=removes older entries (minimum 30). - Entity history:
GET /entity/{entityName}/{entityId}returns the full change history of one record; the UI expands each row to show old/new JSON. - Exports:
GET /export-querydownloads the filtered query as JSON (capped at 50,000 entries);GET /export/user/{userId}is the GDPR Article 15 export (SuperAdmin only). - Tombstones: GDPR anonymization (
POST /anonymize/user/{userId}, Article 17) and purges append an audit tombstone recording the maintenance action, its count, and details, so the log stays self-describing after data is redacted. - Salt chain: anonymization hashing uses
AUDIT_HASH_SALTS(comma-separated chain, latest salt current) withAuditLog:HashSaltas fallback; the CLI secret rotation appends new salts without invalidating old hashes.
Auth events (login failures)
| Page | /dashboard/amministrazione/settings/accessi-errori |
| API | /api/v1/auth-events |
| Access | SuperAdmin only |
Records social-login failures from two sources: server (rejected Google/Apple
exchanges) and client (the login page reports browser-side failures — blocked
popup, adblock — through an anonymous fire-and-forget POST /client). The GET
endpoint filters by method (google/apple), reason, source, and date range, and
returns pages of 50 entries. Client reports accept only allow-listed reasons and
never trust body-supplied IP/user-agent.
Login providers
| Page | /dashboard/amministrazione/settings/provider-accesso |
| API | /api/v1/external-auth-settings |
| Access | SuperAdmin only |
Stores the Google and Apple Client IDs used by social login. No client secrets are stored in the tenant database — only the public identifiers, upserted per provider.
Email templates
| Page | /dashboard/amministrazione/settings/template-email |
| API | GET /api/v1/newsletter/templates/* |
| Access | SuperAdmin (operational-notification permission for listing) |
Lists the transactional email templates known to the renderer with base name, language, and placeholder variables, and renders a live HTML preview for any template. Templates themselves live on disk in the application image; the page is a read-only inspection surface. See Email Configuration for providers and senders.
Email delivery log
| Page | /dashboard/amministrazione/settings/log-consegna-email |
| API | /api/v1/email-delivery-logs |
| Access | SuperAdmin only |
A single grid across every email provider, merging the local delivery log (written
by every send path) with live provider analytics. Filters: date range, status,
provider, recipient, send-job ID, and channel; paginated at 25 rows.
GET /availability drives the Settings tab visibility and is always enabled.
Config editor
| Page | /dashboard/amministrazione/configurazione-tecnica |
| API | /api/v1/config-editor |
| Access | SuperAdmin only |
Raw JSON editing for three files: theme (flo.theme.json), brand-config
(flo.configs.json), and whitelabel (<env>.config.json). The service validates
JSON before writing, creates a timestamped .bak.<yyyyMMddHHmmss> backup before
every save, and keeps the 5 most recent backups. File keys are allow-listed and
path traversal is rejected. All reads and writes are lease-guarded: on a DR standby
the page is read-only (see Failover and Disaster Recovery).
App logs
| Page | /dashboard/amministrazione/settings/log |
| API | /api/v1/logs |
| Access | SuperAdmin only |
Server-side log viewer over the application's rolling Serilog files:
- Periods:
24h,48h,72h,1w(default),1m,all. - Filters: log levels (
VRB,DBG,INF,WRN,ERR,FTL), free-text search, request path, and source context; newest-first with paging (max 5,000 rows per query). - Per-user view:
GET /user/{userId}. - Exports: CSV (
/export/csv) and JSON (/export/json). GET /diagnosticreports where the log files live on the container filesystem.
For container-level logs (blue/green/Traefik/Postgres) use the CLI:
flo logs app|db|proxy|errors|days|day|raw <id>.