This guide explains how to set up the local development environment, run the project, and stop everything at the end of the day.
Recommended setup for Windows contributors: Windows + WSL2 (Ubuntu) + Docker Desktop + VS Code.
We keep the repository inside the WSL filesystem and run the backend/web/tooling from Linux. This gives a smoother developer experience than mixing native Windows tooling with Linux-oriented project scripts.
This project replaces the most painful parts of the current wiki-based Maker Lab workflow while preserving the existing installed base.
The core goals are:
- integrate with Snipe-IT as the authoritative inventory system,
- support the full requisition lifecycle: request → approve/reject → assign → return,
- allow multiple requisitions during the same project lifecycle,
- replace Markdown-based project creation with structured forms,
- integrate authentication with the university SSO / universal user,
- support both web and mobile clients.
.
├── apps/
│ ├── web/ # Next.js web app
│ ├── mobile/ # Expo / React Native mobile app
│ ├── api/ # FastAPI backend
│ └── migration/ # legacy wiki import / migration scripts
├── infra/
│ ├── docker/ # Docker Compose setup
│ ├── db/ # Database initialization scripts
│ ├── nginx/ # Nginx configuration
│ └── snipeit/ # Snipe-IT environment config
├── docs/ # Documentation
└── README.md
- Next.js + TypeScript for the web application
- Tailwind CSS for styling
- pnpm for JavaScript/TypeScript package management
- Turborepo for monorepo task orchestration
- Expo + React Native for Android and iOS mobile development
- Android is developed locally on Windows using Android Studio
- iOS cannot be simulated locally on Windows; use a physical device or cloud builds when needed
- FastAPI for the backend API
- Python 3.12 with pip and venv
- SQLModel / SQLAlchemy for ORM / DB access
- Pydantic for validation and schemas
- PostgreSQL for application data
- Docker Desktop + Docker Compose for local services
- Nginx later for reverse proxying in deployment environments
- Snipe-IT as the inventory authority
- University SSO as the preferred authentication path
- Legacy Maker Lab Wiki as a migration source
- WSL2 Ubuntu as the main development environment on Windows
- VS Code Remote - WSL for editing the codebase
- GitHub for code review and collaboration
Install these tools directly on Windows:
- WSL2 with Ubuntu
- Docker Desktop
- VS Code
- Android Studio
Inside WSL Ubuntu we install and use:
- Git
- Node.js LTS
- pnpm
- Python 3.12, pip, and venv
- project dependencies
- backend, web, and migration commands
Open PowerShell as Administrator and run:
wsl --install -d Ubuntu
wsl --update
wsl -l -vRestart the computer if Windows asks for it.
When Ubuntu starts for the first time, create your Linux username and password.
Install Docker Desktop and then enable:
- Use WSL 2 based engine
- WSL integration for your Ubuntu distro
After that, open Ubuntu and verify Docker works from WSL:
docker version
docker compose versionInstall:
- Visual Studio Code
- Remote - WSL extension
Later, when you are inside the repo in Ubuntu, you will open it with:
code .Install Android Studio on Windows and let the setup wizard install:
- Android SDK
- Android SDK Platform-Tools
- Android Emulator
- at least one recent Android system image
For daily work, Android Studio stays on Windows, but the repository remains inside WSL.
On Windows, Android development is local. For iOS, use a physical device or cloud build flow.
Open Ubuntu and run:
sudo apt update && sudo apt upgrade -y
sudo apt install -y \
build-essential \
curl \
wget \
git \
unzip \
zip \
jq \
ca-certificates \
gnupg \
lsb-release \
file \
xz-utils \
python3 \
python3-pip \
python3-venvVerify Python and pip:
python3 --version
pip3 --versionWe use Node only inside WSL for the monorepo tooling.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
source ~/.bashrc
nvm install --lts
nvm use --lts
nvm alias default 'lts/*'
node -v
npm -vnpm install --global corepack@latest
corepack enable
corepack prepare pnpm@latest-10 --activate
pnpm -vKeep the repository in the Linux filesystem, not under C:\.
mkdir -p ~/dev
cd ~/dev
git clone <YOUR_REPOSITORY_URL> deti-maker-lab
cd deti-maker-labOpen it in VS Code:
code .Create the local environment files from the examples provided in the repo.
Typical files:
infra/db/.env.postgres
infra/snipeit/.env.snipeit
apps/api/.env
apps/migration/.env
To initialize your PostgreSQL environment file, copy the example:
cp infra/db/.env.postgres.example infra/db/.env.postgresFor the backend API, copy the example:
cp apps/api/.env.example apps/api/.envEnsure the values in .env match your local setup. For example, apps/api/.env might look like:
DATABASE_URL=postgresql+psycopg://makerlab_app:CHANGE_ME_STRONG_PASSWORD@localhost:5432/makerlab
SNIPEIT_BASE_URL=http://snipeit
SNIPEIT_API_TOKEN=YOUR_SNIPEIT_API_TOKEN
SSO_CALLBACK_URL=https://deti-makerlab.ua.pt/auth/auth
DML_AUTH_KEY=your_client_key_here
DML_AUTH_SECRET=your_client_secret_here
# JWT
JWT_SECRET_KEY=supersecretkey
JWT_ALGORITHM=HS256
JWT_EXPIRE_MINUTES=60
# Comma-separated list of university emails that should be granted the lab_technician role
LAB_TECHNICIANS=lab.tech@ua.pt,another.labtech@ua.ptAt the beginning of development, SSO and Snipe-IT values may be left empty if the repo contains mock adapters or local-only configuration.
From the repo root:
pnpm installFrom the backend directory, you need to create the venv folder (because the package.json dev script expects it there):
cd apps/api
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
cd ../..If you are working on the migration script, you can do the same there:
cd apps/migration
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cd ../..The API's
devscript usesvenv/bin/uvicorn, so you do not explicitly need to activate the virtual environment to run it via Turborepo, but you must create thevenvdirectory.
The recommended local infrastructure is at least:
- PostgreSQL
- Snipe-IT (optional but often used)
- Nginx (optional, used for full routing simulation)
From the repo root:
docker compose -f infra/docker/docker-compose.yml up -dCheck running containers:
docker psOnce the containers are running, bootstrap Snipe-IT and generate/inject the API token automatically by running:
./infra/docker/bootstrap-snipeit.shThe database schema is automatically applied by schema.sql found in infra/db/init/ when the Postgres container starts for the first time. To load the seed test data, run the seed command (see Section 10).
For quick local development, run the services separately or use Turbo.
Terminal 1 — web app
cd ~/dev/deti-maker-lab
pnpm --filter web devExpected URL: http://localhost:3000
Terminal 2 — FastAPI backend
cd ~/dev/deti-maker-lab
pnpm --filter api devExpected URL: http://localhost:8000
Swagger docs: http://localhost:8000/docs
Terminal 3 — mobile app
cd ~/dev/deti-maker-lab
pnpm --filter mobile devThen press a for Android emulator, or scan the QR code in Expo Go.
(Note: Mobile defaults to port 3000. If web is also running, web might shift to port 3001 automatically).
To test the complete system as it runs in production with nginx reverse-proxying:
- Start Docker containers:
docker compose -f infra/docker/docker-compose.yml up -d- Add domain names to your Windows hosts file (see troubleshooting section):
127.0.0.1 deti-makerlab.ua.pt
- Access via:
https://deti-makerlab.ua.pt/new— main sitehttps://deti-makerlab.ua.pt/new/snipe-it— Snipe-IT inventory
You'll see a certificate warning for self-signed SSL — click "Advanced" and continue anyway.
Alternatively, from the repo root, run:
pnpm devThis starts both the API and the mobile app in parallel (as configured in turbo.json).
Database tables are defined in infra/db/init/schema.sql, which is automatically applied when the Postgres container starts for the first time.
If you want to populate the database with sample test data (seeds), run the following command from the repository root:
docker compose -f infra/docker/docker-compose.yml exec -T postgres psql -U makerlab -d makerlab < infra/db/init/seed.sqlIf you ever need to reset the database entirely (both schema and data), you can remove the volume and restart Docker:
docker compose -f infra/docker/docker-compose.yml down -v
docker compose -f infra/docker/docker-compose.yml up -d(Warning: this will delete all local data, and you will need to re-run the seed command if you want the sample data).
This is the recommended day-to-day workflow for contributors using Windows.
- Start Docker Desktop on Windows.
- Open Windows Terminal or PowerShell.
- Enter Ubuntu:
wsl- Go to the project:
cd ~/dev/deti-maker-lab- Open VS Code in WSL:
code .- Start infrastructure:
docker compose -f infra/docker/docker-compose.yml up -d postgres- Refresh dependencies only when needed:
pnpm install
cd apps/api && source venv/bin/activate && pip install -r requirements.txt && cd ../..- Start the apps you need:
pnpm --filter web dev
pnpm --filter api dev
pnpm --filter mobile dev- Use web + api for most feature work.
- Run mobile only when you are actively testing the mobile app.
- Run migration scripts only when working on legacy import tasks.
- Keep Docker containers limited to what is necessary.
This section is important. At the end of the day, shut down local processes so they do not keep using CPU, RAM, battery, or disk resources.
In each terminal running a dev server, press:
Ctrl + C
Do this for:
pnpm --filter web devpnpm --filter api devpnpm --filter mobile dev
If you launched the Android emulator, close it from Android Studio or the emulator window.
From the repo root:
docker compose -f infra/docker/docker-compose.yml downThis stops and removes the containers but keeps the Docker volumes, so your local database data is preserved.
Do not use
down -vunless you intentionally want to delete local database data.
If you only want a temporary pause and keep containers ready for a quick restart, you can use:
docker compose -f infra/docker/docker-compose.yml stopAfter all WSL terminals are closed, you can shut down WSL from Windows PowerShell:
wsl --shutdownThis frees memory used by the Linux VM.
If you are completely done for the day, you can also quit Docker Desktop from the Windows tray icon.
This is useful when you are not doing any more container work.
pnpm install
pnpm --filter web dev
pnpm --filter api dev
pnpm --filter mobile devcd apps/api
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cd ../..
pnpm --filter api devdocker compose -f infra/docker/docker-compose.yml up -d
docker compose -f infra/docker/docker-compose.yml stop
docker compose -f infra/docker/docker-compose.yml down
docker pswsl
wsl -l -v
wsl --shutdownTo keep the environment predictable for everyone:
- always develop from WSL, not from
C:\... - commit lockfiles:
pnpm-lock.yaml - do not commit
.envfiles with secrets - do not commit
venv/ - avoid changing tool versions casually
- when upgrading Node / pnpm / Python / Expo / FastAPI, announce it in the team chat and update this document
- stop Docker containers and dev servers after work
If you're trying to access https://deti-makerlab.ua.pt/new or https://deti-makerlab.ua.pt/new/snipe-it but get "This site can't be reached", you need to add the domain names to your Windows hosts file.
Why? The containers are running in Docker Desktop (which uses WSL2), and nginx is configured to serve the site via domain names with HTTPS. Your Windows browser needs to know where to find these domains.
Solution:
- Open PowerShell as Administrator (right-click → "Run as administrator")
- Run:
Add-Content -Path "C:\Windows\System32\drivers\etc\hosts" -Value "`n127.0.0.1 deti-makerlab.ua.pt`" -Force- Flush the DNS cache:
ipconfig /flushdns- Close and reopen your browser, then try:
https://deti-makerlab.ua.pt/newhttps://deti-makerlab.ua.pt/new/snipe-it
You'll see a certificate warning (self-signed SSL) — click "Advanced" and continue anyway.
Note: If you're doing local development only (not testing the full nginx setup), keep using http://localhost:3000 and http://localhost:8000 instead.
- Check that Docker Desktop is installed
- Check that WSL integration is enabled for Ubuntu
- Restart Docker Desktop
- Run:
npm install --global corepack@latest
corepack enable
corepack prepare pnpm@latest-10 --activate- If the repo pins pnpm in
package.json, make sure the pinned version is a full semver version, not only a major version.
- Run:
cd apps/api
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt- The virtual environment is probably not initialized or the API filter is not picking it up. Ensure
venvis in theapps/apifolder since thedevscript uses./venv/bin/uvicorn.
- Open Android Studio first
- Start an emulator from the Device Manager
- Then run the mobile app again
- Check what is running on:
3000for web and mobile8000for API5432for PostgreSQL
- Stop the conflicting process or change the local port
This guide is the baseline for local development. As the repository evolves, update this file whenever:
- a new service is added,
- a port changes,
- the local Docker stack changes,
- the FastAPI startup command changes,
- the mobile workflow changes,
- the SSO or Snipe-IT configuration becomes mandatory for local development.