Remove the module "xxx" { source = "./module" } indirection layer
from all 66 service stacks. Resources are now defined directly in
each stack's main.tf instead of through a wrapper module.
- Merge module/main.tf contents into stack main.tf
- Apply variable replacements (var.tier -> local.tiers.X, renamed vars)
- Fix shared module paths (one fewer ../ at each level)
- Move extra files/dirs (factory/, chart_values, subdirs) to stack root
- Update state files to strip module.<name>. prefix
- Update CLAUDE.md to reflect flat structure
Verified: terragrunt plan shows 0 add, 0 destroy across all stacks.
202 lines
8.4 KiB
Markdown
202 lines
8.4 KiB
Markdown
# Codebase Structure
|
|
|
|
**Analysis Date:** 2026-02-17
|
|
|
|
## Directory Layout
|
|
|
|
```
|
|
f1-stream/
|
|
├── main.go # Entry point, service initialization, signal handling
|
|
├── go.mod # Go module definition
|
|
├── go.sum # Dependency lock file
|
|
├── Dockerfile # Container image definition
|
|
├── redeploy.sh # Kubernetes redeployment script
|
|
├── index.html # HTML template served at root
|
|
├── internal/ # Private Go packages
|
|
│ ├── auth/ # WebAuthn authentication and session management
|
|
│ ├── models/ # Domain data types
|
|
│ ├── server/ # HTTP handlers, routes, middleware
|
|
│ ├── store/ # File-based persistence layer
|
|
│ ├── scraper/ # Reddit content scraper
|
|
│ └── proxy/ # HTTP proxy with rate limiting
|
|
├── static/ # Frontend assets served to clients
|
|
│ ├── index.html # Main SPA template
|
|
│ ├── css/ # Stylesheets
|
|
│ └── js/ # Client-side JavaScript modules
|
|
└── .planning/ # Planning/documentation directory
|
|
└── codebase/ # Architecture analysis documents
|
|
```
|
|
|
|
## Directory Purposes
|
|
|
|
**Root Level:**
|
|
- Purpose: Service configuration and entry point
|
|
- Contains: Go module, main executable, Docker configuration, shell scripts
|
|
- Key files: `main.go` (service bootstrap), `go.mod` (dependencies)
|
|
|
|
**`internal/`:**
|
|
- Purpose: Private packages (not importable by external code)
|
|
- Contains: All business logic, separated by concern
|
|
- Key pattern: Each subdirectory is a distinct Go package with clear responsibility
|
|
|
|
**`internal/auth/`:**
|
|
- Purpose: User authentication, session management, context helpers
|
|
- Contains: WebAuthn ceremony handlers, session token management, user-in-context utilities
|
|
- Key files:
|
|
- `auth.go`: Registration/login handlers, ceremony session storage, credential validation
|
|
- `context.go`: Request context helpers for passing user data between middleware and handlers
|
|
|
|
**`internal/models/`:**
|
|
- Purpose: Domain model definitions
|
|
- Contains: User, Stream, ScrapedLink, Session type definitions
|
|
- Key files: `models.go` (all types, includes WebAuthn interface implementations)
|
|
|
|
**`internal/server/`:**
|
|
- Purpose: HTTP API and routing layer
|
|
- Contains: Handler functions, route registration, middleware implementations
|
|
- Key files:
|
|
- `server.go`: Server struct, route registration, API handlers (streams, admin, public endpoints)
|
|
- `middleware.go`: LoggingMiddleware, RecoveryMiddleware, AuthMiddleware, RequireAuth, RequireAdmin, OriginCheck
|
|
|
|
**`internal/store/`:**
|
|
- Purpose: Persistent storage abstraction over file system
|
|
- Contains: JSON file operations, per-entity storage methods, atomic write patterns
|
|
- Key files:
|
|
- `store.go`: Store struct, directory initialization, JSON helper functions (readJSON, writeJSON)
|
|
- `streams.go`: Stream CRUD operations, publish toggle, seeding
|
|
- `users.go`: User lookup, credential updates, admin count
|
|
- `sessions.go`: Session creation, validation, expiry cleanup
|
|
- `scraped.go`: Scraped link persistence, active link filtering
|
|
|
|
**`internal/scraper/`:**
|
|
- Purpose: Background content aggregation
|
|
- Contains: Interval-based scraper, Reddit-specific scraper logic
|
|
- Key files:
|
|
- `scraper.go`: Scraper service, interval-based run loop, manual trigger mechanism, deduplication logic
|
|
- `reddit.go`: Reddit API polling, F1 keyword filtering, URL extraction (not included in sample reads but referenced)
|
|
|
|
**`internal/proxy/`:**
|
|
- Purpose: HTTP content fetching with security controls and rate limiting
|
|
- Contains: Rate limiter, private IP validation, response modification
|
|
- Key files: `proxy.go` (implements http.Handler, rate limiting, content fetching, base tag injection)
|
|
|
|
**`static/`:**
|
|
- Purpose: Frontend assets served to browser
|
|
- Contains: HTML template and client-side code
|
|
- Key files:
|
|
- `index.html`: SPA HTML template (includes script tags loading js/)
|
|
- `js/app.js`: Toast notifications, dialog system, tab switching, initialization
|
|
- `js/auth.js`: Registration/login UI, WebAuthn client ceremony
|
|
- `js/streams.js`: Stream display, filtering, admin operations
|
|
- `js/utils.js`: Shared utilities (HTML escaping)
|
|
- `css/`: Stylesheets for app UI
|
|
|
|
## Key File Locations
|
|
|
|
**Entry Points:**
|
|
- `main.go`: Service initialization, dependency injection, signal handling, goroutine startup
|
|
|
|
**Configuration:**
|
|
- Environment variables read in `main.go` (LISTEN_ADDR, DATA_DIR, SCRAPE_INTERVAL, etc.)
|
|
- WebAuthn config passed to `auth.New()`
|
|
- `.env` files not tracked (see .gitignore)
|
|
|
|
**Core Logic:**
|
|
- Request routing: `internal/server/server.go:registerRoutes()`
|
|
- Auth logic: `internal/auth/auth.go`
|
|
- Data storage: `internal/store/store.go` and per-entity files
|
|
- Scraping: `internal/scraper/scraper.go`
|
|
- Proxying: `internal/proxy/proxy.go`
|
|
|
|
**Testing:**
|
|
- No test files present in codebase (see TESTING.md concerns section)
|
|
|
|
## Naming Conventions
|
|
|
|
**Files:**
|
|
- Go source files: lowercase with underscores (e.g., `auth.go`, `middleware.go`)
|
|
- JavaScript files: lowercase with hyphens or underscores (e.g., `app.js`, `auth.js`)
|
|
- JSON data files: lowercase (e.g., `streams.json`, `users.json`, `sessions.json`)
|
|
|
|
**Directories:**
|
|
- Go packages: lowercase, single word preferred (e.g., `auth`, `store`, `models`)
|
|
- Frontend assets: plural nouns (e.g., `static`, `css`, `js`)
|
|
|
|
**Functions:**
|
|
- Go: CamelCase (exported), camelCase (unexported)
|
|
- JavaScript: camelCase throughout (e.g., `loadPublicStreams()`, `showToast()`)
|
|
|
|
**Types:**
|
|
- Go structs: CamelCase (e.g., `User`, `Stream`, `Store`, `Auth`)
|
|
- Methods: CamelCase (e.g., `BeginLogin()`, `AddStream()`)
|
|
|
|
**Variables:**
|
|
- Go: camelCase (e.g., `listenAddr`, `dataDir`, `adminUsername`)
|
|
- JavaScript: camelCase (e.g., `container`, `userID`, `sessionToken`)
|
|
|
|
## Where to Add New Code
|
|
|
|
**New Feature (e.g., new stream filter):**
|
|
- Primary code: Add handler in `internal/server/server.go`, register route in `registerRoutes()`
|
|
- Store operations: Add method to appropriate file in `internal/store/` (likely `streams.go`)
|
|
- Frontend: Add UI in `static/` and API call in `static/js/streams.js` or new module
|
|
- Models: Extend types in `internal/models/models.go` if new fields needed
|
|
|
|
**New Authentication Method:**
|
|
- Core implementation: New file in `internal/auth/` (e.g., `oauth.go`)
|
|
- Handlers: Add methods following WebAuthn pattern (BeginXxx, FinishXxx)
|
|
- Routes: Register in `registerRoutes()`
|
|
- Frontend: Add form/button in `static/js/auth.js`
|
|
|
|
**New Background Service (e.g., content validator):**
|
|
- Implementation: New file in `internal/` or new package `internal/validator/`
|
|
- Integration: Initialize in `main()` alongside `scraper.New()`
|
|
- Lifecycle: Use context pattern from scraper's `Run(ctx)` method
|
|
- Storage: Use existing `Store` instance
|
|
|
|
**Utilities/Helpers:**
|
|
- Shared by Go packages: Add to package where most useful, or create new `internal/util/` package
|
|
- Shared by frontend: Add to `static/js/utils.js` or create new module
|
|
- Shared helpers pattern: Functions not tied to single package, used across multiple
|
|
|
|
## Special Directories
|
|
|
|
**`internal/`:**
|
|
- Purpose: Enforce package privacy (cannot be imported by external code)
|
|
- Generated: No
|
|
- Committed: Yes
|
|
|
|
**`static/`:**
|
|
- Purpose: Served directly to clients via `http.FileServer`
|
|
- Generated: No (hand-written frontend)
|
|
- Committed: Yes
|
|
|
|
**`.planning/codebase/`:**
|
|
- Purpose: Architecture documentation for development guidance
|
|
- Generated: No (manually created by mapping process)
|
|
- Committed: Yes
|
|
|
|
**Data Directory (runtime):**
|
|
- Purpose: Persistent JSON files (streams.json, users.json, sessions.json, scraped.json)
|
|
- Location: Specified by DATA_DIR env var (default `/data`)
|
|
- Generated: Yes (created on first run)
|
|
- Committed: No (varies per deployment environment)
|
|
|
|
## Import Patterns
|
|
|
|
**Go Package Imports:**
|
|
- Standard library first: `import ("context" "fmt" "log")`
|
|
- Internal packages second: `import ("f1-stream/internal/auth" "f1-stream/internal/store")`
|
|
- External third-party last: `import ("github.com/go-webauthn/webauthn/webauthn")`
|
|
|
|
**Cross-Package Dependencies:**
|
|
- Server depends on: Auth, Store, Proxy, Scraper, Models
|
|
- Auth depends on: Store, Models
|
|
- Scraper depends on: Store, Models
|
|
- Proxy depends on: none (standalone service)
|
|
- Store depends on: Models
|
|
- Models depends on: external WebAuthn library only
|
|
|
|
---
|
|
|
|
*Structure analysis: 2026-02-17*
|