276 lines
14 KiB
Markdown
276 lines
14 KiB
Markdown
# Tabulae Aeriae — Project Scope Statement
|
||
|
||
**Version:** 1.0
|
||
**Date:** March 29, 2026
|
||
**License:** AGPL-3.0 (pending final confirmation)
|
||
**Repository:** Forgejo (self-hosted)
|
||
|
||
---
|
||
|
||
## 1. Project Overview
|
||
|
||
Tabulae Aeriae is a self-hostable, web-based pilot logbook system designed to provide FAA-compliant flight record keeping, robust reporting, currency tracking, and data visualization. The system targets two tiers of users: a free open-source tier for non-commercial pilots (Part 91, recreational, student) and a paid professional tier for commercial operators (Part 135, Part 121).
|
||
|
||
The project is motivated by the absence of a quality open-source, self-hostable pilot logbook that provides genuine FAA regulatory compliance, one-click report generation for common FAA forms, and a data-driven currency tracking engine. Existing open-source projects (web-logbook, jetlog, flightlog) are either EASA-focused, passenger flight trackers, or lack the reporting depth that professional pilots require.
|
||
|
||
---
|
||
|
||
## 2. Objectives
|
||
|
||
### Primary Objectives (v1)
|
||
|
||
- Provide a complete FAA-compliant logbook meeting 14 CFR 61.51 requirements
|
||
- Generate FAA Form 8710-1 Section III data with one-click reporting
|
||
- Generate FAA medical (8500-8) total time and last-6-months data with one-click reporting
|
||
- Track pilot currency under 14 CFR 61.57 (day, night, instrument, flight review) with real-time status display
|
||
- Visualize flight data through maps (route visualization) and charts (time breakdowns, trends)
|
||
- Support self-hosted deployment on low-resource hardware (Raspberry Pi / Docker Swarm)
|
||
- Maintain a complete audit trail of all logbook changes
|
||
|
||
### Secondary Objectives (v1)
|
||
|
||
- Provide a skeleton framework for future EASA (FCL.050) compliance
|
||
- Support configurable, user-saveable custom reports for insurance, company, and personal use
|
||
- Support CSV import with a pluggable adapter architecture for future format support
|
||
- Track pilot qualifications, certificates, ratings, endorsements, and currency events in a unified table
|
||
- Track medical certificate status with expiry countdowns
|
||
|
||
### Deferred Objectives (Paid Tier / Future Releases)
|
||
|
||
- PF/PNF (Pilot Flying / Pilot Not Flying) as first-class fields
|
||
- IOE (Initial Operating Experience) tracking
|
||
- High minimums captain status tracking
|
||
- Duty/rest tracking (Part 117, Part 135 Subpart F)
|
||
- Augmented operations crew management
|
||
- Operator-specific currency rule overrides (61.57(e) exceptions)
|
||
- GPS track import (KML/GPX) for precise route/night calculation
|
||
- SQLite backend option for simplified single-user deployment
|
||
- Full EASA compliance (FCL.050 fields, EASA PDF export formats)
|
||
- OAuth2/OIDC/LDAP authentication providers
|
||
|
||
---
|
||
|
||
## 3. Technical Architecture
|
||
|
||
### Stack
|
||
|
||
| Layer | Technology | Rationale |
|
||
|-------|-----------|-----------|
|
||
| Backend | Go with Chi router | Low memory footprint, single binary, fast compilation, strong stdlib |
|
||
| Database | PostgreSQL 16 | Robust, supports JSONB for flexible fields, trigger-based audit trail, already deployed on target infrastructure |
|
||
| Frontend | React + Vite + Tailwind CSS | Rich interactivity for report builder, maps, charts; static build embedded in Go binary |
|
||
| Charts | Recharts | React-native, lightweight, composable |
|
||
| Maps | react-leaflet | React-native, lighter than OpenLayers, strong community |
|
||
| Deployment | Docker (multi-stage build) | Single image containing Go binary with embedded frontend assets; no runtime dependencies on Node or Nginx |
|
||
|
||
### Deployment Target
|
||
|
||
Docker Swarm on Raspberry Pi cluster. Estimated resource consumption:
|
||
|
||
| Container | Memory Limit | CPU Limit |
|
||
|-----------|-------------|-----------|
|
||
| Tabulae Aeriae (Go + static assets) | 128 MB | 0.5 CPU |
|
||
| PostgreSQL 16 Alpine | 256 MB | 0.5 CPU |
|
||
| **Total** | **~384 MB** | **1.0 CPU** |
|
||
|
||
### Build Pipeline
|
||
|
||
Multi-stage Docker build:
|
||
1. **Stage 1 (Node):** Build React frontend with Vite → static assets
|
||
2. **Stage 2 (Go):** Compile Go binary embedding frontend via `embed.FS`
|
||
3. **Stage 3 (Alpine):** Minimal runtime image with binary + CA certificates + timezone data
|
||
|
||
Final image size: estimated 20–30 MB.
|
||
|
||
---
|
||
|
||
## 4. Data Architecture
|
||
|
||
### Database Tables (v1 — 10 tables)
|
||
|
||
| Table | Purpose |
|
||
|-------|---------|
|
||
| `users` | Pilot accounts, authentication, regulatory profile, tier |
|
||
| `flights` | Core logbook entries — all time fields, approaches, custom fields |
|
||
| `aircraft` | Real aircraft and simulators/FTDs — tail numbers, type, attributes, device info |
|
||
| `airports` | Seeded from OurAirports; includes user-defined custom airports |
|
||
| `airport_identifiers` | Maps current and former airport codes to physical airports |
|
||
| `pilot_qualifications` | Certificates, ratings, endorsements, and currency events (IPC, flight review, checkrides) |
|
||
| `medical_certificates` | Medical class, issue/expiry dates, examiner info |
|
||
| `saved_reports` | User-saved report configurations with JSONB config |
|
||
| `currency_rules` | JSON-driven currency rule definitions (system and user-defined) |
|
||
| `audit_log` | Append-only changelog triggered by INSERT/UPDATE/DELETE on tracked tables |
|
||
|
||
### Key Schema Design Principles
|
||
|
||
- **All times stored as INTEGER minutes.** Floating-point hours introduce rounding errors that accumulate over a career. Rounding to display hours (truncate, round-nearest, or round-up) is applied only at the reporting layer, after aggregation.
|
||
- **All timestamps stored as TIMESTAMPTZ in UTC.** No local time in storage or computation. Local time conversion is a display-layer concern only.
|
||
- **No pre-aggregated compound categories.** Fields like "cross-country while under instruction" are derived at query time using `LEAST()` intersection logic. Pilots log atomic observations; the system computes intersections.
|
||
- **JSONB for flexible structures.** Instrument approaches (variable count and type), custom fields (company/insurance-specific), and report configurations all use JSONB for schema flexibility without sacrificing queryability.
|
||
- **Historical accuracy over normalization.** The `tail_number` is denormalized onto the flight record because aircraft registrations change. The `departure_airport` and `arrival_airport` store the code the pilot used at the time, even if that code has since been retired.
|
||
- **Simulators and FTDs in the aircraft table.** Training devices are aircraft for logging purposes. A boolean `is_simulator` flag plus device-specific nullable columns (level, serial, approval number) avoid a separate table and dual foreign key complexity.
|
||
|
||
### Airport Data
|
||
|
||
Source: OurAirports (`davidmegginson/ourairports-data`), Unlicense. Over 78,000 airports worldwide, updated daily, includes closed airports.
|
||
|
||
Strategy: Embed a snapshot at build time for offline-capable first boot. Provide an admin command (`--refresh-airports`) or API endpoint to pull updated data on demand.
|
||
|
||
Historical code changes (e.g., 09G → KTEW) are handled by the `airport_identifiers` table, which maps multiple codes to a single physical airport with `is_current` and date-range fields.
|
||
|
||
---
|
||
|
||
## 5. Reporting
|
||
|
||
### Built-in Reports (One-Click)
|
||
|
||
| Report | Output |
|
||
|--------|--------|
|
||
| **FAA 8710-1 Section III** | Complete pilot time matrix — all categories, classes, and time fields. Derived at query time from atomic flight fields using `LEAST()` for compound categories. Rounded to whole hours per user preference. |
|
||
| **FAA Medical (8500-8)** | Total all-time hours and total hours in last 6 calendar months. Two numbers, one click. |
|
||
| **Currency Status** | Real-time status of all active currency rules — green/yellow/red with days remaining and remediation guidance. |
|
||
|
||
### Configurable Reports
|
||
|
||
Users can create and save custom reports by selecting date range (fixed, rolling, or all-time), filters (aircraft, category/class, airport), grouping (month, year, type, category/class), columns to include, and output format (on-screen, PDF, CSV).
|
||
|
||
Report configurations are stored as JSONB and can be pinned to the dashboard for one-click access.
|
||
|
||
### 8710 Derivation Method
|
||
|
||
Compound time categories are derived using `LEAST()` logic at query time:
|
||
|
||
- **XC Instruction Received** = `SUM(LEAST(cross_country, dual_received))` on flights where both > 0
|
||
- **Night PIC/SIC** = `SUM(LEAST(night_time, pic_time + sic_time))` on flights where both > 0
|
||
|
||
This prevents the aggregation errors that occur when pilots manually pre-compute compound categories. The pilot logs atomic observations; the system handles the math.
|
||
|
||
Rounding is applied after aggregation (sum all minutes across all flights, then round to hours), not per-flight, to prevent cumulative rounding error.
|
||
|
||
---
|
||
|
||
## 6. Currency Tracking
|
||
|
||
### Engine Design
|
||
|
||
Currency rules are **data, not code.** Each rule is a JSON configuration stored in the `currency_rules` table. The engine evaluates rules against flight records and qualification events to produce real-time status.
|
||
|
||
### FAA Rules (v1)
|
||
|
||
| Rule | Regulation | Lookback | Requirements |
|
||
|------|-----------|----------|-------------|
|
||
| Day currency (per category/class/type) | 61.57(a) | 90 days rolling | 3 takeoffs + 3 landings |
|
||
| Night currency (per category/class/type) | 61.57(b) | 90 days rolling | 3 night takeoffs + 3 night full-stop landings |
|
||
| Instrument currency | 61.57(c) | 6 calendar months | 6 approaches + holding + tracking |
|
||
| Instrument grace period | 61.57(c)/(d) | Months 7–12 after lapse | Same tasks to self-restore; IPC required after month 12 |
|
||
| Flight review | 61.56 | 24 calendar months | Flight review, checkride, or WINGS phase |
|
||
| Medical certificate | 61.23 | Per class/age | Valid medical not expired |
|
||
|
||
### Custom Rules
|
||
|
||
Users can define personal minimums, insurance requirements, or company-specific rules using the same engine.
|
||
|
||
### Night Definition Handling
|
||
|
||
The `night_time` field stores sunset-to-sunrise time (the standard logging definition). Night takeoff/landing classification for currency purposes uses the 1-hour-after-sunset to 1-hour-before-sunrise standard, auto-suggested from departure/arrival times and airport coordinates.
|
||
|
||
### Night Time Auto-Calculation
|
||
|
||
Solar position computed at intervals along the great circle route between departure and arrival airports. Accounts for aircraft movement relative to the terminator — critical for long-haul flights crossing significant longitude. Produces the sunset-to-sunrise value for logging. Always pilot-overridable.
|
||
|
||
---
|
||
|
||
## 7. Authentication & Authorization
|
||
|
||
### Architecture
|
||
|
||
Single auth system with a pluggable provider interface. No separate codepaths for free vs. commercial.
|
||
|
||
**v1 provider:** Username/password with bcrypt hashing and JWT token issuance.
|
||
|
||
**Future providers (same interface):** OAuth2/OIDC (Google, generic), LDAP. Adding a provider means implementing the `AuthProvider` interface — no changes to middleware, handlers, or session management.
|
||
|
||
### Feature Gating
|
||
|
||
Tier-based authorization middleware reads a `tier` field (free/professional) and gates access to paid-tier features. Auth and authorization are separate concerns — the auth system doesn't know about tiers.
|
||
|
||
---
|
||
|
||
## 8. Import / Export
|
||
|
||
### Import
|
||
|
||
Pluggable adapter architecture. Each adapter implements an `ImportAdapter` interface with `Detect()` (auto-format detection) and `Parse()` (conversion to internal model) methods.
|
||
|
||
**v1 adapter:** Generic CSV with user-defined column mapping.
|
||
**Future adapters:** ForeFlight, LogTen Pro, Logbook Pro, AeroLog.
|
||
|
||
Import supports partial success (bad rows reported individually, good rows imported), duplicate detection, and detailed per-row error reporting.
|
||
|
||
### Export
|
||
|
||
- CSV: Full logbook export
|
||
- PDF: Configurable column layout (user-defined logbook page format)
|
||
|
||
---
|
||
|
||
## 9. Visualization
|
||
|
||
### Flight Map
|
||
|
||
Interactive world map (react-leaflet) displaying great circle routes between airports. Filterable by date range, aircraft, and category/class.
|
||
|
||
### Statistics Dashboard
|
||
|
||
Recharts-based charts showing: time by category/class over time, cumulative hours, flights by month/year, time by aircraft type, airport frequency, and custom breakdowns.
|
||
|
||
---
|
||
|
||
## 10. Audit Trail
|
||
|
||
PostgreSQL trigger-based changelog. Every INSERT, UPDATE, and DELETE on tracked tables (`flights`, `aircraft`, `users`) writes a row to `audit_log` with the full old and new row values as JSONB. The `changed_by` user ID is captured via a PostgreSQL session variable set by the application middleware.
|
||
|
||
Enables: full reconstruction of any record's history at any point in time, regulatory compliance documentation, and dispute resolution for commercial operators.
|
||
|
||
---
|
||
|
||
## 11. EASA Skeleton
|
||
|
||
FAA compliance is the v1 target. EASA support is prepared via:
|
||
|
||
- A `regulatory_profile` field on the user record (values: `faa`, `easa`, `both`)
|
||
- Nullable EASA-specific columns on `flights` and `aircraft` tables (multi-pilot time, co-pilot time, SPSE/SPME, function type, etc.)
|
||
- These columns are hidden in the UI when `regulatory_profile = 'faa'`
|
||
- Full EASA implementation is a future release — the schema is ready, the UI and reporting are not
|
||
|
||
---
|
||
|
||
## 12. Out of Scope (v1)
|
||
|
||
- Duty/rest tracking (Part 117, Part 135 Subpart F)
|
||
- Augmented operations / multi-crew scheduling
|
||
- PF/PNF as first-class schema fields (available via custom_fields JSONB)
|
||
- IOE tracking as a first-class field
|
||
- High minimums captain tracking
|
||
- Operator-specific currency overrides (61.57(e) exceptions)
|
||
- GPS track import (KML/GPX)
|
||
- SQLite backend
|
||
- Full EASA compliance
|
||
- OAuth2/OIDC/LDAP authentication
|
||
- Mobile-native applications (responsive web only)
|
||
- Integration with external services (ForeFlight, Garmin Pilot, etc.)
|
||
- Electronic endorsement/signature system
|
||
- Multi-tenant SaaS hosting infrastructure
|
||
|
||
---
|
||
|
||
## 13. Risks and Mitigations
|
||
|
||
| Risk | Impact | Mitigation |
|
||
|------|--------|-----------|
|
||
| FAA regulatory changes | Currency rules or reporting requirements change | Rules are data-driven JSON configs; updates are database migrations, not code changes |
|
||
| PostgreSQL resource consumption on Pi | Exceeds memory limits under load | Alpine image, connection pooling, aggressive `work_mem` tuning; schema is simple (10 tables) |
|
||
| Airport data staleness | New airports or code changes not reflected | Build-time embed with on-demand refresh command; quarterly refresh cadence is sufficient |
|
||
| Night time calculation accuracy | Solar algorithm produces incorrect results for edge cases | Algorithm uses well-established NOAA equations; pilot always has manual override; auto-calculation is a suggestion, not a mandate |
|
||
| Scope creep from professional tier features | v1 becomes unshippable | Professional features are explicitly deferred and documented; schema is designed to accommodate them without destructive migrations |
|