Admin

Building a custom admin project

Scaffold your own project admin on top of the base layer in about ten minutes.

Building a custom admin project

You've got the base layer running (see Getting started). Now you want a project admin with your brand, your modules, and your backend — the way redelay/admin sits on top of redelay/js-admin-nuxt4.

How should your project depend on the base layer? The scaffold below uses a filesystem extends to a sibling clone (Mode A) — simplest for hacking inside the monorepo. For a real project, prefer the versioned dependency (@redelay/js-admin pinned to a tag, with a local dev override): a fresh clone or CI builds without the base-layer tree beside it, and the version is pinned. See Consuming the base layer (versioned) — the canonical approach for new projects.

1. Scaffold

Sit the project admin as a sibling of the base layer in the same monorepo:

text
your-monorepo/
├── js-admin-nuxt4/    # clone of redelay/js-admin-nuxt4
└── your-admin/        # this one
    ├── package.json
    ├── nuxt.config.ts
    ├── app.config.ts
    ├── tailwind.config.ts
    ├── assets/css/tailwind.css
    └── modules/

package.json

json
{
  "name": "your-admin",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "nuxt dev --port 3001",
    "build": "nuxt build",
    "postinstall": "nuxt prepare"
  },
  "dependencies": {
    "@iconify-json/heroicons": "^1.2.3",
    "@iconify-json/lucide": "^1.2.73",
    "@nuxt/ui": "^4.1.0",
    "@pinia/nuxt": "^0.11.3",
    "nuxt": "^4.2.1",
    "nuxt-open-fetch": "^0.13.6",
    "pinia": "^3.0.4"
  }
}

nuxt.config.ts

Copy the skeleton from layered architecture. Point extends at your sibling clone of js-admin-nuxt4.

assets/css/tailwind.css

The base layer's css: ['~/assets/css/tailwind.css'] resolves ~ to this project at runtime. That means you MUST provide this file. Don't @import the base's stylesheet; duplicate its imports and add @source globs pointing at both trees:

css
@import "tailwindcss";
@import "@nuxt/ui";

/* Project-owned sources */
@source "../../components/**/*";
@source "../../layouts/**/*";
@source "../../pages/**/*";
@source "../../modules/**/*";

/* Inherited base-layer sources */
@source "../../../js-admin-nuxt4/components/**/*";
@source "../../../js-admin-nuxt4/layouts/**/*";
@source "../../../js-admin-nuxt4/pages/**/*";
@source "../../../js-admin-nuxt4/modules/**/*";

/* Brand colour tokens */
:root {
  --tblr-primary: #8B5CF6;  /* your brand colour here */
}

tailwind.config.ts (empty stub)

Required by @nuxt/ui v4 for Tailwind bootstrapping; @source directives in the CSS file drive the actual scan:

ts
export default { content: [], theme: { extend: {} } }

app.config.ts — brand theme

ts
export default defineAppConfig({
  ui: {
    colors: {
      primary: 'violet',   // or indigo, cyan, emerald, …
      neutral: 'slate',
    },
  },
})

The primary colour feeds every color="primary" button/badge/link. Nuxt UI ships 22 named palettes.

The base layer's Dockerfile.admin is a plain node:20-alpine + pnpm; reuse it. The compose service wires the two layer paths as separate bind mounts so hot-reload works across both:

yaml
# infra/docker-compose.yml
admin:
  build:
    context: ..
    dockerfile: infra/dockerfiles/Dockerfile.admin
  working_dir: /app/your-admin
  command: sh -c "test -d node_modules/nuxt || pnpm install --no-frozen-lockfile; pnpm dev --host 0.0.0.0 --port 3001"
  ports: ["3001:3001"]
  environment:
    NUXT_API_URL: http://localhost:8001
    NUXT_API_INTERNAL_URL: http://admin-api:8001
  volumes:
    - ../your-admin:/app/your-admin
    - ../js-admin-nuxt4:/app/js-admin-nuxt4
    - your-admin-node-modules:/app/your-admin/node_modules
  depends_on:
    - admin-api

Do not mount a named volume for js-admin-nuxt4/node_modules — it forces a second install and creates the pnpm duplicate-instance problem. The base layer is source-only at runtime.

3. First login

Start the stack and navigate to http://localhost:3001. The base layer's /login page appears — it's inherited through the layer. Sign in with your backend's credentials.

4. Add your first module

See Building admin modules.