generated from ludops/ludops-skeleton
142 lines
4.1 KiB
Markdown
142 lines
4.1 KiB
Markdown
# 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:
|
|
|
|
```sh
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
# Install dependencies
|
|
pnpm install
|
|
|
|
# Start both api and web in watch mode
|
|
pnpm dev
|
|
```
|
|
|
|
- Web: http://localhost:5173
|
|
- API: http://localhost:3000
|
|
|
|
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` |
|