TreeMap
무료 오픈소스 디스크 사용량 시각화 도구로, 사각형 트리맵·중복 파일 탐색·디스크 가득 예측·정리 시 파일을 휴지통으로만 이동한다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Pilot logbook for real and sim flying: AI quick log, SimBrief and flight plan PDF import, currency and maintenance tracking, and instructor sign-off. Django REST + Next.js.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A pilot logbook for real and simulator flying, with AI quick entry and instructor sign-off.
Live demo · Django REST API + Next.js · GPL-3.0
AirFleet keeps a pilot's flights, aircraft and training records in one place. Log a flight by
hand, describe it in plain words and let AI fill in the form, pull it from SimBrief or a flight
plan PDF, or import a ForeFlight logbook. AirFleet then works out totals, currency, maintenance
due dates and route maps, and lets an instructor sign lessons and give endorsements.README 전문 보기 ↗A pilot logbook for real and simulator flying, with AI quick entry and instructor sign-off.
Live demo · Django REST API + Next.js · GPL-3.0
AirFleet keeps a pilot's flights, aircraft and training records in one place. Log a flight by hand, describe it in plain words and let AI fill in the form, pull it from SimBrief or a flight plan PDF, or import a ForeFlight logbook. AirFleet then works out totals, currency, maintenance due dates and route maps, and lets an instructor sign lessons and give endorsements.
AirFleet is a personal project, not a certified logbook. It isn't meant to replace an official logbook or satisfy regulatory recordkeeping requirements.
(FPL-...) message). Drafts stay out of totals, currency, rankings and maintenance until you add
the actual times and untick Draft. The PDF itself isn't stored./privacy notice of what is stored and which services see it, and account
deletion from the profile page that erases the pilot's flights, aircraft, photos, likes, notifications
and comments (a comment with replies stays as Comment deleted).backend/)DATABASE_URLdjangorestframework-simplejwt), plus Google sign-inpypdf for flight plan PDFs, django-storages for S3-compatible photo storageThe backend is organized around Django apps:
AirFleet_api/ — settings, URLs, throttle scopesflights/ — flights, aircraft, insights, imports/exports, airport data, quick log, weather and
SimBrief lookups, flight plan parsingusers/ — accounts, profiles, password reset, public pilot pagesinstruction/ — instructor links, lesson signatures, endorsements and student progressgroups/ — pilot groups (airlines, operators, flight schools, alliances, communities) and their membershipsfrontend/)src/utils/api.tsrender.yaml)The client signs in with a password (or Google, whose ID token the backend exchanges for its own
tokens) and gets an access/refresh token pair. The frontend stores them in cookies, sends the access
token on each request, and refreshes it once on a 401 before sending the user back to /login.
AUTH_USER_MODEL is users.CustomUser; token lifetimes, throttles and CORS origins are set in
backend/AirFleet_api/settings.py.
POST /api/flights/quick-log/ takes text (a pilot's own description of a flight, up to 1,000
characters) and now (their local time, so "this morning" resolves) and returns form fields plus
warnings; nothing is saved. A language model reads the text and answers in JSON, which
flights/quick_log.py checks before it reaches the form: airports must be in the bundled database,
hours must be 0–24, arrival is worked out from departure plus total time, and disagreements are
flagged. The prompt also lists the pilot's fleet so "the 172" can resolve to a registration.
Providers are any OpenAI-compatible API, tried in order: Gemini (GEMINI_API_KEY) then Groq
(GROQ_API_KEY). Both have free tiers, so the second takes over when the first is down or out of
its daily quota. GET /api/flights/quick-log/ returns {"enabled": ...}, and the form hides quick
log when neither key is set. Requests are limited per user (QUICK_LOG_RATE, default 30/hour).
POST /api/stats/ask/ takes question (up to 300 characters) and now, and answers with the
filters it used plus one total from the stats page or one currency card. The model's only job is to
turn the question into those filters — which stats total, a date range, an aircraft from the pilot's
own fleet, an airport, whether simulator sessions count, or a currency check — so no wording or
number from the model reaches the pilot. Filters it can't use are dropped with a warning (an aircraft
that isn't in the fleet, an unknown airport, dates that don't read or run backwards), a currency
question is answered as of today across all aircraft, and a question that fits none of the filters
gets a 422 with examples rather than an approximation. Drafts stay out, as everywhere else. Asking
shares the quick log providers and rate limit, and the panel is hidden when quick log is.
GET /api/insights/ returns findings computed from the logbook in flights/patterns.py, each with
the numbers behind it. POST /api/insights/themes/ sends the notes of the pilot's last 40 logged
flights to the quick log providers and returns recurring themes. A theme is kept only if it cites at
least two of the flights the model was shown; it shares quick log's rate limit.
GET /api/flights/<id>/review/ checks a draft flight in flights/plan_review.py. This part
deliberately uses no language model. Every suggestion comes from arithmetic the pilot can check: their
average block speed in the aircraft (or type), their longest leg, the airports they've logged,
currency on the day of the flight, the aircraft's maintenance, the sun's position at the destination
for night arrivals, and the current METAR when the flight leaves within three hours. It doesn't
replace a briefing: forecasts, NOTAMs, fuel and performance are left to the pilot.
InstructorLink joins a student and an instructor. Either pilot invites the other by username or
email (POST /api/instruction/links/); the invitee gets an email and accepts on the Instruction page.
Either side can decline or unlink. While linked, the instructor sees the student's flights that have
dual received time, limited to the fields they would sign (GET /api/instruction/links/<id>/flights/).
Signing (POST /api/instruction/flights/<id>/sign/) needs an active link, dual received time on the
flight, a certificate number on the instructor's profile that hasn't expired, a ticked attestation and
the instructor's password. Each Signature stores:
The flight API recomputes the hash from the current entry. If the student edits a signed field, the signature shows as invalidated, with the fields that changed, until the instructor signs again (or the values are put back). Notes, photos and weather aren't signed and can change freely. A signature stays on the student's flight if the instructor unlinks or deletes their account.
The instructor who signed can withdraw a signature (POST /api/instruction/signatures/<id>/withdraw/)
with an optional reason and their password, even after unlinking. Nothing is deleted: the signature
is marked withdrawn, the student sees when and why, and the lesson can be signed again.
Endorsements (Endorsement) are given by a linked instructor to their student
(POST /api/instruction/links/<id>/endorsements/): pre-solo, solo, solo cross-country, knowledge test,
practical test, flight review, IPC, complex, high-performance, tailwheel, or a custom one. Each kind
has a plain-language starting draft (instruction/endorsements.py) that the instructor edits before
signing; it is not the wording of AC 61-65. An endorsement records the same instructor details as a
signature, the date given, and an expiry where the kind has one (solo: 90 days; practical test: 2
calendar months; flight review: 24 calendar months). Students see theirs on the Instruction page, the
instructor sees in full the ones they gave, and the instructor can withdraw one the same way as a signature.
Student progress (GET /api/instruction/dashboard/) shows an instructor every student on an
active link, measured against the private pilot minimums of 14 CFR 61.109(a) for airplane
single-engine land. The rows are a hard-coded table of one rule each in
instruction/requirements.py — total, dual, dual cross-country, dual night, night landings with an
instructor, dual simulated instrument, dual in the last two calendar months, solo and solo
cross-country — summed over the student's logged flights, simulator sessions left out, with the
signed share of the dual shown alongside it. The server writes the "missing" sentences, so the page
holds no rules of its own. Three requirements a logbook can't express (the 100 nm night
cross-country, the 150 nm solo cross-country, three solo full-stop landings at a towered airport)
are listed as things to check in the logbook rather than counted, and the six endorsements the
certificate needs are shown as current, expired or missing from any instructor, not only the one
looking.
The totals are a deliberate privacy trade, set out on /privacy: they cover all of the student's
logged flights, including solo and other time not flown with this instructor, but the flights behind
them stay hidden. The page names its approximations — solo is PIC time on a flight with no dual
received, dual night and dual simulated instrument count the smaller of that time and the flight's
dual, and aircraft class isn't filtered — and it is a guide to what to fly next, not a checkride
sign-off.
The CSV export adds instructor_name, instructor_certificate, instructor_signed_at and
signature_status (valid, invalidated or withdrawn) from each flight's latest signature. They are
ignored on import: a signature can't be imported.
AirFleet calls this instructor-verified. It is not presented as a signature that satisfies 14 CFR 61.51(h) or the FAA's guidance on electronic signatures (AC 120-78A), and the hash is change detection, not tamper-proofing against someone with database access.
.github/workflows/ # backend and frontend CI
backend/
AirFleet_api/
flights/
groups/
instruction/
users/
flights/data/airports.csv.gz
Dockerfile
manage.py
launcher.sh # container entrypoint: migrate, collectstatic, gunicorn
requirements.txt
frontend/
e2e/ # Playwright end-to-end tests
src/app/ # pages (App Router)
src/components/
src/utils/ # API client and formatting helpers
docker-compose.yml
render.yaml
neon.ts
From the project root:
docker compose up --build
This starts:
80003000Requires Python 3.12+ (Django 6).
cd backend
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python manage.py migrate
python manage.py runserver 0.0.0.0:8000
python manage.py test # run the API test suite
flights/data/airports.csv.gz is generated from
OurAirports: every open
airport and seaplane base with a 4-character ICAO-style code.
Requires Node.js 20.9+ (Next.js 16).
cd frontend
npm install
npm run dev
Checks: npm run lint, npm run typecheck, npm run build.
Playwright drives the production build against the real API. With Postgres running and
DATABASE_URL/SECRET_KEY set:
cd frontend
npx playwright install chromium # or set PLAYWRIGHT_CHROMIUM_PATH to an existing Chromium
npm run build
PYTHON=../backend/.venv/bin/python npm run test:e2e # starts Django and Next itself
CI runs the backend suite (.github/workflows/backend.yml) and lint, typecheck, build and
the end-to-end tests (.github/workflows/frontend.yml).
The application relies on values such as:
SECRET_KEY=your-secret
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/airfleet
NEXTAUTH_SECRET=your-nextauth-secret
NEXTAUTH_URL=http://localhost:3000
Optional:
# Backend
FRONTEND_URL=https://airfleet.vercel.app # where password-reset links point
EMAIL_HOST=smtp.example.com # without it, reset emails are printed to the log
EMAIL_PORT=587
EMAIL_HOST_USER=...
EMAIL_HOST_PASSWORD=...
DEFAULT_FROM_EMAIL="AirFleet <[email protected]>"
GOOGLE_CLIENT_ID=... # enables Google sign-in (same ID as the frontend)
GEMINI_API_KEY=... # quick log, note themes and asking, from aistudio.google.com (free tier)
GROQ_API_KEY=... # quick log fallback, from console.groq.com (free tier)
GEMINI_MODEL=gemini-flash-lite-latest # optional overrides of the quick log models
GROQ_MODEL=openai/gpt-oss-20b
QUICK_LOG_RATE=30/hour # quick log limit per user
# Frontend
GOOGLE_CLIENT_ID=... # with GOOGLE_CLIENT_SECRET, shows "Continue with Google"
GOOGLE_CLIENT_SECRET=...
API_URL=... # API origin for server-side calls, if it differs from NEXT_PUBLIC_API_URL
NEXT_PUBLIC_ENABLE_DEBUG=true # turns on the /debug connection page
[email protected] # shown on /privacy for data requests, and on a group page for making it official
NEXT_PUBLIC_ARCGIS_API_KEY=... # optional: high-res Esri satellite view (free tier, 2M tiles/month); without it satellite uses NASA Blue Marble
NEXT_PUBLIC_CARTO_API_KEY=... # dark basemap tiles (free key from carto.com/basemaps/apikey); without it the map falls back to OpenStreetMap
For Google sign-in, create an OAuth client (Web application) in Google Cloud and add
<frontend URL>/api/auth/callback/google as an authorized redirect URI.
The demo runs entirely on free tiers: Neon (Postgres), Render (Django API) and Vercel (Next.js).
?sslmode=require).render.yaml
and asks for DATABASE_URL (the Neon string) and the optional quick log keys GEMINI_API_KEY
and GROQ_API_KEY; SECRET_KEY is generated.
Migrations run automatically on every start. The free instance sleeps after 15 minutes
idle, so the first request after a pause takes about a minute.frontend and Node 22, and set
NEXT_PUBLIC_API_URL to the Render URL (e.g. https://airfleet-api.onrender.com),
plus NEXTAUTH_SECRET and NEXTAUTH_URL. The backend accepts requests from
airfleet.vercel.app, airfleet-project.vercel.app and their preview URLs; add other
domains to CORS_ALLOWED_ORIGINS in backend/AirFleet_api/settings.py.To reset the demo data, use Neon's branch reset (or drop and recreate the database); the next Render start re-creates the schema.
Flight photos go to the private photos bucket in Neon Object Storage (declared in
neon.ts). Set AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_ENDPOINT_URL_S3 and
AWS_REGION on Render (neon link writes them to .env.local); the API then returns
short-lived signed photo URLs. Without them, photos fall back to local disk.
Typical usage looks like this: