A complete walkthrough for setting up Gesso on your machine and deploying it to production. Plan on roughly thirty to sixty minutes for a first-time setup, depending on whether you already have accounts with Supabase and Vercel.
Gesso runs on Next.js 16 with the App Router and uses Supabase for its database, authentication, and file storage. Make sure the following are installed and accessible from your terminal.
node --version. If you
need to install or upgrade, use
nodejs.org or a version
manager such as nvm.
npm, but any
package manager that respects the lockfile will work.
git --version.
Clone the repository to your machine and move into the project directory.
git clone https://github.com/stockphrase/gesso.git
cd gesso
If you plan to contribute changes, fork the repository on GitHub
first and clone your fork instead. You can add the upstream
remote afterward with
git remote add upstream https://github.com/stockphrase/gesso.git.
From inside the gesso directory, install
dependencies. The lockfile pins exact versions, so use a clean
install for reproducibility.
npm install
Equivalent commands for other package managers:
pnpm install, yarn install, or
bun install. The install pulls down Next.js 16,
React 19, the Supabase client libraries, Tailwind CSS v4,
FontAwesome, JSZip, and Marked, among others.
If you see warnings about peer dependencies for React 19, they are expected and safe to ignore. The project is built against React 19.2 and Next.js 16, which are released and stable.
Supabase backs every persistent piece of Gesso: user accounts, courses, assignments, submissions, and uploaded files. You will create one project per Gesso instance.
gesso-dev), and set a strong database password.
Save the password in a password manager.
The service_role key bypasses Row Level
Security and must never be exposed to the browser or
committed to git. It belongs only in server-side code and in
your .env.local file.
Create a file named .env.local in the project root.
This file is git-ignored and stays on your machine. Populate it
with the values you copied from the Supabase API settings page.
NEXT_PUBLIC_SUPABASE_URL=https://your-project-ref.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-public-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
Each variable serves a specific purpose:
| Variable | Used by |
|---|---|
| NEXT_PUBLIC_SUPABASE_URL | The base URL of your Supabase project. Exposed to the browser, used by the client to talk to Supabase. |
| NEXT_PUBLIC_SUPABASE_ANON_KEY | The public-facing API key. Safe to expose; access control is enforced server-side via Row Level Security. |
| SUPABASE_SERVICE_ROLE_KEY | Server-only key for privileged operations such as creating users from the admin panel. Never sent to the browser. |
Variables that begin with NEXT_PUBLIC_ are
inlined into the client bundle by Next.js. Variables without
that prefix are only available in server components, route
handlers, and server actions.
Gesso expects a specific set of tables in your Supabase Postgres database. Open SQL Editor in your Supabase dashboard and create the schema. You can either run a migration file from the repository (if one is provided) or apply the schema by hand.
The core tables are:
auth.users with role (teacher, tutor, student)
and display name.
Each table should have Row Level Security enabled
with policies that scope access by course membership. If the
repository ships a supabase/ directory with
migration files, run them in order; otherwise, refer to the
schema documentation in the project README.
The Supabase CLI makes schema management much easier for
iterative development. Install it with
npm install -g supabase, then use
supabase link to connect your local project to
the cloud database.
Course materials and student submissions are stored in Supabase Storage. In your Supabase dashboard, go to Storage and create the following buckets:
For each bucket, set it to private (not public), and add Storage policies that mirror your database row-level policies. Files should never be reachable by URL without an authenticated request.
Gesso uses Supabase Auth with email-and-password sign-in. Open Authentication → Providers in your Supabase dashboard and confirm that the Email provider is enabled.
Under Authentication → URL Configuration,
set the Site URL to your dev URL (typically
http://localhost:3000) and add additional redirect
URLs for any environments you deploy to, such as your Vercel
preview and production domains.
Customize the confirmation and password-reset email templates under Authentication → Email Templates. The defaults will work, but updating the sender name and visual style is recommended for production.
Gesso only allows registration for email addresses present in
the email_whitelist table. New addresses are added
by an admin from inside the application; users cannot
self-register without being on the list.
With dependencies installed and your environment file in place, start Next.js in development mode.
npm run dev
The app will be available at
http://localhost:3000.
Edits to files under app/ and
components/ hot-reload automatically. The first
page load may take a few seconds while Next.js compiles.
The repository's next.config.mjs includes an
allowedDevOrigins entry for a specific local IP.
If you intend to test from a phone or another machine on your
LAN, edit that file to include your own dev machine's IP, then
restart the dev server.
// next.config.mjs
const nextConfig = {
allowedDevOrigins: ['192.168.1.42'],
};
Gesso has no public sign-up. The first user must be created manually so that they can then add other users from the admin panel.
teacher or
admin:
insert into public.profiles (id, email, display_name, role)
values (
'paste-the-user-id-from-auth-users',
'you@example.com',
'Your Name',
'teacher'
);
You can now sign in at
http://localhost:3000 and create your first
course. From there, additional users can be invited through the
application's UI, which writes to the
email_whitelist table on your behalf.
Vercel is the recommended host for Next.js applications and the path of least resistance for Gesso.
.env.local:
NEXT_PUBLIC_SUPABASE_URL,
NEXT_PUBLIC_SUPABASE_ANON_KEY, and
SUPABASE_SERVICE_ROLE_KEY. Apply them to all
environments (Production, Preview, Development).
Subsequent pushes to your default branch trigger automatic production deploys. Pull requests get their own preview URL, which is handy for review.
Delete node_modules and .next, then
run npm install again. Verify you are on Node 20
or later with node --version.
Re-copy the keys from
Project Settings → API. Keys are scoped
to a single project — using a key from the wrong project will
fail silently or with cryptic errors. Restart the dev server
after editing .env.local; Next.js does not pick up
env changes automatically.
Update the Site URL in Authentication → URL Configuration to your production domain, and add it to the allowed redirect URLs.
Check your Storage bucket policies. The most common cause is a bucket that is private (correct) but missing a SELECT policy for authenticated users who should have access.
If queries return empty arrays when they should return data, inspect your RLS policies in the Supabase dashboard under Authentication → Policies. A missing policy is functionally identical to "no rows match."
Tailwind v4 reads its content paths from the Next.js configuration automatically, but if you add new top-level directories, restart the dev server so the JIT compiler picks them up.
With your instance up and your first admin account created, the day-to-day work happens inside the application. The User Manual covers everything from setting up a course and managing your roster to creating multi-stage assignments and returning marked drafts. Share it with the teachers, students, and tutors on your instance.