feat: add admin panel, stats endpoint, and url field to listings

- Add full admin CRUD routes for users, companies, listings, oil-prices
  protected behind auth middleware (/admin/*)
- Add public /stats endpoint returning latest market price aggregates
- Add /health and / health check endpoints
- Add `url` field to listings (struct, all SQL queries, create/update)
- Add `phone` and `url` fields to OilPrice struct
- Remove deprecated company CRUD handlers (get_company, create_company)
- Update schema.sql; remove one-off alter/drop migration scripts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 11:34:03 -05:00
parent 85bbe43192
commit 6c95a7d201
14 changed files with 749 additions and 137 deletions

View File

@@ -20,6 +20,12 @@ mod state;
mod company;
mod listing;
mod oil_prices;
mod stats;
mod admin;
async fn health_check() -> &'static str {
"NewEnglandBio API is running"
}
#[tokio::main]
async fn main() {
@@ -75,9 +81,12 @@ async fn main() {
.route("/listing/:listing_id", axum::routing::get(get_listing_by_id))
.route("/listing/:listing_id", axum::routing::put(update_listing))
.route("/listing/:listing_id", axum::routing::delete(delete_listing))
.merge(crate::admin::admin_routes())
.route_layer(middleware::from_fn_with_state(state.clone(), auth_middleware));
let public_routes = Router::new()
.route("/", axum::routing::get(health_check))
.route("/health", axum::routing::get(health_check))
.route("/auth/register", axum::routing::post(register))
.route("/auth/login", axum::routing::post(login))
.route("/auth/logout", axum::routing::post(logout))
@@ -85,7 +94,8 @@ async fn main() {
.route("/state/:state_abbr", axum::routing::get(get_counties_by_state))
.route("/state/:state_abbr/:county_id", axum::routing::get(get_county_by_id))
.route("/listings/county/:county_id", axum::routing::get(get_listings_by_county))
.route("/oil-prices/county/:county_id", axum::routing::get(get_oil_prices_by_county));
.route("/oil-prices/county/:county_id", axum::routing::get(get_oil_prices_by_county))
.route("/stats", axum::routing::get(crate::stats::data::get_latest_stats));
let app = public_routes
.merge(protected_routes)