tabulae-aeriae/documentation/administrative/tabulae-aeriae-scope-statement.md

276 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 2030 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 712 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 |