Go to file
Ludo afb1a8719b
Build and Deploy / build-and-push (push) Successful in 1m20s Details
fix: month and year repeat
2026-05-04 17:52:17 +02:00
.gitea/workflows Fix CI/CD database migration 2026-05-04 14:34:50 +02:00
apps fix: month and year repeat 2026-05-04 17:52:17 +02:00
packages/shared Initial commit 2026-04-21 17:03:39 +00:00
.env.example Init todo app 2026-04-21 19:10:02 +02:00
.gitignore Initial commit 2026-04-21 17:03:39 +00:00
.npmrc Initial commit 2026-04-21 17:03:39 +00:00
Dockerfile Fix CI/CD database migration 2026-05-04 14:34:50 +02:00
QUICKSTART.md letsgo 2026-05-04 14:26:10 +02:00
README.md Init todo app 2026-04-21 19:10:02 +02:00
SETUP.md letsgo 2026-05-04 14:26:10 +02:00
docker-compose.dev.yml letsgo 2026-05-04 14:26:10 +02:00
docker-compose.prod.yml Initial commit 2026-04-21 17:03:39 +00:00
package.json letsgo 2026-05-04 14:26:10 +02:00
pnpm-lock.yaml Initial commit 2026-04-21 17:03:39 +00:00
pnpm-workspace.yaml Initial commit 2026-04-21 17:03:39 +00:00
turbo.json Initial commit 2026-04-21 17:03:39 +00:00

README.md

ludops-todo

A fullstack monorepo template for quickly scaffolding and deploying apps on your own infrastructure.

Stack: Node.js (Fastify) · React + Vite · PostgreSQL (Drizzle ORM) · Docker · Gitea CI/CD · Nginx Proxy Manager


Creating a new app from this template

1. Fork or copy the repository

In Gitea, use "Fork" or create a new repo and push this one under a new name.
Convention: ludops-<appname> (e.g. ludops-portfolio, ludops-dashboard).

2. Rename everything (global find & replace)

Search the entire repo for todo and replace with your app name (lowercase, no spaces).

File What changes
.env.example APP_NAME and REGISTRY_IMAGE values
Root package.json "name" field
apps/web/src/App.tsx APP_NAME constant (display name)

Tip: In VS Code use Ctrl+Shift+H to find & replace across all files.

3. Set repository variables in Gitea

In your new repo: Settings → Variables → Add variable

Variable Example value
APP_NAME myapp
REGISTRY_IMAGE git.ludops.com/ludops/ludops-myapp

These are injected into the CI runner automatically — no .env file needed on the server for the pipeline.

4. Create the database

Connect to your shared Postgres instance and create the app's database:

sudo docker exec -it ludops-postgres psql -U gitea -c "CREATE DATABASE todo_db;"

The DATABASE_URL in docker-compose.prod.yml automatically uses ${APP_NAME}_db.

5. Push to trigger the CI pipeline

git push

Gitea Actions will:

  1. Build and push the Docker image to the registry
  2. Pull the new image on the server
  3. Run drizzle-kit push to sync the DB schema
  4. Start the container with docker compose up -d

6. Route your domain

In Nginx Proxy Manager, add a new proxy host:

  • Domain: myapp.yourdomain.com
  • Forward hostname: ludops-myapp-app ← matches container_name in docker-compose
  • Forward port: 3000
  • Enable SSL via Let's Encrypt

That's it. Your app is live.


Project structure

.
├── apps/
│   ├── api/                  # Fastify backend
│   │   ├── src/
│   │   │   ├── index.ts      # Server entry point — add your API routes here
│   │   │   └── db/
│   │   │       ├── index.ts  # Drizzle client
│   │   │       ├── schemas.ts
│   │   │       └── schemas/
│   │   │           └── visit-logs.schema.ts  # Keep: tracks page visits
│   │   └── drizzle.config.ts
│   └── web/                  # React + Vite frontend
│       └── src/
│           └── App.tsx       # Start building your UI here
├── packages/
│   └── shared/               # Types shared between api and web
│       └── index.ts
├── docker-compose.prod.yml   # Production container config
├── Dockerfile                # Multi-stage build
├── .env.example              # ← copy to .env on the server
└── .gitea/workflows/
    └── deploy.yml            # CI/CD pipeline

Local development

# Install dependencies
pnpm install

# Start both api and web in watch mode
pnpm dev

You'll need a local Postgres instance and a .env or the DATABASE_URL env var set for the API.


Adding database tables

  1. Create a new schema file in apps/api/src/db/schemas/
  2. Export it from apps/api/src/db/schemas.ts
  3. Push to the server — the CI pipeline runs drizzle-kit push automatically

Adding shared types

Add exports to packages/shared/index.ts. They are available in both api and web as @ludops/shared.


Built-in features kept from the todo

Feature Where
Visit logging (IP + user agent per API request) apps/api/src/db/schemas/visit-logs.schema.ts
/api/status endpoint (health + visit count) apps/api/src/index.ts
SPA fallback routing apps/api/src/index.ts
Static file serving (web dist) apps/api/src/index.ts