Add Rails backend: accounts via magic link, server documents, sharing

The app becomes a Rails 8 application; the Vue frontend moves to
app/frontend and is served through vite_rails.

- Without an account documents stay in the browser (IndexedDB). Sign-in
  is by magic link or the 6-digit code from the same mail; afterwards
  local documents can be uploaded into the account.
- Server documents (/d/<id>) with versioned saves and a single-editor
  lock per browser tab; others see them read-only and follow by polling.
- Sharing via link (works without an account) and via e-mail invitation,
  roles viewer/editor; the owner manages links and people.
- Store gains a read-only mode that blocks all content changes.
- Solid Queue, Cache and Cable share the one PostgreSQL database.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
wkh
2026-09-28 20:09:06 +02:00
co-authored by Claude Opus 5.5
parent 5a0f1fcd78
commit e14bada114
190 changed files with 6077 additions and 722 deletions
+81
View File
@@ -0,0 +1,81 @@
/**
* Public surface of the formula engine.
*
* Nothing in `./` imports Vue, the DOM or any spreadsheet library. See
* ./README.md for the grammar (EBNF), the evaluation model and the error model.
*/
export { tokenize, LexError, type Token, type TokenType } from './lexer';
export {
parseFormula,
parseFunctionBlock,
parseMacroBlock,
collectRefs,
collectRefsInBlock,
ParseError,
type Node,
type CellNode,
type RangeNode,
type NamedRefNode,
type BlockNode,
type ActionNode,
} from './parser';
export { evaluate, runMacroActions } from './evaluator';
export { DependencyGraph } from './graph';
export { FUNCTIONS, getFunction, hasFunction, BUILTIN_SIGNATURES } from './functions';
export {
colToNumber,
numberToCol,
parseA1,
toA1,
looksLikeCell,
expandRange,
rangeCells,
wholeLineAt,
parseLinePart,
formatLinePart,
WHOLE_LINE_END,
cycleReferenceLocks,
currentIdentifierAtCaret,
} from './refs';
export {
Workbook,
literalValue,
type TableModel,
} from './workbook';
export {
dateToSerial,
timeSerial,
serialToUtcDate,
todaySerial,
nowSerial,
parseDateTimeLiteral,
type DateLiteralKind,
} from './dates';
export {
buildFunctionIndex,
expandUserFunctions,
expandMacroBlock,
collectCalledFunctionNames,
collectCalledFunctionNamesInBlock,
declaredBlockNames,
findInvalidForSource,
findInvalidActionTarget,
blockAlwaysReturns,
type FunctionDef,
} from './userFunctions';
export {
FormulaError,
isError,
keyOf,
parseKey,
ERROR_CODES,
type ErrorCode,
type CellValue,
type CellRef,
type Scalar,
type EngineHost,
type MacroWriteHost,
type MacroNetworkHost,
type NamedRangeDef,
} from './types';