Asset notice: SFX are CC0-licensed audio from Kenney (commercial use OK, no attribution required). See
docs/ASSET_PROVENANCE.mdfor full provenance.
Royal Manager is an RPG-inspired habit tracker focused on consistency and recovery after failure. Habits become daily quests, and each check-in can be recorded as complete, minimum effort, failed, or skipped.
Current RPG features add five fixed hero classes with visible base combat stats at selection time, local avatars, and a private solo adventure whose deterministic combat reacts to habit outcomes. Missing a full day of habits (outside a rest day) now costs the hero HP in the active adventure run. A Settings page lets each user toggle sound effects, motivational messages, and global checklist presentation, customize the accent color/background/panel opacity, and choose a seriousness level (casual through hardcore) that scales enemy HP and attack in adventure combat. Current interface integrates the approved Stitch handoff with real auth, habit, check-in, progress, and settings data. Multiplayer, guilds, a working economy, complex inventory, payments, and advanced AI remain outside current scope.
- Next.js 16, React 19, and TypeScript
- Tailwind CSS
- Supabase Auth and Supabase Postgres
- Drizzle ORM and Drizzle Kit
- Vitest and Playwright
Supabase runs locally in Docker. You do not need to install PostgreSQL on the host machine.
Install:
- Node.js 20.19.0 or newer;
- npm;
- Docker Desktop, Docker Engine, or another Docker-compatible runtime.
When using WSL, enable Docker integration for the project distribution.
Confirm the required tools are available:
node --version
npm --version
docker versiondocker version must display both the Client and Server sections. If only the
Client appears, start Docker before continuing.
From the repository root:
npm installnpm run db:startThis starts the required Supabase services in Docker, including PostgreSQL, Auth, the API, Studio, and Mailpit. The first execution may take longer while Docker downloads the service images.
Check the services and obtain the local API credentials:
npm run db:statusCreate the local environment file:
cp .env.example .env.localOpen .env.local and replace:
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=replace-with-local-publishable-keywith the publishable key shown by npm run db:status.
The default local configuration should look like:
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=<key printed by npm run db:status>
APP_URL=http://127.0.0.1:3000
DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgresDo not commit .env.local. It is ignored by Git. The DATABASE_URL is
server-only and must never be exposed in browser code.
npm run db:resetThis recreates the local database, applies every migration from
supabase/migrations, and loads supabase/seed.sql.
Warning: db:reset deletes existing data in the local Docker database. Do not
run it against an environment containing data you need to preserve.
npm run devOpen http://127.0.0.1:3000.
During local development, open http://127.0.0.1:3000/ui for the canonical
color tokens, shared components, interaction states, sprites, and responsive
patterns. This route deliberately returns 404 in production and is not linked
from application navigation. Product components may use layout utilities, but
visual color decisions belong in app/globals.css semantic tokens.
| Service | Address |
|---|---|
| Application | http://127.0.0.1:3000 |
| Supabase API | http://127.0.0.1:54321 |
| PostgreSQL | 127.0.0.1:54322 |
| Supabase Studio | http://127.0.0.1:54323 |
| Mailpit | http://127.0.0.1:54324 |
Mailpit captures local authentication emails, including password recovery messages. Messages are not sent to real addresses during local development.
Local email confirmation remains disabled by default, so local signup creates
a session immediately. To test the hosted-style confirmation flow through
Mailpit, set enable_confirmations = true under [auth.email] in
supabase/config.toml, restart the local stack, and restore the setting after
testing. The checked-in confirmation template targets /auth/confirm.
Set the server-only APP_URL deployment variable to the canonical application
origin, such as https://app.example.com. Do not include a path, query, hash,
or trailing slash.
In the hosted Supabase dashboard:
-
Set Auth URL Configuration → Site URL to the same canonical origin.
-
Add the exact
${APP_URL}/auth/confirmand${APP_URL}/auth/recoveryURLs to Redirect URLs. -
Replace the Confirm signup email template link with:
<a href="{{ .RedirectTo }}?token_hash={{ .TokenHash }}&type=email"> Confirm email address </a>
-
Disable link tracking in the SMTP provider because rewritten confirmation URLs may break authentication.
-
Copy
supabase/templates/recovery.htmlinto the Reset password email template. Use a production SMTP provider for reliable delivery.
After deployment, create a new account and verify that the email uses the
production domain, /auth/confirm establishes the cookie session, and the user
arrives at /profile/class.
With Supabase and the application running:
- Open the application and create an account. Passwords must be at least 10 characters and include an uppercase letter, a lowercase letter, and a number.
- If an email message is generated, open Mailpit and use its confirmation link.
- Sign in.
- Create a habit with a full goal and a minimum goal.
- Confirm that the habit appears as a quest on today's dashboard.
- Record a complete check-in and confirm that it grants 20 XP.
- Record a minimum check-in for another habit and confirm that it grants 10 XP.
- Record a failed check-in and confirm that a failure reason is required and no XP is removed.
- Confirm that another check-in for the same habit and date is rejected.
- Open the weekly review and check the consistency summary.
Run the database tests while Supabase is active:
npm run db:testRun unit tests and coverage:
npm run test
npm run test:coverageRun static checks and the production build:
npm run lint
npm run typecheck
npm run buildRun the end-to-end suite:
npm run test:e2e:install
npm run test:e2etest:e2e:install installs the project-compatible Chromium build and its Linux
system libraries. Run it once after installing dependencies and again after
Playwright version upgrades. On WSL/Linux, the command uses sudo and may ask
for the distribution user's password.
Weekly-review E2E fixtures need a server-only Supabase service role. Against the
local Docker stack, tests discover it from supabase status --output json.
Hosted or CI runs must set SUPABASE_SERVICE_ROLE_KEY explicitly. Never prefix
this variable with NEXT_PUBLIC or expose it to browser code.
The data architecture has two distinct responsibilities:
db/schema.tsis the editable source of truth for tables, enums, indexes, constraints, and Row Level Security policies.supabase/migrationscontains the versioned SQL that Supabase applies.
After changing db/schema.ts, generate and verify the migration:
npm run db:generate
npm run db:check
npm run db:resetDrizzle generates the SQL migrations. Generated SQL must be reviewed and committed, but should not be edited manually.
PostgreSQL features that Drizzle cannot model, such as specialized functions, triggers, grants, or RPCs, belong in a custom migration:
npm run db:custom -- --name=descriptive_nameThe application accesses data through Supabase so authenticated requests remain protected by Row Level Security. PostgreSQL is the source of truth.
# Start Supabase containers
npm run db:start
# Inspect service status and local credentials
npm run db:status
# Start Next.js
npm run dev
# Stop Supabase containers
npm run db:stopdb:stop stops the services without resetting the local database.
If npm run db:start cannot connect to Docker:
- start Docker Desktop or the Docker daemon;
- verify
docker versionshows the Server section; - under WSL, verify Docker integration is enabled;
- run
npm run db:startagain.
Stop another Royal Manager stack:
npm run db:stopIf the conflict remains, identify the application using ports 3000,
54321, 54322, 54323, or 54324, then stop it or update the corresponding
local configuration.
Run:
npm run db:statusConfirm that .env.local uses the displayed API URL and publishable key, then
restart npm run dev. Next.js reads environment variables when the development
server starts.
For disposable local data, recreate the database:
npm run db:resetRemember that this removes current local records.
If you enjoyed the project, you can leave a small donation on Ko-fi — no strings attached.
The source code in this repository is licensed under MIT.
Some assets (AI-generated character sprites, sound effects, and other
media under public/assets/ and assets/source/) are covered by separate
terms — see Asset provenance for the current
status of each.