← All templates
    Backend Logic
    Free download

    Internal Admin Dashboard Template for Lovable

    Role-gated metrics and an append-only event log, where the admin check lives in the database rather than in a hidden menu item.

    Stack: React + Vite, TypeScript, Tailwind CSS, shadcn/ui, Supabase

    What is in the download

    • A build prompt that requires a window on every metric and distinguishes zero from unknown
    • A schema with a separate user_roles table and an events log
    • RLS where a member sees only their own events and an admin sees all of them
    • No insert policy on user_roles at all, so nobody can self-promote from the client
    • An aggregate function deliberately left non-definer, so it respects the caller's policies
    • Seven verification queries, run once as a member and once as an admin

    What it is not

    • Not a pre-built app you clone and run. There is no repository and no node_modules.
    • Not a design file or a theme. Lovable generates the interface from the prompt.
    • Not a substitute for reading the SQL. You are running it against your own database.

    Setup order

    Running these out of order is the usual reason a template appears broken. The schema comes before the prompt, because the prompt references the table names it creates.

    1. Run schema.sql in the Supabase SQL editor

      Creates the role type, both tables and the policies.

    2. Grant yourself admin from the SQL editor

      The commented statement at the end of schema.sql. Deliberately not an endpoint, because a self-service role grant is a privilege escalation.

    3. Run verify.sql as a member first

      The member results prove the policies. Running only as an admin proves nothing.

    4. Paste prompt.md into Lovable

    Things that catch people out

    • Keeping roles in their own table rather than a column on profiles is what allows the read policy on user_roles to differ from the write policy. A role column on a user-editable profile row is self-service privilege escalation.
    • event_counts_by_day() is intentionally not SECURITY DEFINER. If you add that keyword to make a chart work for non-admins, you have just exposed the whole event log. Verification query 5 catches it.
    • There is no update or delete policy on events, because an audit log that can be rewritten is not one.

    prompt.md

    Download

    The build prompt

    # Context
    Build an internal dashboard that answers what is happening right now, for a team operating a
    product rather than browsing analytics. The reader is an operator on a shift, so the page
    must be legible in five seconds and must never show a number without a time window.
    
    ## Core Features (Priority Order)
    1. Role-gated access: only users with the admin role may open the dashboard at all
    2. Four headline metrics with an explicit window on each, such as last 24 hours
    3. One time-series chart with a selectable range, defaulting to 7 days
    4. A recent-events table, newest first, paginated
    5. An empty state that distinguishes "no data yet" from "query failed"
    
    ## Visual Style
    - Information density over whitespace, but one clear hierarchy: metrics, chart, table
    - shadcn/ui: Card for metric tiles, Table for events, Tabs or Select for the range picker,
      Skeleton for loading, Badge for event severity
    - Numbers right-aligned and tabular, so columns scan vertically
    
    ## Technical Requirements
    - Breakpoints sm 640px, md 768px, lg 1024px; the table scrolls inside its own container
      rather than making the page scroll sideways
    - Every metric states its window in the tile, not in a tooltip
    - Loading skeletons sized to the final content, so nothing jumps
    - Distinguish zero from unknown: render a dash for a failed query, never 0
    - Dark mode via Tailwind's dark: prefix
    
    ## Implementation Strategy
    1. The admin role check and the route guard, before any query
    2. One metric tile end to end against the schema in schema.sql
    3. The remaining tiles, then the events table
    4. The chart last, because it depends on the aggregate function being settled
    
    ## Safe-Guard Instructions
    - A dashboard is not an implementation of access control. Enforce the admin check in the
      data layer as well as the UI: the policies in schema.sql do this.
    - Never expose raw event payloads to a non-admin.
    - Do not add a policy that lets a user read all events "for testing".
    - Aggregate reads must respect the same policies as row reads.
    
    ## Growth Features (Required for Distribution)
    - **Product-led Growth:** expose a narrow, read-only version of one metric to ordinary users
      in their own account view, so the value of the data is visible without granting admin.

    schema.sql

    In the bundle

    Roles, events and policies

    -- Internal dashboard schema for Lovable + Supabase
    -- Reviewed row-level security. Read the comments before running this.
    --
    -- The point of this file: role checks live in the database, not only in the UI. A generated
    -- dashboard that hides a menu item is not access control.
    
    create type public.app_role as enum ('admin', 'member');
    
    create table public.user_roles (
      user_id uuid not null references auth.users (id) on delete cascade,
      role public.app_role not null default 'member',
      created_at timestamptz not null default now(),

    The rest of schema.sql, with every policy written and its denials verified, is in The Complete Lovable Bundle.

    Get the Bundle

    verify.sql

    In the bundle

    Policy verification queries

    -- Verification queries. Run these as an ordinary member first, then as an admin.
    -- The member results are the ones that prove the policies work.
    
    -- As a MEMBER (no admin role):
    
    -- 1. Should return only your own events, never the whole table.
    select id, name, user_id from public.events order by created_at desc limit 20;
    
    -- 2. Should return only your own role row.
    select * from public.user_roles;
    
    -- 3. Should FAIL. There is no insert policy on user_roles, so nobody self-promotes.

    The rest of verify.sql, with every policy written and its denials verified, is in The Complete Lovable Bundle.

    Get the Bundle

    Next

    If you want a prompt rather than a whole starting point, the prompt library has 101 of them across six categories. If you are watching what this costs to build, how Lovable credits work explains why a vague prompt against a large project is expensive twice over.