Files
OpenFlare/downstream
ryan c9b702d234 refactor(core): fix cross-domain auth imports, unify migration, add downstream scaffold
Architecture:
- Move GetFromContext/SetToContext from plugins/domain/auth to pkg/util
- Move auth context key constants to core/contracts (AuthUserObjKey, AuthTokenAuthKey, etc.)
- Add AuthUserIDKey, AuthUserNameKey, GetCurrentUserID, RevokeToken to contracts.AuthService
- All 4 domain plugin Apply() methods now resolve AuthService via core.Using IoC
- Plugin route middleware uses authSvc.RequireAuthMiddleware() cast to gin.HandlerFunc
- DisallowTokenAuth added to AuthService contract

Migration:
- Replace cmd/app.go SetMigrationRunner bridge with gooseEngine implementing core.MigrationEngine
- Remove cmd/root.go PreRun migration hooks and runMigrations() function
- Migrations now run via core.App.Start() → RunMigrations()

Events:
- Add complete domain event topic catalog and payload DTOs to core/contracts/events.go
- 15 event topics across auth, user, admin, upload, message_gateway, risk_control

Downstream:
- Create downstream/ directory with README and custom_example plugin scaffold

CI:
- Update Makefile code-check architecture guards for Cordis layering
- Enforce: core no gin/gorm/asynq, contracts no plugins/, pkg no plugins/, domain no cross-domain
2026-08-28 11:51:48 +08:00
..

Downstream Custom Plugins

This directory is the designated location for downstream (deployment-specific) Cordis plugins.

Architecture

downstream/
├── README.md
└── plugins/
    └── custom_example/       # Example plugin — copy & rename to get started
        └── plugin.go

Downstream plugins follow the same core.Plugin contract as platform plugins:

type Plugin interface {
    Name() string
    Apply(ctx *core.Context) error
}

Rules

  1. Naming: Each plugin directory name becomes its import path and plugin ID (kebab-case recommended).
  2. Dependencies: Downstream plugins may import core/, core/contracts/, pkg/, and plugins/infra/ packages from the platform. They MUST NOT import domain plugin internal packages — use core.Inject[contracts.XxxService](ctx) instead.
  3. Registration: Add your downstream plugin to cmd/app.go before the platform plugins or after, depending on which services it needs:
    // newWaveletApp in cmd/app.go
    app.Use(
        database.New(),
        cache.New(),
        logger.New(),
        storage.New(),
        // ... platform domain plugins ...
        custom_hello.New(), // your downstream plugin
        driver_http.New(driver_http.WithAddr(config.Config.App.Addr)),
        driver_asynq_worker.New(),
        driver_asynq_cron.New(),
    )
    
  4. Migration: If your plugin needs database tables, embed SQL files in a migrations/ directory and register via ctx.Migrations().Register(...) in Apply().

Quick Start

package custom_example

import (
    "github.com/Rain-kl/Wavelet/core"
    "github.com/Rain-kl/Wavelet/core/contracts"
    "github.com/gin-gonic/gin"
)

type Plugin struct{}

func New() *Plugin { return &Plugin{} }

func (p *Plugin) Name() string { return "custom_example" }

func (p *Plugin) Apply(ctx *core.Context) error {
    // Example: register a route that uses AuthService
    var authSvc contracts.AuthService
    if err := ctx.Using(func(svc contracts.AuthService) { authSvc = svc }); err != nil {
        return err
    }

    g := ctx.Router().Group("/api/v1/custom", authSvc.RequireAuthMiddleware().(gin.HandlerFunc))
    g.GET("/hello", func(c *gin.Context) {
        user, _ := authSvc.GetCurrentUser(c.Request.Context())
        c.JSON(200, gin.H{"message": "Hello " + user.Username})
    })

    return nil
}