A Call-for-Papers (CfP) platform built with Next.js, designed to help organizers manage conferences, proposals, and speaker scheduling.
When creating documentation for SessioFlow, follow this recommended order:
Step 1: Inception (Product Discovery)
β
Step 2: Flow Documentation (Reveals Entities)
β
Step 3: Entity Lifecycle (Define Entities)
β
Step 4: More Flows (Reference Existing Entities)
1. Inception Phase (docs/inception/)
- Complete Inception Steps 1-8 (Product Vision β MVP Canvas)
- Step 6: User Journey Mapping identifies all journeys (J1-J5)
- Step 7: Features & Sequencing defines MVP scope
2. Flow Documentation (docs/product/bounded-contexts/{context}/flows/)
- Start with Journey 1 (e.g., Setup Conference)
- Use
create-flow-documentationskill to generate flow specs - Flow reveals which entities are needed (Conference, CfpConfig, etc.)
- Extract Business Rules (BR-XXX) and Invariants (INV-XXX)
3. Entity Lifecycle Documentation (docs/product/bounded-contexts/{context}/entities/)
- Create entity docs based on entities revealed in flows
- Use
create-entity-lifecycleskill to generate entity specs - Define state machines, transitions, and domain methods
- Extract additional BRs and INVs if needed
4. Additional Flows (docs/product/bounded-contexts/{context}/flows/)
- Document remaining journeys (J2-J4)
- Reference existing entity lifecycle docs
- Extract BRs and INVs as needed
docs/
βββ inception/ # Inception workshop outputs
β βββ 1-product-vision-and-boundaries.md
β βββ 2-tradeoffs.md
β βββ 3-personas/
β βββ 4-empathy-map.md
β βββ 5-brainstorming.md
β βββ 6-user-journeys/ β START HERE
β βββ 7-features-and-sequencing.md
β βββ 8-mvp-canvas-definition.md
β
βββ product/ # DDD documentation
βββ bounded-contexts/
β βββ conference/
β βββ flows/ β Create flows first (reveals entities)
β β βββ journey-01-setup-conference.md
β βββ entities/ β Then create entities
β β βββ conference.md
β β βββ cfp-config.md
β βββ business-rules/ β Extracted from flows/entities
β β βββ BR-001-*.md
β βββ invariants/ β Extracted from flows/entities
β βββ INV-001-*.md
βββ flows/ # Flow catalog
βββ README.md
SessioFlow provides two AI skills to help generate documentation:
| Skill | Purpose | Triggers When You Say |
|---|---|---|
| create-flow-documentation | Generate user journey flows | "Create flow for Journey 2", "Generate flow specification" |
| create-entity-lifecycle | Generate entity specs | "Create entity lifecycle for Conference", "Document the Submission entity" |
Both skills are self-contained with all templates and guidelines bundled.
flowchart TB
subgraph Inception["Inception Phase"]
A["Inception Steps 1-8"] --> B["Step 6: User Journey Mapping"]
B --> C["Step 7: Features & Sequencing"]
end
subgraph FlowDocs["Flow Documentation"]
D["Create Flow 1<br/>(Journey 01: Setup Conference)"] --> E["Extract BRs & INVs<br/>from flow steps"]
E --> F["journey-01-setup-conference.md"]
end
subgraph EntityDocs["Entity Lifecycle Documentation"]
G["Create Entity Lifecycle<br/>(Conference, CfpConfig)"] --> H["Extract BRs & INVs<br/>from entity constraints"]
H --> I["conference.md, cfp-config.md"]
end
subgraph BRINV["Business Rules & Invariants"]
J["business-rules/BR-XXX-*.md"]
K["invariants/INV-XXX-*.md"]
end
subgraph AdditionalFlows["Additional Flows"]
L["Create Flow 2-4<br/>(Reference Existing Entities)"] --> M["journey-02-04.md"]
end
%% Connections
C --> D
F -.-> G
G -.-> L
E -.-> J
E -.-> K
H -.-> J
H -.-> K
M -.-> J
M -.-> K
%% Styling
style Inception fill:#e3f2fd
style FlowDocs fill:#c8e6c9
style EntityDocs fill:#fff9c4
style BRINV fill:#f3e5f5
style AdditionalFlows fill:#ffe0b2
Legend:
- π΅ Inception - User journey identification
- π’ Flow Docs - Journey specifications with diagrams
- π‘ Entity Docs - Entity state machines and constraints
- π£ BR/INV - Extracted business rules and invariants
- π Additional Flows - Reference existing entities
Entity lifecycle documentation is created from multiple input sources:
| Document | What It Provides | Example |
|---|---|---|
| Flow Documentation (Primary) | Entity behaviors, state transitions, domain methods | Flow shows Conference.publishCfp() β Entity needs publishCfp() method |
| Journey Mapping (Step 6) | Entity requirements from user needs | "Create conference" β Need Conference entity |
| Features & Sequencing (Step 7) | Feature scope and entity relationships | "CfP Management" β Need Conference + CfpConfig entities |
| MVP Canvas (Step 8) | Entity constraints and priorities | MVP scope limits Conference to 5 states |
Extraction Process:
Flow: Journey 01 - Setup Conference
β
Identifies: Conference entity with states DRAFT β CFP_OPEN
β
Reveals: Methods create(), publishCfp(), closeCfp()
β
Creates: conference.md with state machine and domain methods
β
Extracts: INV-001 (state machine), BR-001 (date validation)
Why Flow First?
- Flows reveal what entities are actually needed
- Flows show how entities behave in real scenarios
- Flows identify which state transitions matter
- Flows expose edge cases that become invariants
Entity Lifecycle Template Uses:
- State Machine from flow transitions
- Domain Methods from flow steps
- Constraints from flow validations
- Business Rules from flow edge cases
Both flows and entities automatically extract Business Rules (BR) and Invariants (INV) during creation.
| Source | What It Extracts | Example |
|---|---|---|
| Flow Creation | Rules governing flow steps, validations, edge cases | BR-001: Cfp Dates Must Be Valid (from flow validation step) |
| Entity Lifecycle | Rules governing state transitions, domain methods, constraints | INV-001: Conference State Must Follow State Machine (from entity state machine) |
Process:
Flow Creation:
Journey Steps β Identify validations/edge cases β Extract BRs/INVs β Link in flow
Entity Lifecycle:
Entity Definition β Identify constraints/methods β Extract BRs/INVs β Link in entity
Output Structure:
docs/product/bounded-contexts/conference/
βββ flows/
β βββ journey-01-setup-conference.md β Links to: BR-001, INV-002
βββ entities/
β βββ conference.md β Links to: INV-001, BR-004
β βββ cfp-config.md β Links to: INV-002, BR-001
βββ business-rules/
β βββ BR-001-cfp-dates-validation.md
β βββ BR-004-free-tier-conference-limit.md
βββ invariants/
βββ INV-001-state-transition-validity.md
βββ INV-002-cfp-date-order.md
Note: You don't create BRs/INVs separately - they're automatically extracted during flow and entity creation.
Key decisions that shape the SessioFlow architecture:
| ADR | Status | Description |
|---|---|---|
| ADR-002-00 | Superseded | Use Supabase for Backend and Database |
| ADR-002-01 | β Approved | Amendment: DDD Abstraction Layer |
| ADR-002-02 | β Accepted | Vendor Lock-in Alternatives Analysis |
| ADR-002-03 | β Accepted | Authentication Strategy with DDD |
| ADR-004-00 | Superseded | Implement Magic Link Authentication |
| ADR-004-01 | β Approved | Amendment: Auth with DDD Abstraction |
| ADR-005-00 | Superseded | Use Supabase Storage for Files |
| ADR-005-01 | β Approved | Amendment: Storage with DDD Abstraction |
| ADR-009 | β Approved | Adopt Domain-Driven Design (DDD) Structure |
| ADR-011-00 | Superseded | Use Resend for Email Communications |
| ADR-011-01 | β Approved (Optional) | Amendment: Optional Email Abstraction |
Latest Decisions:
- Authentication Strategy (ADR-004-01): Implement DDD ports & adapters pattern for vendor-agnostic authentication
- Storage Strategy (ADR-005-01): Supabase Storage with DDD abstraction (swappable to Cloudflare R2)
- DDD Architecture (ADR-009): Adopt Domain-Driven Design structure for long-term maintainability
- Hybrid Approach (ADR-002-01): Consider Supabase Database + Auth0 + DDD abstraction for MVP
SessioFlow follows Domain-Driven Design (DDD) principles with a split monorepo structure that enables independent deployment and backend stack swapping:
sessioflow/
βββ apps/
β βββ backend/ # Backend service (Node/Go/Kotlin)
β β βββ src/
β β β βββ modules/
β β β β βββ conference/ # Bounded context
β β β β β βββ domain/ # Domain layer (immutable)
β β β β β βββ application/ # Application layer
β β β β β βββ infrastructure/ # Infrastructure layer (swappable)
β β β β β βββ interfaces/
β β β β β βββ api/ # API contracts (backend-specific)
β β β βββ shared/ # Shared backend utilities
β βββ frontend/ # Next.js frontend
β βββ src/
β βββ app/ # Next.js pages
β βββ components/ # UI components
β βββ modules/ # Frontend modules
β βββ conference/
β βββ interfaces/web/ # React components
β
βββ packages/ # Shared packages (utils, etc.)
β βββ utils/ # Frontend & backend utilities
βββ docs/ # Documentation
Monorepo Structure Benefits:
- β Backend stack independence - Swap Node β Go/Kotlin without touching frontend
- β Independent deployment - Backend and frontend can be deployed separately
- β DDD purity - Domain/application layers are encapsulated in backend
- β Clear ownership - Frontend and backend teams work independently
- β Reduced migration cost - 8-14 hours for backend swap (vs 52-336 hours)
Module-Based Architecture Benefits:
- β High cohesion - All code for a feature is together
- β Independent modules - Change one feature without affecting others
- β
Easier navigation - Find all conference code in
backend/modules/conference/ - β Better scaling - Add features without touching existing code
- β Clear boundaries - No accidental dependencies between features
- Frontend: Next.js 14+ (App Router)
- Language: TypeScript (strict mode)
- Database: PostgreSQL (Supabase or swappable alternative)
- Authentication: Auth0 / NextAuth / Supabase (swappable via DDD abstraction)
- Storage: Supabase Storage / Cloudflare R2 (swappable via DDD abstraction)
- Email: Resend (with optional abstraction)
- Testing: Vitest (unit), Playwright (E2E)
- Architecture: Domain-Driven Design (DDD) with Ports & Adapters
All external dependencies use DDD abstraction to enable vendor independence:
// Domain layer defines the interface
interface AuthProvider {
login(credentials): Promise<User>;
logout(token): Promise<void>;
getCurrentUser(token): Promise<User | null>;
}
interface StorageProvider {
upload(file): Promise<UploadResult>;
download(path): Promise<Buffer>;
getUrl(path): Promise<string>;
delete(path): Promise<void>;
}
// Infrastructure layer implements the interface
class Auth0Provider implements AuthProvider { ... }
class NextAuthProvider implements AuthProvider { ... }
class SupabaseStorageAdapter implements StorageProvider { ... }
class CloudflareR2Adapter implements StorageProvider { ... }
// Application layer uses only the interface
class LoginUseCase {
constructor(private provider: AuthProvider) {}
}Benefits:
- β Swap providers with 8-14 hours effort (vs 52-336 hours)
- β Vendor lock-in reduced by 85%
- β Easy testing with mock implementations
- β Can optimize costs by switching providers
SessioFlow uses the Command Query Responsibility Segregation (CQRS) pattern for the application layer:
// Command (Write Operation)
export class CreateConferenceCommand {
constructor(
public readonly name: string,
public readonly slug: string,
public readonly cfpStartDate: Date,
public readonly cfpEndDate: Date
) {}
}
export class CreateConferenceHandler {
constructor(
private conferenceRepository: ConferenceRepository,
private uuidGenerator: UuidGenerator
) {}
async handle(command: CreateConferenceCommand): Promise<Result<CreateConferenceDto>> {
// 1. Validate command
// 2. Create domain entity
// 3. Persist to repository
// 4. Return response DTO
}
}
// Query (Read Operation)
export class GetConferenceQuery {
constructor(public readonly id: string) {}
}
export class GetConferenceHandler {
constructor(private conferenceRepository: ConferenceRepository) {}
async handle(query: GetConferenceQuery): Promise<Result<GetConferenceDto>> {
// 1. Query repository
// 2. Map to response DTO
// 3. Return data (no side effects)
}
}Benefits:
- β Clear separation between read and write operations
- β Response DTOs provide stable API contracts
- β Independent optimization of reads and writes
- β Improved testability with single-responsibility handlers
- β Better alignment with DDD application layer
- Node.js 18+ or Bun
- PostgreSQL database (Supabase or self-hosted)
- Auth provider (Auth0, NextAuth, or custom)
- Storage provider (Supabase Storage, Cloudflare R2, or MinIO)
# Install dependencies
npm install
# or
bun install
# Set up environment variables
cp .env.example .env.local
# Edit .env.local with your configuration
# Run development server
npm run dev
# or
bun run dev# Database
DATABASE_URL=postgresql://user:password@host:5432/database
# Authentication (Auth0 example)
AUTH0_DOMAIN=your-domain.auth0.com
AUTH0_CLIENT_ID=your-client-id
AUTH0_CLIENT_SECRET=your-client-secret
# Alternative: NextAuth
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret
# Alternative: Supabase Auth
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_ANON_KEY=your-anon-key
# Storage (Supabase example)
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_KEY=your-service-key
# Alternative: Cloudflare R2
R2_ACCOUNT_ID=your-account-id
R2_ACCESS_KEY_ID=your-access-key
R2_SECRET_ACCESS_KEY=your-secret-key
R2_BUCKET_NAME=your-bucket
# Email (Resend example)
RESEND_API_KEY=re_your-api-keyThe project uses Drizzle Kit for database migrations. Local PostgreSQL is managed via Docker Compose.
# Start local PostgreSQL (Docker) β the compose file lives with the backend app
docker compose -f apps/backend/docker-compose.yml up -d
# Generate migration from schema (after schema changes)
npm run db:generate
# Apply migrations to database
npm run db:migrate
# Push schema directly (no migration file)
npm run db:push
# Open Drizzle Studio (database GUI)
npm run db:studioMigration files are stored in: drizzle/
Schema is defined in: src/modules/conference/infrastructure/database/drizzle-schema.ts
npm run dev# Unit tests (Vitest)
npm test
# E2E tests (Playwright)
npm run test:e2e
# Single test file
npx vitest run tests/unit/auth.test.ts
npx playwright test tests/e2e/auth.spec.tsnpm run typechecknpm run lint
npm run lint:fix
npm run formatnpm run build
npm run start- β Conference creation and management
- β Call-for-Papers (CFP) configuration
- β Proposal submission by speakers
- β Speaker profiles with profile photos
- β Admin dashboard for organizers
- β Row-Level Security (RLS) for data protection
- π Review and scoring system
- π Session scheduling and conflict detection
- π Email notifications
- π Export proposals to CSV/PDF
- π Multi-language support
SessioFlow follows DDD principles to ensure long-term maintainability:
- Domain Layer: Pure business logic, vendor-agnostic
- Application Layer: Use cases and orchestration
- Infrastructure Layer: External service implementations (swappable)
- Interface Layer: UI and API entry points
Benefits:
- β Clear separation of concerns
- β Easy to test (domain logic has no dependencies)
- β Swappable infrastructure (database, auth, storage)
- β Scales well for complex domain features
All external dependencies are accessed through repository interfaces:
// Domain defines the contract
interface AuthProvider {
login(credentials): Promise<User>;
logout(token): Promise<void>;
getCurrentUser(token): Promise<User | null>;
}
interface StorageProvider {
upload(file): Promise<UploadResult>;
download(path): Promise<Buffer>;
getUrl(path): Promise<string>;
delete(path): Promise<void>;
}
// Infrastructure implements the contract
class Auth0Provider implements AuthProvider { ... }
class NextAuthProvider implements AuthProvider { ... }
class SupabaseStorageAdapter implements StorageProvider { ... }
class CloudflareR2Adapter implements StorageProvider { ... }
// Application uses only the interface
class LoginUseCase {
constructor(private provider: AuthProvider) {}
}Benefits:
- β Swap Auth0 for NextAuth with 1-line change
- β Swap Supabase Storage for Cloudflare R2 with 1-line change
- β Swap database provider with minimal changes
- β Migration cost reduced by 85% (from 156-336 hours to 24-42 hours)
# Fast Standalone Architecture Check (< 2s) for AI Agents & Developers
npm run check:arch # Check all domain modules
npm run check:arch packages/modules/conference # Check target module/file
# Testing & Type Safety
npm run test # Run unit test suite (Vitest)
npm run test:changed # Run tests for Git modified files
npm run test:architecture # Run full Vitest architecture test suite
npm run typecheck # TypeScript type checking
npm run lint # Run ESLint checksSessioFlow enforces strict Domain-Driven Design (DDD) rules via ts-archunit automated checks:
- Domain Isolation: Domain modules (
packages/modules/*/src/domain/) cannot depend on application, infrastructure, ORMs, or external UI frameworks. - Value Objects: Must have
private constructor, static factory (create/fromString),get value(), andequals(other)method. Raw primitives (string,number,boolean) are forbidden in domain entity properties and factory parameters. - Domain Events: Must reside in
domain/events/, end withEvent, definetype+timestamp, and implementtoJSON()serialization for Outbox persistence. - Domain Exceptions: Must reside in
domain/exceptions/, end withError, and extend baseDomainError/EntityNotFoundError. - Repositories: Repository interfaces reside in
domain/, implementations reside ininfrastructure/and reconstitute entities via static.fromData(...)factory methods.
- Read the ADR documentation to understand architectural decisions
- Follow DDD patterns when adding new features
- Write tests for new functionality
- Submit a pull request with a clear description
MIT License - see LICENSE file for details
- Architecture Rules & Invariants Guide
- ADR Documentation
- DDD Implementation Guide
- Authentication Strategy (ADR-004-01)
- Storage Strategy (ADR-005-01)
- Supabase Integration (ADR-002-00)
- Pretalx (Reference CfP Platform)
- Auth0 Documentation
- NextAuth.js Documentation
- Supabase Documentation
- Cloudflare R2 Documentation
For questions or issues:
- Open an issue on GitHub
- Review existing ADRs for architectural context
- Check the docs for detailed information
- Read ADR-009: Understand the DDD architecture
- Read ADR-002b: Understand authentication strategy
- Set up environment: Follow installation instructions above
- Run tests:
npm testto verify setup - Start coding: Follow DDD patterns in existing code
- Review ADR-002 Amendment: Understand vendor abstraction benefits
- Review ADR-004 Amendment: Auth implementation details
- Review ADR-005 Amendment: Storage implementation details
- Consider trade-offs: Speed vs. flexibility, vendor lock-in vs. development time
Last Updated: 2026-06-11 Maintained By: Technical Team