shopadmin

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: AGPL-3.0 Imports: 19 Imported by: 0

README

shopadmin

Tests Status Go Report Card PkgGoDev

License

This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). You can find a copy of the license at https://www.gnu.org/licenses/agpl-3.0.en.html

For commercial use, please use my contact page to obtain a commercial license.

Introduction

Admin interface for github.com/dracory/shopstore. Provides a ready-to-use admin panel for managing products, categories, discounts, and orders.

Modeled after github.com/dracory/cmsstore/admin — same folder-per-controller pattern, same UiConfig/UiBase conventions.

Features

  • Product management — create, update, delete, list with AJAX
  • Category management — create, update, delete, list with AJAX
  • Discount management — create, delete, list with AJAX
  • Order management — list orders, view order details
  • Media management — upload, reorder, delete product images
  • Metadata & tags — per-product metadata and tag editing
  • Customer resolution — pluggable via CustomerResolverInterface (no dependency on any specific user/auth package)
  • Custom layouts — bring your own layout via FuncLayout
  • Bootstrap + Vue CDN — default UI works out of the box

Installation

go get github.com/dracory/shopadmin

Quick Start

package main

import (
    "log/slog"
    "net/http"
    "os"

    "github.com/dracory/shopadmin"
    "github.com/dracory/shopstore"
)

func main() {
    store, err := shopstore.NewStore(shopstore.NewStoreOptions{
        DB:                 yourDB,
        ProductTableName:   "shop_product",
        CategoryTableName:  "shop_category",
        // ... other table names
        AutomigrateEnabled: true,
    })
    if err != nil {
        log.Fatal(err)
    }

    admin, err := shopadmin.New(shopadmin.AdminOptions{
        Store:       store,
        Logger:      slog.New(slog.NewTextHandler(os.Stderr, nil)),
        AdminHomeURL: "/admin",
        ShopAdminURL: "/admin/shop",
    })
    if err != nil {
        log.Fatal(err)
    }

    http.Handle("/admin/shop", admin)
    http.ListenAndServe(":8080", nil)
}

Integration with a Router

shopadmin.AdminInterface exposes Handle(w, r), which is an http.HandlerFunc-compatible method. Wire it into any router that accepts standard http.Handler:

// stdlib
mux.Handle("/admin/shop", http.HandlerFunc(admin.Handle))

// github.com/dracory/rtr
route := rtr.NewRoute().
    SetName("Admin > Shop").
    SetPath("/admin/shop").
    SetHTMLHandler(admin.Handle)

Customer Resolution

Shopadmin does not depend on userstore or any specific auth package. Instead, order controllers resolve customer names/emails via an optional CustomerResolverInterface:

type CustomerResolverInterface interface {
    FindByID(ctx context.Context, customerID string) (name, email string)
    SearchIDs(ctx context.Context, name, email string) ([]string, error)
}

Provide an implementation at construction time:

admin, _ := shopadmin.New(shopadmin.AdminOptions{
    Store:  store,
    Logger: logger,
    CustomerResolver: &myCustomerResolver{userStore: app.GetUserStore()},
})

If CustomerResolver is nil, customer fields stay empty and customer filtering is disabled — no panic, no error.

See docs/proposal.md for the full design rationale.

Custom Layout

By default, shopadmin renders a bare-bones HTML page with Bootstrap and Vue from CDN. To embed the admin inside your own layout (branding, menus, etc.), provide FuncLayout:

admin, _ := shopadmin.New(shopadmin.AdminOptions{
    Store:  store,
    Logger: logger,
    FuncLayout: func(title, body string, opts struct {
        Styles     []string
        StyleURLs  []string
        Scripts    []string
        ScriptURLs []string
    }) string {
        return myLayout(title, body, opts)
    },
})

The anonymous struct matches cmsstore/admin exactly, so you can reuse your existing cmsstore layout function.

Testing

go test ./...

Tests use an in-memory SQLite database via modernc.org/sqlite — no external services required.

Documentation

Overview

Package shopadmin provides a standalone shop admin interface following the folder-per-controller pattern. Each controller is in its own subfolder and handles its own views and AJAX data.

This module is modeled on github.com/dracory/cmsstore/admin.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrStoreRequired is returned when Store is not provided
	ErrStoreRequired = errors.New("store is required")

	// ErrLoggerRequired is returned when Logger is not provided
	ErrLoggerRequired = errors.New("logger is required")
)

Functions

This section is empty.

Types

type AdminInterface

type AdminInterface interface {
	Handle(w http.ResponseWriter, r *http.Request)
}

AdminInterface defines the interface for the shop admin

func New

func New(opts AdminOptions) (AdminInterface, error)

New creates a new shop admin instance. Returns ErrStoreRequired if Store is nil, ErrLoggerRequired if Logger is nil.

type AdminOptions

type AdminOptions struct {
	// Store is the shopstore.StoreInterface (required)
	Store shopstore.StoreInterface

	// Logger is required (matches cmsstore requirement)
	Logger *slog.Logger

	// CustomerResolver resolves customer data for order views.
	// Optional — nil means customer fields stay empty and customer
	// filtering is disabled. Called by order_details and order_manager.
	CustomerResolver CustomerResolverInterface

	// FuncLayout is an optional function to render the admin interface
	// inside your own layout (branding, menus, etc.).
	// If nil, a default bare-bones HTML page is used (Bootstrap + Vue CDN).
	// Uses anonymous struct to match cmsstore/admin exactly, so consumers
	// can reuse their cmsstore layout function for shopadmin.
	FuncLayout func(title string, body string, options struct {
		Styles     []string
		StyleURLs  []string
		Scripts    []string
		ScriptURLs []string
	}) string

	// AdminHomeURL is the URL for the admin home page (default: "/admin")
	AdminHomeURL string

	// ShopAdminURL is the base URL for shop admin (default: "/admin/shop")
	ShopAdminURL string

	// FileManagerURL is the URL for the file manager (optional)
	FileManagerURL string

	// AuthUserID returns the authenticated user ID from the request.
	// If it returns "", the user is treated as unauthenticated.
	AuthUserID func(r *http.Request) string
}

AdminOptions contains all dependencies and configuration for the shop admin.

Store, CacheStore, and Logger replace the in-repo version's Registry field (which was app.AppInterface). This matches the cmsstore/admin convention where stores are passed directly.

Customer resolution is via CustomerResolverInterface rather than a userstore dependency, keeping shopadmin decoupled from any specific auth/user-management package.

type CustomerResolverInterface

type CustomerResolverInterface = shared.CustomerResolverInterface

CustomerResolverInterface resolves customer data for order views. The host project provides an implementation — shopadmin does not care where the data comes from (userstore, CRM, external API, etc.).

This is a re-export of shared.CustomerResolverInterface so consumers of the root shopadmin package can use shopadmin.CustomerResolverInterface without importing the shared subpackage.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL