Lalabase
티켓·문서·근무시간·고객대화를 한 곳에 모아 KI로 검색, 소프트웨어 기업 고객 프로젝트용, 오픈소스로 자체 서버·독일 클라우드에 배포
PatrolKit은 스키 파출 일정·시간·스키 교환·전체 참여 도구를 한 곳에 통합합니다
PatrolKit streamlines ski patrol administration — duty scheduling, time tracking, ski swap management, and patrol-wide engagement tools in one place.
비즈니스TypeScript · JavaScriptGitHub @PatrolKit온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Ski patrol operations in one app: ski swap check-in, tags, Square sales, PayPal seller payouts, time clock and provisioned devices. Self-host it on AWS.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
PatrolKit runs a ski patrol's organization:
• members and permissions;
• a ski swap: seller check-in, tags and printing, sales through Square, payouts to sellers through PayPal;
• a time clock;
• provisioned devices: check-in iPads, plus print and scanner bridges.
One installation hosts many organizations. Each one connects its own Square and PayPal accounts from inside the app.
This repository holds the API and the web app. This README covers running it locally and deploying it on your own AWS account.README 전문 보기 ↗PatrolKit runs a ski patrol's organization:
One installation hosts many organizations. Each one connects its own Square and PayPal accounts from inside the app.
This repository holds the API and the web app. This README covers running it locally and deploying it on your own AWS account.
┌──────────────── EC2 instance ────────────────┐
app.example.org ──▶ │ Caddy (TLS) ──▶ Node.js app on :4000 (pm2) │ ──▶ RDS MySQL 8
swap.example.org ──▶ │ API + staff and seller web │ ──▶ S3, SES, SNS
└───────────────────────────────────────────────┘
▲
Square and PayPal (per org) ───┘ Square API calls; PayPal payout webhooks
/api/v1, the staff app under /app, and the seller-facing site at the root.Needs:
.npmrc):pnpm config set "//npm.fontawesome.com/:_authToken" <your Font Awesome package token>
Then:
node scripts/dev-setup.mjs
pnpm dev
dev-setup.mjs is safe to rerun. It:
docker-compose.yml);apps/api/.env from .env.example, with fresh JWT keys;Once pnpm dev is running:
/api to the API.GET /readyz checks the app and its database.To sign in, go to /app/auth/login with any seeded user from TESTING.md. Outbound email and SMS are off by default, so the page shows the sign-in code itself.
| Command | What it does |
|---|---|
pnpm dev | API and web in watch mode |
pnpm build · pnpm lint · pnpm test | Build, lint, unit tests (Jest for the API, Vitest for the web) |
pnpm db:migrate · pnpm db:seed | prisma migrate dev, and the seed (permissions, modules, the super admin, demo data in development) |
pnpm release | Deploy to your server (below) |
| Resource | Notes |
|---|---|
| EC2 instance | Amazon Linux 2023. Give it an Elastic IP. Its security group allows 80 and 443 from anywhere, and SSH only from you (or use EC2 Instance Connect). |
| RDS MySQL 8 | A database named, say, patrolkit. Its security group allows 3306 only from the instance's. |
| DNS | A records for your staff and seller hostnames, pointing at the Elastic IP. |
| SES | Verify your sending domain (DKIM). Request production access, or SES will only send to verified addresses. Sign-in links, invites and receipts all go by email. |
| S3 bucket (optional) | Item photos and org logos, read publicly from PHOTO_BASE_URL, so allow public s3:GetObject. Without it, logos live in the database and photos go only to Square. |
| SNS (optional) | Texted sign-in codes, US and Canadian numbers only. Needs an origination number: a toll-free number registered through AWS End User Messaging. Without it, everyone signs in by email. |
| IAM role for the instance | The policy below. |
{
"Version": "2012-10-17",
"Statement": [
{ "Effect": "Allow", "Action": ["ses:SendEmail"], "Resource": "*" },
{ "Effect": "Allow", "Action": ["sns:Publish"], "Resource": "*" },
{ "Effect": "Allow", "Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"], "Resource": "arn:aws:s3:::YOUR-PHOTO-BUCKET/*" }
]
}
If you use DEVICE_IMAGE_BUCKET for bridge firmware, add s3:GetObject on that bucket too.
npm install -g pm2) and Caddy. Run pm2 startup once, so the app comes back after a reboot./home/ec2-user/patrolkit. The release script deploys there./etc/caddy/Caddyfile, then sudo systemctl enable --now caddy. Caddy gets and renews the TLS certificates itself.app.example.org, swap.example.org {
reverse_proxy localhost:4000
}
Create /home/ec2-user/patrolkit/.env from .env.example. These matter in production:
| Variable | Set it to |
|---|---|
NODE_ENV | production |
DATABASE_URL | Your RDS connection string |
JWT_PRIVATE_KEY, JWT_PUBLIC_KEY | A pair from node scripts/gen-keys.mjs |
SQUARE_ENCRYPTION_KEY | openssl rand -hex 32. Keep it: changing it orphans every org's stored Square token. |
APP_URL | https://app.example.org |
SELLER_SITE_URL | https://swap.example.org |
COOKIE_DOMAIN | example.org |
OUTBOUND_NOTIFICATIONS | on. Anything else sends no email or SMS at all. |
MAIL_TRANSPORT, EMAIL_FROM, SES_REGION, AWS_REGION | ses, a verified sender, and your regions |
SEED_SUPERADMIN_EMAIL | Your email: the platform's first super admin |
PHOTO_BUCKET, PHOTO_BASE_URL, AWS_SNS_ORIGINATION_NUMBER | If you set up S3 and SNS |
scripts/release.mjs deploys over SSH. At the top of the script, set SERVER (e.g. [email protected]) and KEY (your SSH key). When you deploy, set VITE_SELLER_SITE_URL to your seller URL, since it's built into the web bundle.
VITE_SELLER_SITE_URL=https://swap.example.org pnpm release
The release:
prisma/ to the server;prisma migrate deploy and the seed;/readyz to answer.It warns if SELLER_SITE_URL is unset or OUTBOUND_NOTIFICATIONS isn't on. Run the same command for every later deploy.
https://app.example.org/app/auth/login with SEED_SUPERADMIN_EMAIL.https://app.example.org/api/v1/webhooks/paypal; register that URL in your PayPal application.pnpm release.pnpm release it. The migrations stay, and the older code ignores what it doesn't know.GET /readyz checks the app and its database. Point an uptime check or a load balancer at it..env, so keep a copy of .env somewhere safe.apps/api/scripts/smoke-*.mjs exercise a feature end to end against a running API. Each one's header says how to run it.
patrolkit-smoke, plus an empty patrolkit-smoke-other that checks one org can't see another's data.PAYOUTS_STUB=1 and the SMOKE_*_FILE variables)._fixture.mjs to the server and run it there with the .env loaded (set -a && . ./.env && set +a).The Bindings lookup says whether a binding model is on its maker's indemnified list. The models themselves are public, and ship in the item taxonomy. Which ones are indemnified, season by season, comes from licensed lists (NSSRA's combined list is for its members only), so this repository doesn't include it.
To use the lookup, get each season's lists yourself and convert them to the CSV format in docs/plan/44_binding_indemnification. Then load them through Platform Admin → Bindings, or with pnpm --filter api db:import-indemnification -- <season folder>. pnpm --filter api db:export-indemnification -- <folder> writes a database's lists back out in the same format, for a private backup. Keep these files out of any public repository.
server/
├─ apps/
│ ├─ api/ # NestJS API; serves the built web app in production
│ │ ├─ prisma/ # schema, migrations, seed, item taxonomy
│ │ └─ scripts/ # smoke scripts and one-off tools
│ └─ web/ # React + Vite: the staff app (/app) and the seller site (/)
├─ docs/plan/ # one folder per feature: its implementation plan and iPad handoff
├─ scripts/ # dev-setup.mjs, release.mjs, gen-keys.mjs
├─ docker-compose.yml # MySQL 8 + Mailpit, for local development
└─ .env.example # every variable the API reads
| Concern | What it uses |
|---|---|
| API | NestJS, TypeScript, Prisma on MySQL 8 |
| Web | React, Vite, TypeScript, Tailwind, TanStack Query, React Router, Font Awesome Pro |
| Sign-in | Passwordless: emailed sign-in links and texted codes; EdDSA JWTs; device tokens for provisioned devices |
| Email, SMS | Amazon SES; Amazon SNS. Locally, Mailpit. |
| Payments | Square (catalog, inventory, sales) and PayPal (payouts), connected per organization |
| Hosting | EC2, Caddy, pm2; RDS; S3 |
MIT, © 2026 ovrEngineered, LLC. Font Awesome Pro is licensed separately, by Fonticons, Inc.